Bug 195638 - [JSC] CodeBlock::visitChildren is reporting extra memory even when its JITCode is singleton
Summary: [JSC] CodeBlock::visitChildren is reporting extra memory even when its JITCod...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Caio Lima
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2019-03-12 13:08 PDT by Caio Lima
Modified: 2019-03-13 18:10 PDT (History)
9 users (show)

See Also:


Attachments
RFC Patch (4.73 KB, patch)
2019-03-12 13:21 PDT, Caio Lima
no flags Details | Formatted Diff | Diff
WIP - Patch (11.08 KB, patch)
2019-03-13 07:55 PDT, Caio Lima
no flags Details | Formatted Diff | Diff
Patch (13.55 KB, patch)
2019-03-13 14:37 PDT, Caio Lima
no flags Details | Formatted Diff | Diff
Patch (12.92 KB, patch)
2019-03-13 14:43 PDT, Caio Lima
no flags Details | Formatted Diff | Diff
Patch (12.79 KB, patch)
2019-03-13 17:28 PDT, Caio Lima
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Caio Lima 2019-03-12 13:08:50 PDT
After https://bugs.webkit.org/show_bug.cgi?id=194659, we have singleton DirectJITCode per entrypoint type on no JIT configuration. However, we still use setJITCode and keep reporting extra memory for those JITCodes, even if they being shared.
Extra memory is used by `Heap::updateAllocationLimits` and having higher value can potentially put more pressure on GC.
Comment 1 Caio Lima 2019-03-12 13:21:16 PDT
Created attachment 364435 [details]
RFC Patch

This change was used to create an alternative method to notify CodeBlock that it is referring to a shared m_jitCode. The flag `m_isSharedJITCode` is used to store such modification.

We ran Speedometer on minibrowser with JIT disabled to compare this approach. The results there are neutral.

Run 1:
ToT: 55.8 +- 1.0
Changes: 55.7 +- 1.0

Run 2:
ToT: 53.1 +- 0.69
Changes: 53.6 +- 0.49

Run 3:
ToT: 50.04 +- 0.65
Changes: 49.8 +- 0.58

I tried run some numbers on JetStream2, but with no JIT config, takes very long to run tests. It is probably very hard to see performance difference there, but I'll run other JS benchmarks to see difference on numbers.
Comment 2 Caio Lima 2019-03-13 07:55:19 PDT
Created attachment 364534 [details]
WIP - Patch
Comment 3 Dominik Inführ 2019-03-13 08:33:39 PDT
Looks good to me.
Comment 4 Mark Lam 2019-03-13 12:07:40 PDT
Comment on attachment 364534 [details]
WIP - Patch

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

> Source/JavaScriptCore/bytecode/CodeBlock.cpp:951
> +    if (thisObject->m_jitCode && !thisObject->m_jitCode->isShared())
>          extraMemoryAllocated += thisObject->m_jitCode->size();

nit: we're computing thisObject->m_jitCode 3 times here.  I suggest prefetching it once.

> Source/JavaScriptCore/bytecode/CodeBlock.h:395
> +            ASSERT(heap()->isDeferred());

Do we really want to make this assert conditional?  Even though we only reportExtraMemoryAllocated() when !isShared, do we ever want to allow the caller to call setJITCode() without deferring GCs?  Unless there's a strong reason why we need this,I think it's better to have that assertion unconditionally so that the contract for calling setJITCode() is unconditional.

> Source/JavaScriptCore/jit/JITCode.h:208
> +    virtual bool isShared() const { return false; }

