Bug 127152

Summary: CodeBlockSet should be generational
Product: WebKit Reporter: Mark Hahnenberg <mhahnenberg>
Component: JavaScriptCoreAssignee: Mark Hahnenberg <mhahnenberg>
Status: RESOLVED FIXED    
Severity: Normal CC: commit-queue, fpizlo
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on: 131356    
Bug Blocks:    
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Final patch none

Description Mark Hahnenberg 2014-01-16 17:05:21 PST
This is a big overhead during EdenCollections. We should think about how we can generationalize our CodeBlock lifetimes.
Comment 1 Mark Hahnenberg 2014-01-30 12:14:13 PST
Created attachment 222707 [details]
Patch
Comment 2 Geoffrey Garen 2014-01-30 12:33:55 PST
Comment on attachment 222707 [details]
Patch

r=me
Comment 3 Mark Hahnenberg 2014-01-30 16:09:14 PST
(In reply to comment #1)
> Created an attachment (id=222707) [details]
> Patch

Hmm, I think this patch has issues. The correctness of the weakReferenceHarvester stuff in which CodeBlocks participate is dependent on visiting all marked CodeBlocks during a collection. Otherwise we won't propagate liveness for all the things that hang off of CodeBlock that need it.

Another alternative is to just ignore all new CodeBlocks (i.e. auto-promote, pretenure, etc.). We'd still have to visit them to LUB value profiles.
Comment 4 Mark Hahnenberg 2014-03-31 16:16:19 PDT
Created attachment 228214 [details]
Patch
Comment 5 Mark Hahnenberg 2014-03-31 16:23:06 PDT
Created attachment 228216 [details]
Patch
Comment 6 Geoffrey Garen 2014-03-31 16:49:30 PDT
Comment on attachment 228216 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=228216&action=review

r=me

> Source/JavaScriptCore/bytecode/CodeBlock.h:1004
> +        // During EdenCollections all CodeBlocks that are visited are assumed to be live.

Would be nice to explain our reasoning here: It's probably cheaper to assume liveness, and we don't want to worry about write barrier subtleties required by the mutually weak liveness methodology.

> Source/JavaScriptCore/heap/CodeBlockSet.cpp:71
> +void CodeBlockSet::clearAllMarks()
>  {
> -    for (CodeBlock* codeBlock : m_set) {
> +    promoteYoungCodeBlocks();
> +    for (CodeBlock* codeBlock : m_oldCodeBlocks) {
>          codeBlock->m_mayBeExecuting = false;
>          codeBlock->m_visitAggregateHasBeenCalled = false;
>      }
>  }

It feels strange for "clearAllMarks" to promote. And might this get us into a bad state if deleteAllCompiledCode is called at the start of an eden collection? Similarly strange, though less so, for deleteUnmarkedAndUnreferenced to promote.

Can we make the caller promote instead? For example, Heap::deleteAllCompiledCode could run only during full collections, and Heap::markRoots could eagerly promote code blocks before full collections and lazily promote code blocks after eden collections. Or, Heap::resetAllocators() could promote code blocks unconditionally, and Heap::deleteAllCompiledCode could run after Heap::resetAllocators().
Comment 7 Geoffrey Garen 2014-04-02 12:19:03 PDT
Comment on attachment 228216 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=228216&action=review

> Source/JavaScriptCore/heap/CodeBlockSet.cpp:135
> +        m_oldCodeBlocks.remove(codeBlock);

Needs early return.
Comment 8 Mark Hahnenberg 2014-04-02 14:08:44 PDT
Created attachment 228428 [details]
Final patch
Comment 9 Mark Hahnenberg 2014-04-02 14:10:31 PDT
Comment on attachment 228428 [details]
Final patch

View in context: https://bugs.webkit.org/attachment.cgi?id=228428&action=review

> Source/JavaScriptCore/bytecode/CodeBlock.h:151
> +    template <typename Functor> void forEachRelatedCodeBlock(Functor&& functor)
> +    {
> +        Functor f(std::forward<Functor>(functor));
> +        Vector<CodeBlock*, 4> codeBlocks;
> +        codeBlocks.append(this);
> +
> +        while (!codeBlocks.isEmpty()) {
> +            CodeBlock* currentCodeBlock = codeBlocks.takeLast();
> +            f(currentCodeBlock);
> +
> +            if (CodeBlock* alternative = currentCodeBlock->alternative())
> +                codeBlocks.append(alternative);
> +            if (CodeBlock* osrEntryBlock = currentCodeBlock->specialOSREntryBlockOrNull())
> +                codeBlocks.append(osrEntryBlock);
> +        }
> +    }

I had to add handling of the OSR entry block along with the alternative blocks. To make it more general, I turned it into a DFS of a DAG. There's no defense against cycles.
Comment 10 Geoffrey Garen 2014-04-02 16:17:46 PDT
Comment on attachment 228428 [details]
Final patch

r=me
Comment 11 WebKit Commit Bot 2014-04-02 16:50:52 PDT
Comment on attachment 228428 [details]
Final patch

Clearing flags on attachment: 228428

Committed r166678: <http://trac.webkit.org/changeset/166678>
Comment 12 WebKit Commit Bot 2014-04-02 16:50:56 PDT
All reviewed patches have been landed.  Closing bug.