Title: [188792] trunk/Source/_javascript_Core
Revision
188792
Author
[email protected]
Date
2015-08-21 15:48:49 -0700 (Fri, 21 Aug 2015)

Log Message

Unify code paths for manually deleting all code
https://bugs.webkit.org/show_bug.cgi?id=148280

Reviewed by Saam Barati.

We used to have three paths for manually deleting all code. Now we have
one shared path.

* debugger/Debugger.cpp:
(JSC::Debugger::attach): Notify the debugger of all previous code when
it attaches. We used to do this when recompiling, which was only correct
by accident.

(JSC::Debugger::recompileAllJSFunctions): Switch to the shared path.

* heap/Heap.h:
(JSC::Heap::compiledCode):

* inspector/agents/InspectorRuntimeAgent.cpp:
(Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets):
(Inspector::InspectorRuntimeAgent::willDestroyFrontendAndBackend):
(Inspector::InspectorRuntimeAgent::setTypeProfilerEnabledState):
(Inspector::InspectorRuntimeAgent::getBasicBlocks):
(Inspector::TypeRecompiler::visit): Deleted.
(Inspector::TypeRecompiler::operator()): Deleted.
(Inspector::recompileAllJSFunctionsForTypeProfiling): Deleted. Switch
to the shared path.

* runtime/VM.cpp:
(JSC::VM::afterVMExit): Added a helper for scheduling an activity after
VM exit. We can't delete code while it's on the stack, and we can't
delete auxiliary profiling data while profiling code is on the stack,
so in those cases, we schedule the deletion for the next time we exit.

(JSC::VM::deleteAllCode): Use afterVMExit because we might have code
on the stack when debugger, profiler, or watchdog state changes.

* runtime/VM.h:

* runtime/VMEntryScope.cpp:
(JSC::VMEntryScope::VMEntryScope):
(JSC::VMEntryScope::addDidPopListener):
(JSC::VMEntryScope::~VMEntryScope):
(JSC::VMEntryScope::setEntryScopeDidPopListener): Deleted.
* runtime/VMEntryScope.h:
(JSC::VMEntryScope::globalObject): Removed the uniquing feature from
the scope pop listener list because we don't have a client that wants
it, and it's not convenient to use correctly since you can't take
the address of a member function, a lambda, or an std::function. We can
add this feature back if we discover that we want it.

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (188791 => 188792)


--- trunk/Source/_javascript_Core/ChangeLog	2015-08-21 22:42:35 UTC (rev 188791)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-08-21 22:48:49 UTC (rev 188792)
@@ -1,3 +1,56 @@
+2015-08-21  Geoffrey Garen  <[email protected]>
+
+        Unify code paths for manually deleting all code
+        https://bugs.webkit.org/show_bug.cgi?id=148280
+
+        Reviewed by Saam Barati.
+
+        We used to have three paths for manually deleting all code. Now we have
+        one shared path.
+
+        * debugger/Debugger.cpp:
+        (JSC::Debugger::attach): Notify the debugger of all previous code when
+        it attaches. We used to do this when recompiling, which was only correct
+        by accident.
+
+        (JSC::Debugger::recompileAllJSFunctions): Switch to the shared path.
+
+        * heap/Heap.h:
+        (JSC::Heap::compiledCode):
+
+        * inspector/agents/InspectorRuntimeAgent.cpp:
+        (Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets):
+        (Inspector::InspectorRuntimeAgent::willDestroyFrontendAndBackend):
+        (Inspector::InspectorRuntimeAgent::setTypeProfilerEnabledState):
+        (Inspector::InspectorRuntimeAgent::getBasicBlocks):
+        (Inspector::TypeRecompiler::visit): Deleted.
+        (Inspector::TypeRecompiler::operator()): Deleted.
+        (Inspector::recompileAllJSFunctionsForTypeProfiling): Deleted. Switch
+        to the shared path.
+
+        * runtime/VM.cpp:
+        (JSC::VM::afterVMExit): Added a helper for scheduling an activity after
+        VM exit. We can't delete code while it's on the stack, and we can't
+        delete auxiliary profiling data while profiling code is on the stack,
+        so in those cases, we schedule the deletion for the next time we exit.
+
+        (JSC::VM::deleteAllCode): Use afterVMExit because we might have code
+        on the stack when debugger, profiler, or watchdog state changes.
+
+        * runtime/VM.h:
+
+        * runtime/VMEntryScope.cpp:
+        (JSC::VMEntryScope::VMEntryScope):
+        (JSC::VMEntryScope::addDidPopListener):
+        (JSC::VMEntryScope::~VMEntryScope):
+        (JSC::VMEntryScope::setEntryScopeDidPopListener): Deleted.
+        * runtime/VMEntryScope.h:
+        (JSC::VMEntryScope::globalObject): Removed the uniquing feature from
+        the scope pop listener list because we don't have a client that wants
+        it, and it's not convenient to use correctly since you can't take
+        the address of a member function, a lambda, or an std::function. We can
+        add this feature back if we discover that we want it.
+
 2015-08-21  Sukolsak Sakshuwong  <[email protected]>
 
         Implement WebAssembly function parser