I'm tend to be wary of adding virtual functions unless there's a good reason for it.  In this case, it probably doesn't matter much either way.  However, I think we can solve this a different way by adding a m_isShared bool to class JITCode itself.  There's definitely space for it in the object already.  That way, we can avoid creating 2 new classes, and some virtual function calls.  Actually, instead of a bool, the preferred idiom would be to use a:

    class JITCode {
        ....
        enum class ShareAttribute : uint8_t {
            NotShared,
            Shared
        };

... and have the JITCode constructor take a default arg of ShareAttribute::NotShared.  The shared cases can pass ShareAttribute:Shared explicitly.

> Source/JavaScriptCore/jit/JITCode.h:252
> +    SharedDirectJITCode(CodeRef<JSEntryPtrTag>, CodePtr<JSEntryPtrTag> withArityCheck, JITType);

I recommend just implementing the constructor as an inline function here instead of in the .cpp.  All it does is forward construction to the base class.  Hence, there's no value in not inlining it.

> Source/JavaScriptCore/jit/JITCode.h:253
> +    virtual ~SharedDirectJITCode();

This is not needed since it adds no behavior change.

> Source/JavaScriptCore/jit/JITCode.h:269
> +    SharedNativeJITCode(CodeRef<JSEntryPtrTag>, JITType);

Ditto: inline the constructor.

> Source/JavaScriptCore/jit/JITCode.h:270
> +    virtual ~SharedNativeJITCode();

Ditto: not needed.
Comment 5 Caio Lima 2019-03-13 14:37:35 PDT
Created attachment 364574 [details]
Patch
Comment 6 Caio Lima 2019-03-13 14:41:58 PDT
Comment on attachment 364534 [details]
WIP - Patch

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

Thx a lot for the review. I uploaded new Patch with your comments.

>> Source/JavaScriptCore/bytecode/CodeBlock.cpp:951
>>          extraMemoryAllocated += thisObject->m_jitCode->size();
> 
> nit: we're computing thisObject->m_jitCode 3 times here.  I suggest prefetching it once.

Done

>> Source/JavaScriptCore/bytecode/CodeBlock.h:395
>> +            ASSERT(heap()->isDeferred());
> 
> Do we really want to make this assert conditional?  Even though we only reportExtraMemoryAllocated() when !isShared, do we ever want to allow the caller to call setJITCode() without deferring GCs?  Unless there's a strong reason why we need this,I think it's better to have that assertion unconditionally so that the contract for calling setJITCode() is unconditional.

No reason. I moved ASSERT outside the loop then.

>> Source/JavaScriptCore/jit/JITCode.h:208
>> +    virtual bool isShared() const { return false; }
> 
> I'm tend to be wary of adding virtual functions unless there's a good reason for it.  In this case, it probably doesn't matter much either way.  However, I think we can solve this a different way by adding a m_isShared bool to class JITCode itself.  There's definitely space for it in the object already.  That way, we can avoid creating 2 new classes, and some virtual function calls.  Actually, instead of a bool, the preferred idiom would be to use a:
> 
>     class JITCode {
>         ....
>         enum class ShareAttribute : uint8_t {
>             NotShared,
>             Shared
>         };
> 
> ... and have the JITCode constructor take a default arg of ShareAttribute::NotShared.  The shared cases can pass ShareAttribute:Shared explicitly.

Ok. The reason to use virtual methods was to avoid adding a new field to JITCode, but since it is not a problem here, I moved to the approach you suggested.

>> Source/JavaScriptCore/jit/JITCode.h:252
>> +    SharedDirectJITCode(CodeRef<JSEntryPtrTag>, CodePtr<JSEntryPtrTag> withArityCheck, JITType);
> 
> I recommend just implementing the constructor as an inline function here instead of in the .cpp.  All it does is forward construction to the base class.  Hence, there's no value in not inlining it.

Not necessary, since I removed this class.

>> Source/JavaScriptCore/jit/JITCode.h:253
>> +    virtual ~SharedDirectJITCode();
> 
> This is not needed since it adds no behavior change.

Ditto.

>> Source/JavaScriptCore/jit/JITCode.h:269
>> +    SharedNativeJITCode(CodeRef<JSEntryPtrTag>, JITType);
> 
> Ditto: inline the constructor.

Ditto.

>> Source/JavaScriptCore/jit/JITCode.h:270
>> +    virtual ~SharedNativeJITCode();
> 
> Ditto: not needed.

Ditto.
Comment 7 Caio Lima 2019-03-13 14:43:56 PDT
Created attachment 364576 [details]
Patch
Comment 8 Mark Lam 2019-03-13 15:00:08 PDT
Comment on attachment 364574 [details]
Patch

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

LGTM.  Please remove the test code before landing.

> Source/JavaScriptCore/ChangeLog:11
> +        This patch is introducing new field on JITCode to represent
> +        its shared versions. With this new field, we introduced a new
> +        method `isShared()` to indicate that a JITCode is shared among
> +        CodeBlocks. This is being used by `CodeBlock::setJITCode` and

I suggest rephrasing the above as:
This patch introduces a m_isShared flag to track whether the JITCode is shared between  many CodeBlocks.  This flag is used in `CodeBlock::setJITCode ...

> Source/JavaScriptCore/ChangeLog:12
> +        `CodeBlock::visitChildren` to avoid report duplicated extra memory for

/report duplicated/reporting duplicate/

> Source/JavaScriptCore/ChangeLog:14
> +        With those changes, we now stop accounting singleton LLIntEntrypoints

... we now stop counting singleton ...

> Source/JavaScriptCore/ChangeLog:16
> +        change can pottentially avoid unecessary GC pressure, because

/pottentially/potentially/

> Source/JavaScriptCore/ChangeLog:20
> +        (see results below), it is important keep extra memory usage consistent,

important to ...

I would also say "correct" instead of "consistent".  I also suggest putting a period after consistent/correct, and starting "Otherwise ..." as a new sentence.

> Source/JavaScriptCore/jit/JITCode.h:216
> +    bool isShared() const
> +    { 
> +        return m_shareAttribute == ShareAttribute::Shared;
> +    }

nit: I prefer to put this all on a single line since there's only one statement in it.  For example, see intrinsic() above.

> Source/JavaScriptCore/runtime/Options.cpp:226
>  static bool jitEnabledByDefault()
>  {
> -    return is32Bit() || isAddress64Bit();
> +    return false;
>  }

I think this is test code you forgot to remove.
Comment 9 Mark Lam 2019-03-13 15:01:11 PDT
Comment on attachment 364576 [details]
Patch

LGTM but please see my suggestions from https://bugs.webkit.org/show_bug.cgi?id=195638#c8.
Comment 10 Caio Lima 2019-03-13 17:17:58 PDT
Comment on attachment 364574 [details]
Patch

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

Thx a lot for the review and suggestions.

>> Source/JavaScriptCore/ChangeLog:11
>> +        CodeBlocks. This is being used by `CodeBlock::setJITCode` and
> 
> I suggest rephrasing the above as:
> This patch introduces a m_isShared flag to track whether the JITCode is shared between  many CodeBlocks.  This flag is used in `CodeBlock::setJITCode ...

Done.

>> Source/JavaScriptCore/ChangeLog:16
>> +        change can pottentially avoid unecessary GC pressure, because
> 
> /pottentially/potentially/

Oops.

>> Source/JavaScriptCore/ChangeLog:20
>> +        (see results below), it is important keep extra memory usage consistent,
> 
> important to ...
> 
> I would also say "correct" instead of "consistent".  I also suggest putting a period after consistent/correct, and starting "Otherwise ..." as a new sentence.

Changed.

>> Source/JavaScriptCore/jit/JITCode.h:216
>> +    }
> 
> nit: I prefer to put this all on a single line since there's only one statement in it.  For example, see intrinsic() above.

Done.

>> Source/JavaScriptCore/runtime/Options.cpp:226
>>  }
> 
> I think this is test code you forgot to remove.

Oops. I uploaded a version without this. I'm sorry for the noise.
Comment 11 Caio Lima 2019-03-13 17:28:54 PDT
Created attachment 364594 [details]
Patch
Comment 12 WebKit Commit Bot 2019-03-13 18:09:47 PDT
Comment on attachment 364594 [details]
Patch

Clearing flags on attachment: 364594

Committed r242928: <https://trac.webkit.org/changeset/242928>
Comment 13 WebKit Commit Bot 2019-03-13 18:09:49 PDT
All reviewed patches have been landed.  Closing bug.
Comment 14 Radar WebKit Bug Importer 2019-03-13 18:10:18 PDT
<rdar://problem/48872196>