Bug 112477 - Potentially unsafe register allocations in DFG code generation
Summary: Potentially unsafe register allocations in DFG code generation
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Michael Saboff
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2013-03-15 16:19 PDT by Michael Saboff
Modified: 2013-03-18 20:59 PDT (History)
4 users (show)

See Also:


Attachments
Patch (27.55 KB, patch)
2013-03-15 16:28 PDT, Michael Saboff
webkit-ews: commit-queue-
Details | Formatted Diff | Diff
Speculative patch for Qt build failure (27.64 KB, patch)
2013-03-15 17:08 PDT, Michael Saboff
ggaren: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Saboff 2013-03-15 16:19:39 PDT
A register that is allocated via GPRTemporary within one side or the other of an if () {} else {} is unsafe.  The register allocation can cause a spill on the one path that doesn't happen on the other path.  A subsequent use of the spilled register will load from the spilled location.

This was the root of https://bugs.webkit.org/show_bug.cgi?id=111777 - "Crash when updating predictions below JSC::arrayProtoFuncForEach on tuaw.com article"

I looked at the uses of GPRResult and GPRTemporary objects and found the following possibly similar issues:
   GPRTemporary structure(this) in SpeculativeJIT::compileObjectOrOtherLogicalNot for both DFGSpeculativeJIT32_64.cpp (~1598) and DFGSpeculativeJIT64.cpp (~1612)
   GPRTemporary structure(this) in SpeculativeJIT::compileObjectToObjectOrOtherEquality for both DFGSpeculativeJIT32_64.cpp (~1387) and DFGSpeculativeJIT64.cpp (~1411)
   GPRTemporary structure(this) in SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality for both DFGSpeculativeJIT32_64.cpp (~1488) and DFGSpeculativeJIT64.cpp (~1509)

Tracked also in <rdar://problem/13406093>
Comment 1 Michael Saboff 2013-03-15 16:28:20 PDT
Created attachment 193397 [details]
Patch
Comment 2 Early Warning System Bot 2013-03-15 16:56:33 PDT
Comment on attachment 193397 [details]
Patch

Attachment 193397 [details] did not pass qt-ews (qt):
Output: http://webkit-commit-queue.appspot.com/results/17060952
Comment 3 Michael Saboff 2013-03-15 17:08:02 PDT
Created attachment 193402 [details]
Speculative patch for Qt build failure

Added initialization to InvalidGPRReg for structureGPR in three places.
Comment 4 Filip Pizlo 2013-03-16 12:02:34 PDT
Comment on attachment 193402 [details]
Speculative patch for Qt build failure

Why was it wrong before?
Comment 5 Michael Saboff 2013-03-18 10:31:51 PDT
(In reply to comment #4)
> (From update of attachment 193402 [details])
> Why was it wrong before?

Compiler error for uninitialized variable.
Comment 6 Geoffrey Garen 2013-03-18 11:32:54 PDT
Comment on attachment 193402 [details]
Speculative patch for Qt build failure

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

r=me with one change suggested below:

> Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp:1609
> +    GPRTemporary structure;
> +    GPRReg structureGPR = InvalidGPRReg;
> +
> +    if (!m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
> +        GPRTemporary realStructure(this); // Only allocate on this path, before the branch
> +        structure.adopt(realStructure);
> +        structureGPR = structure.gpr();
> +    }

Let's use this model everywhere -- that way, we're always allocating our registers at the top of the function, and it's clearer that we got this right.

Let's update this comment so it's clearer why we're doing this. Something like, "The masquerades as undefined case will use the structure register, so allocate it here. Do this at the top of the function to avoid branching around a register allocation."
Comment 7 Geoffrey Garen 2013-03-18 11:39:28 PDT
> +    if (!m_jit.graph().globalObjectFor(m_currentNode->codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {

You mentioned that you were worried about this cost of this line of code. Let's put the result in a local variable and reuse it. That will resolve the cost, and read better too.
Comment 8 Michael Saboff 2013-03-18 12:14:05 PDT
Committed r146100: <http://trac.webkit.org/changeset/146100>
Comment 10 Geoffrey Garen 2013-03-18 20:28:53 PDT
(In reply to comment #9)
> Is it possible that this caused 20% memory regression on Mac?

I would put the probability of that below 1%.
Comment 11 Ryosuke Niwa 2013-03-18 20:30:00 PDT
(In reply to comment #10)
> (In reply to comment #9)
> > Is it possible that this caused 20% memory regression on Mac?
> 
> I would put the probability of that below 1%.

Okay, it's probably http://trac.webkit.org/changeset/146089 then.
Comment 12 Michael Saboff 2013-03-18 20:59:44 PDT
(In reply to comment #9)
> Is it possible that this caused 20% memory regression on Mac?
> 
> https://perf.webkit.org/#mode=charts&chartList=%5B%5B%22Mac%20MountainLion%22%2C%22Parser%2Fhtml5-full-render%3AJSHeap%22%5D%2C%5B%22Mac%20Lion%22%2C%22Parser%2Fhtml5-full-render%3AJSHeap%22%5D%5D&zoom=%5B1363572327935.7915%2C1363623676769.9104%5D

Have you checked for leaks or does it appear to be just more usage?

As Geoff says, not likely this change.  I only moved around register allocations in the DFG JIT.