Modified: trunk/Source/_javascript_Core/debugger/Debugger.cpp (188791 => 188792)


--- trunk/Source/_javascript_Core/debugger/Debugger.cpp	2015-08-21 22:42:35 UTC (rev 188791)
+++ trunk/Source/_javascript_Core/debugger/Debugger.cpp	2015-08-21 22:48:49 UTC (rev 188792)
@@ -35,72 +35,6 @@
 #include "Protect.h"
 #include "VMEntryScope.h"
 
-namespace {
-
-using namespace JSC;
-
-class Recompiler : public MarkedBlock::VoidFunctor {
-public:
-    Recompiler(JSC::Debugger*);
-    ~Recompiler();
-    IterationStatus operator()(JSCell*);
-
-private:
-    typedef HashSet<FunctionExecutable*> FunctionExecutableSet;
-    typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap;
-    
-    void visit(JSCell*);
-    
-    JSC::Debugger* m_debugger;
-    FunctionExecutableSet m_functionExecutables;
-    SourceProviderMap m_sourceProviders;
-};
-
-inline Recompiler::Recompiler(JSC::Debugger* debugger)
-    : m_debugger(debugger)
-{
-}
-
-inline Recompiler::~Recompiler()
-{
-    // Call sourceParsed() after reparsing all functions because it will execute
-    // _javascript_ in the inspector.
-    SourceProviderMap::const_iterator end = m_sourceProviders.end();
-    for (SourceProviderMap::const_iterator iter = m_sourceProviders.begin(); iter != end; ++iter)
-        m_debugger->sourceParsed(iter->value, iter->key, -1, String());
-}
-
-inline void Recompiler::visit(JSCell* cell)
-{
-    if (!cell->inherits(JSFunction::info()))
-        return;
-
-    JSFunction* function = jsCast<JSFunction*>(cell);
-    if (function->executable()->isHostFunction())
-        return;
-
-    FunctionExecutable* executable = function->jsExecutable();
-
-    // Check if the function is already in the set - if so,
-    // we've already retranslated it, nothing to do here.
-    if (!m_functionExecutables.add(executable).isNewEntry)
-        return;
-
-    ExecState* exec = function->scope()->globalObject()->JSGlobalObject::globalExec();
-    executable->clearCode();
-    executable->clearUnlinkedCodeForRecompilation();
-    if (m_debugger == function->scope()->globalObject()->debugger())
-        m_sourceProviders.add(executable->source().provider(), exec);
-}
-
-inline IterationStatus Recompiler::operator()(JSCell* cell)
-{
-    visit(cell);
-    return IterationStatus::Continue;
-}
-
-} // namespace
-
 namespace JSC {
 
 class DebuggerPausedScope {
@@ -180,6 +114,15 @@
         ASSERT(m_vm == &globalObject->vm());
     globalObject->setDebugger(this);
     m_globalObjects.add(globalObject);
+
+    // Call sourceParsed() because it will execute _javascript_ in the inspector.
+    for (size_t i = 0; i < m_vm->heap.compiledCode().size(); ++i) {
+        ExecutableBase* base = m_vm->heap.compiledCode()[i];
+        if (!base->isFunctionExecutable())
+            continue;
+        FunctionExecutable* executable = static_cast<FunctionExecutable*>(base);
+        sourceParsed(globalObject->globalExec(), executable->source().provider(), -1, String());
+    }
 }
 
 void Debugger::detach(JSGlobalObject* globalObject, ReasonForDetach reason)
@@ -336,26 +279,7 @@
 
 void Debugger::recompileAllJSFunctions(VM* vm)
 {
-    // If _javascript_ is running, it's not safe to recompile, since we'll end
-    // up throwing away code that is live on the stack.
-    if (vm->entryScope) {
-        auto listener = [] (VM& vm, JSGlobalObject* globalObject) 
-        {
-            if (Debugger* debugger = globalObject->debugger())
-                debugger->recompileAllJSFunctions(&vm);
-        };
-
-        vm->entryScope->setEntryScopeDidPopListener(this, listener);
-        return;
-    }
-
-#if ENABLE(DFG_JIT)
-    DFG::completeAllPlansForVM(*vm);
-#endif
-
-    Recompiler recompiler(this);
-    HeapIterationScope iterationScope(vm->heap);
-    vm->heap.objectSpace().forEachLiveCell(iterationScope, recompiler);
+    vm->deleteAllCode();
 }
 
 BreakpointID Debugger::setBreakpoint(Breakpoint breakpoint, unsigned& actualLine, unsigned& actualColumn)

Modified: trunk/Source/_javascript_Core/heap/Heap.h (188791 => 188792)


--- trunk/Source/_javascript_Core/heap/Heap.h	2015-08-21 22:42:35 UTC (rev 188791)
+++ trunk/Source/_javascript_Core/heap/Heap.h	2015-08-21 22:48:49 UTC (rev 188792)
@@ -237,6 +237,8 @@
 
     void addLogicallyEmptyWeakBlock(WeakBlock*);
 
+    Vector<ExecutableBase*>& compiledCode() { return m_compiledCode; }
+
 private:
     friend class CodeBlock;
     friend class CopiedBlock;

Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp (188791 => 188792)


--- trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp	2015-08-21 22:42:35 UTC (rev 188791)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorRuntimeAgent.cpp	2015-08-21 22:48:49 UTC (rev 188792)
@@ -308,40 +308,6 @@
         dataLogF("Inspector::getRuntimeTypesForVariablesAtOffsets took %lfms\n", end - start);
 }
 
