Bug 200792 - CodeBlock destructor should clear all of its watchpoints.
Summary: CodeBlock destructor should clear all of its watchpoints.
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Mark Lam
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2019-08-15 15:25 PDT by Mark Lam
Modified: 2019-08-16 15:50 PDT (History)
9 users (show)

See Also:


Attachments
proposed patch. (4.28 KB, patch)
2019-08-15 15:31 PDT, Mark Lam
no flags Details | Formatted Diff | Diff
proposed patch. (5.63 KB, patch)
2019-08-16 00:58 PDT, Mark Lam
ysuzuki: review+
Details | Formatted Diff | Diff
patch for landing. (8.86 KB, patch)
2019-08-16 15:46 PDT, Mark Lam
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Lam 2019-08-15 15:25:03 PDT
<rdar://problem/53947800>
Comment 1 Mark Lam 2019-08-15 15:31:09 PDT
Created attachment 376434 [details]
proposed patch.
Comment 2 Mark Lam 2019-08-16 00:58:42 PDT
Created attachment 376482 [details]
proposed patch.
Comment 3 Yusuke Suzuki 2019-08-16 01:34:08 PDT
Comment on attachment 376482 [details]
proposed patch.

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

r=me with comments.
And can you ensure that all the watchpoints having CodeBlock as an owner are cleared by DFG::Common::clearWatchpoints?
LLIntPrototypeLoadAdaptiveStructureWatchpoint is not included, but it is OK since it is held by CodeBlock directly.

> Source/JavaScriptCore/bytecode/CodeBlock.cpp:814
> +#if ENABLE(DFG_JIT)

Can you add a comment describing this pathological thing here?

> Source/JavaScriptCore/bytecode/CodeBlock.cpp:815
> +    if (JITCode::isOptimizingJIT(jitType()))

Is baseline JIT OK?

> Source/JavaScriptCore/bytecode/CodeBlock.cpp:816
> +        jitCode()->dfgCommon()->clearWatchpoints();

The watchpoints are typically registered to jettison CodeBlock when the critical invariant is broken.
After CodeBlock is destroyed, I think that JITCode code itself is completely invalid.
Is it possible that the JITCode is executed while CodeBlock is destroyed. If it happens, why is it safe? If it does not happen, can we add assertion to ensure it in JITCode or some places?
Comment 4 Mark Lam 2019-08-16 15:38:48 PDT
Thanks for the review.

(In reply to Yusuke Suzuki from comment #3)
> Comment on attachment 376482 [details]
> proposed patch.
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=376482&action=review
> 
> r=me with comments.
> And can you ensure that all the watchpoints having CodeBlock as an owner are
> cleared by DFG::Common::clearWatchpoints?
> LLIntPrototypeLoadAdaptiveStructureWatchpoint is not included, but it is OK
> since it is held by CodeBlock directly.

I've audited all the Watchpoint types and verified that any watchpoints associated with a CodeBlock is handled by this patch.  I'll documented the audit details in the ChangeLog.


> > Source/JavaScriptCore/bytecode/CodeBlock.cpp:814
> > +#if ENABLE(DFG_JIT)
> 
> Can you add a comment describing this pathological thing here?

Added.
 
> > Source/JavaScriptCore/bytecode/CodeBlock.cpp:815
> > +    if (JITCode::isOptimizingJIT(jitType()))
> 
> Is baseline JIT OK?

Yes.  baseline JIT ha a null dfgCommon(), and hence, cannot have any of the watchpoints in there.

> > Source/JavaScriptCore/bytecode/CodeBlock.cpp:816
> > +        jitCode()->dfgCommon()->clearWatchpoints();
> 
> The watchpoints are typically registered to jettison CodeBlock when the
> critical invariant is broken.
> After CodeBlock is destroyed, I think that JITCode code itself is completely
> invalid.
> Is it possible that the JITCode is executed while CodeBlock is destroyed. If
> it happens, why is it safe? If it does not happen, can we add assertion to
> ensure it in JITCode or some places?

I don't think we execute any code in the JITCode after the CodeBlock is destroyed.  We don't have control flow that will lead to us stepping on the dead code.  However, we do need to clear the watchpoints because we do have control flow that can lead to us stepping on the dead watchpoints if we don't eagerly clear them out.

To ensure that the dead JITCode is not executed after the CodeBlock is destroyed, we can do 1 of the following:
1. on debug builds, fill the JITCode with breakpoint traps on CodeBlock destruction if JITCode's refCount is greater than 1.  This ensure that we'll crash if someone tries to execute any instructions in there.  Or, ...
2. re-architect the system to ensure that CodeBlock is the sole owner of JITCode, and can cleanly delete it on destruction.

I think option 2 is the more efficient solution, but this is out of scope for this patch.  I can look into this later on.

I'll land this patch with the added comments.
Comment 5 Mark Lam 2019-08-16 15:46:51 PDT
Created attachment 376550 [details]
patch for landing.
Comment 6 Mark Lam 2019-08-16 15:50:27 PDT
Landed in r248800: <http://trac.webkit.org/r248800>.