-class TypeRecompiler : public MarkedBlock::VoidFunctor {
-public:
-    inline void visit(JSCell* cell)
-    {
-        if (!cell->inherits(FunctionExecutable::info()))
-            return;
-
-        FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
-        executable->clearCode();
-        executable->clearUnlinkedCodeForRecompilation();
-    }
-    inline IterationStatus operator()(JSCell* cell)
-    {
-        visit(cell);
-        return IterationStatus::Continue;
-    }
-};
-
-static void recompileAllJSFunctionsForTypeProfiling(VM& vm, bool shouldEnableTypeProfiling)
-{
-    bool shouldRecompileFromTypeProfiler = (shouldEnableTypeProfiling ? vm.enableTypeProfiler() : vm.disableTypeProfiler());
-    bool shouldRecompileFromControlFlowProfiler = (shouldEnableTypeProfiling ? vm.enableControlFlowProfiler() : vm.disableControlFlowProfiler());
-    bool needsToRecompile = shouldRecompileFromTypeProfiler || shouldRecompileFromControlFlowProfiler;
-
-    if (needsToRecompile) {
-#if ENABLE(DFG_JIT)
-        DFG::completeAllPlansForVM(vm);
-#endif
-        TypeRecompiler recompiler;
-        HeapIterationScope iterationScope(vm.heap);
-        vm.heap.objectSpace().forEachLiveCell(iterationScope, recompiler);
-    }
-}
-
 void InspectorRuntimeAgent::willDestroyFrontendAndBackend(DisconnectReason reason)
 {
     if (reason != DisconnectReason::InspectedTargetDestroyed && m_isTypeProfilingEnabled)
@@ -358,25 +324,21 @@
     setTypeProfilerEnabledState(false);
 }
 
-void InspectorRuntimeAgent::setTypeProfilerEnabledState(bool shouldEnableTypeProfiling)
+void InspectorRuntimeAgent::setTypeProfilerEnabledState(bool isTypeProfilingEnabled)
 {
-    if (m_isTypeProfilingEnabled == shouldEnableTypeProfiling)
+    if (m_isTypeProfilingEnabled == isTypeProfilingEnabled)
         return;
+    m_isTypeProfilingEnabled = isTypeProfilingEnabled;
 
-    m_isTypeProfilingEnabled = shouldEnableTypeProfiling;
-
     VM& vm = globalVM();
+    vm.whenIdle([&vm, isTypeProfilingEnabled] () {
+        bool shouldRecompileFromTypeProfiler = (isTypeProfilingEnabled ? vm.enableTypeProfiler() : vm.disableTypeProfiler());
+        bool shouldRecompileFromControlFlowProfiler = (isTypeProfilingEnabled ? vm.enableControlFlowProfiler() : vm.disableControlFlowProfiler());
+        bool needsToRecompile = shouldRecompileFromTypeProfiler || shouldRecompileFromControlFlowProfiler;
 
-    // If _javascript_ is running, it's not safe to recompile, since we'll end
-    // up throwing away code that is live on the stack.
-    if (vm.entryScope) {
-        vm.entryScope->setEntryScopeDidPopListener(this,
-            [=] (VM& vm, JSGlobalObject*) {
-                recompileAllJSFunctionsForTypeProfiling(vm, shouldEnableTypeProfiling);
-            }
-        );
-    } else
-        recompileAllJSFunctionsForTypeProfiling(vm, shouldEnableTypeProfiling);
+        if (needsToRecompile)
+            vm.deleteAllCode();
+    });
 }
 
 void InspectorRuntimeAgent::getBasicBlocks(ErrorString& errorString, const String& sourceIDAsString, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Runtime::BasicBlock>>& basicBlocks)

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (188791 => 188792)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2015-08-21 22:42:35 UTC (rev 188791)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2015-08-21 22:48:49 UTC (rev 188792)
@@ -86,6 +86,7 @@
 #include "TypeProfiler.h"
 #include "TypeProfilerLog.h"
 #include "UnlinkedCodeBlock.h"
+#include "VMEntryScope.h"
 #include "Watchdog.h"
 #include "WeakGCMapInlines.h"
 #include "WeakMapData.h"
@@ -471,16 +472,28 @@
     interpreter->stopSampling();
 }
 
+void VM::whenIdle(std::function<void()> callback)
+{
+    if (!entryScope) {
+        callback();
+        return;
+    }
+
+    entryScope->addDidPopListener(callback);
+}
+
 void VM::deleteAllCode()
 {
-    m_codeCache->clear();
-    m_regExpCache->deleteAllCode();
+    whenIdle([this]() {
+        m_codeCache->clear();
+        m_regExpCache->deleteAllCode();
 #if ENABLE(DFG_JIT)
-    DFG::completeAllPlansForVM(*this);
+        DFG::completeAllPlansForVM(*this);
 #endif
-    heap.deleteAllCompiledCode();
-    heap.deleteAllUnlinkedFunctionCode();
-    heap.reportAbandonedObjectGraph();
+        heap.deleteAllCompiledCode();
+        heap.deleteAllUnlinkedFunctionCode();
+        heap.reportAbandonedObjectGraph();
+    });
 }
 
 void VM::dumpSampleData(ExecState* exec)

Modified: trunk/Source/_javascript_Core/runtime/VM.h (188791 => 188792)


--- trunk/Source/_javascript_Core/runtime/VM.h	2015-08-21 22:42:35 UTC (rev 188791)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2015-08-21 22:48:49 UTC (rev 188792)
@@ -541,6 +541,8 @@
     JSLock& apiLock() { return *m_apiLock; }
     CodeCache* codeCache() { return m_codeCache.get(); }
 
+    void whenIdle(std::function<void()>);
+
     JS_EXPORT_PRIVATE void deleteAllCode();
 
     void registerWatchpointForImpureProperty(const Identifier&, Watchpoint*);

Modified: trunk/Source/_javascript_Core/runtime/VMEntryScope.cpp (188791 => 188792)


--- trunk/Source/_javascript_Core/runtime/VMEntryScope.cpp	2015-08-21 22:42:35 UTC (rev 188791)
+++ trunk/Source/_javascript_Core/runtime/VMEntryScope.cpp	2015-08-21 22:48:49 UTC (rev 188792)
@@ -57,9 +57,9 @@
     vm.clearLastException();
 }
 
-void VMEntryScope::setEntryScopeDidPopListener(void* key, EntryScopeDidPopListener listener)
+void VMEntryScope::addDidPopListener(std::function<void ()> listener)
 {
-    m_allEntryScopeDidPopListeners.set(key, listener);
+    m_didPopListeners.append(listener);
 }
 
 VMEntryScope::~VMEntryScope()
@@ -72,8 +72,8 @@
 
     m_vm.entryScope = nullptr;
 
-    for (auto& listener : m_allEntryScopeDidPopListeners.values())
-        listener(m_vm, m_globalObject);
+    for (auto& listener : m_didPopListeners)
+        listener();
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/VMEntryScope.h (188791 => 188792)


--- trunk/Source/_javascript_Core/runtime/VMEntryScope.h	2015-08-21 22:42:35 UTC (rev 188791)
+++ trunk/Source/_javascript_Core/runtime/VMEntryScope.h	2015-08-21 22:48:49 UTC (rev 188792)
@@ -27,9 +27,9 @@
 #define VMEntryScope_h
 
 #include "Interpreter.h"
-#include <wtf/HashMap.h>
 #include <wtf/StackBounds.h>
 #include <wtf/StackStats.h>
+#include <wtf/Vector.h>
 
 namespace JSC {
 
@@ -43,13 +43,12 @@
 
     JSGlobalObject* globalObject() const { return m_globalObject; }
 
-    typedef std::function<void (VM&, JSGlobalObject*)> EntryScopeDidPopListener;
-    void setEntryScopeDidPopListener(void*, EntryScopeDidPopListener);
+    void addDidPopListener(std::function<void ()>);
 
 private:
     VM& m_vm;
     JSGlobalObject* m_globalObject;
-    HashMap<void*, EntryScopeDidPopListener> m_allEntryScopeDidPopListeners;
+    Vector<std::function<void ()>> m_didPopListeners;
 };
 
 } // namespace JSC
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to