Closed Bug 1688033 Opened 4 years ago Closed 4 years ago

Use scalar replacement to optimize the arguments object in Warp

Categories

(Core :: JavaScript Engine: JIT, enhancement, P1)

enhancement

Tracking

()

RESOLVED FIXED
89 Branch
Tracking Status
firefox89 --- fixed

People

(Reporter: iain, Assigned: iain)

References

Details

Attachments

(28 files)

(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details
(deleted), text/x-phabricator-request
Details

We currently optimize arguments by building MIR for each script that uses arguments before baseline compilation, determining whether the arguments object escapes, and (if not) passing around a magic value to represent the uninstantiated arguments object. This has a few downsides. It means we have to build MIR much earlier than we otherwise would, which slows down baseline execution. It's also quite complicated to make sure that the magic value doesn't leak out to code where it doesn't belong (and somewhat error-prone).

An alternative implementation is to treat this as just another example of scalar replacement, similar to what we already do with objects and arrays. This would only apply in Warp, but hopefully the cost of allocating the arguments object more often in baseline would be outweighed by the benefit of not having to build MIR to do the analysis.

Looking at a try run with the arguments analysis disabled, it appears that the EmberJS benchmarks in Speedometer and the Box2D and RayTrace benchmarks in Octane get the most value from the existing optimization.

Adding a jit option so that I can prototype this behind a flag.

The goal of scalar replacement of arguments is to remove all uses of the CreateArgumentsObject instruction, so that DCE can remove it.

However, the MCreateArgumentsObject constructor calls setGuard, which stops DCE from removing it. (This has been true since it was introduced.) As far as I can tell, it doesn't have to be a guard. In FinishBailoutToBaseline, if a frame needs an args object and doesn't have one, then we call ArgumentsObject::createExpected to create it from the restored baseline frame.

Depends on D103108

This is based on the existing code for scalar replacement of objects and arrays. Unlike objects and arrays, we don't have to support mutation of the arguments object, so we can simplify a lot of the code: for example, we don't need to track state per-block.

This initial patch adds support for arguments.length.

Depends on D103109

This adds support for JSOp::GetArg when arguments aliases the formal args.

Depends on D103110

This adds support for arguments[i]. It is based directly on WarpCacheIRTranspiler::emitLoadFrameArgumentResult.

If this bounds check fails, then baseline will attach a new stub in tryAttachGenericElement, preventing a bailout loop. We could also disable scalar replacement of arguments immediately, using a special BailoutKind.

Depends on D103111

Keywords: leave-open
Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/5b100262a038 Add scalarReplaceArguments jit option r=jandem https://hg.mozilla.org/integration/autoland/rev/1a5070c500b4 Allow DCE of MCreateArgumentsObject r=jandem https://hg.mozilla.org/integration/autoland/rev/f1949d2340d9 Add framework for scalar replacement of arguments r=jandem,nbp https://hg.mozilla.org/integration/autoland/rev/2205f04dd8ba Add support for GetArgumentsObjectArg r=jandem https://hg.mozilla.org/integration/autoland/rev/ee7b88395348 Add support for LoadArgumentsObjArg r=jandem

This confused me for a moment. It turns out that the problem was that I hadn't rebased on the latest copy of m-c, and although there were no merge conflicts, recent changes to m-c meant that the part of my patch adding isArgumentsObjectClass to MGuardToClass was incorrectly applied to MHasClass. I've rebased the patch. I'll give it a while to give reviewbot a chance to warn me if it's still a problem, and then I'll reland.

Flags: needinfo?(iireland)
Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/a85f89802dcf Add scalarReplaceArguments jit option r=jandem https://hg.mozilla.org/integration/autoland/rev/ad86d5f1d5c7 Allow DCE of MCreateArgumentsObject r=jandem https://hg.mozilla.org/integration/autoland/rev/c8bef0799361 Add framework for scalar replacement of arguments r=jandem,nbp https://hg.mozilla.org/integration/autoland/rev/ec8cf08562a3 Add support for GetArgumentsObjectArg r=jandem https://hg.mozilla.org/integration/autoland/rev/57bcdf857d44 Add support for LoadArgumentsObjArg r=jandem

Unlike JS_OPTIMIZED_ARGUMENTS, which is not allowed to escape its own frame, an ArgumentsObject can be passed into a different function and cause us to attach a specialized stub. In general, this all works out well. However, it does mean that some assertions in ArgumentsReplacer are too conservative: even before we support inlining functions that use arguments, it is valid to have ArgumentsObject-specific MIR that does not use the CreateArgumentsObject we are replacing.

This patch fixes those assertions and adds some test coverage.

Subsequent patches will introduce FunApplyArgsObj. I'm renaming FunApplyArgs to FunApplyMagicArgs in most places to make it easier to distinguish the two cases. (The exception is MApplyArgs/LApplyArgsGeneric, which I didn't rename because they can be produced by scalar replacement.)

Depends on D104481

The only places we check ELEMENT_OVERRIDDEN_BIT are in GetPropIRGenerator::tryAttachArgumentsObjectArg and MacroAssembler::loadArgumentsObjectElement. In both cases, we subsequently also check for deleted elements. We can remove the redundant check.

This is consistent with ArgumentsObject::obj_delProperty, which sets the other overridden bits when deleting the corresponding property.

Depends on D104482

Being able to test whether an ArgumentsObject has closed-over arguments by checking a flag instead of testing each argument makes future patches significantly simpler.

I considered just making closed-over arguments set ELEMENT_OVERRIDDEN_BIT, but this would make ArgumentsObjectArg fail if any argument was closed over, even if the specific argument we are loading is not.

Depends on D104483

Instead of adding GuardArgumentsObjectNotOverriddenElement and GuardArgumentsObjectNotForwardedArgument to go with GuardArgumentsObjectNotOverriddenIterator, I collapsed them into a single op.

This may also be useful in the future for supporting arguments.callee.

Depends on D104484

pushFunApplyArgsObj is roughly based on pushArrayArguments.

Depends on D104485

Pushing the contents of the args array in an ArgumentsData (after we have guaranteed that there are no forwarded arguments) is almost the same as pushing the contents of an elements array, but with an additional offset. In preparation for the next patch, this patch refactors PushElementsAsArguments to take an offset, and changes names/comments accordingly.

Depends on D104486

As much as possible, I based LApplyArgsObj on LApplyArrayGeneric.

I wrote the tests here by looking at existing apply testcases in jit-tests/tests/arguments and writing similar test cases where the arguments object escapes.

Depends on D104487

The original version of this patch only recovered CreateArgumentsObject on bailout if it didn't escape, but I removed that code based on discussion in #warpbuilder.

This code is tested by /ion/dce-with-rinstructions.js. Prior to this patch, it failed with --scalar-replace-arguments.

Depends on D104488

Depends on D104489

Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/834df8b4b61d Handle arguments objects from other frames r=jandem https://hg.mozilla.org/integration/autoland/rev/21d7ab0b3caf Rename FunApplyArgs to FunApplyMagicArgs r=jandem https://hg.mozilla.org/integration/autoland/rev/46a605bafc76 Set hasOverriddenElement when deleting arguments r=jandem https://hg.mozilla.org/integration/autoland/rev/81fc994238fb Add forwarded argument flag to ArgumentsObject r=jandem https://hg.mozilla.org/integration/autoland/rev/f177c8c6bc29 Add GuardArgumentsObjectFlags r=jandem https://hg.mozilla.org/integration/autoland/rev/1d5b44c118ce Add CallFlags::FunApplyArgsObj r=jandem https://hg.mozilla.org/integration/autoland/rev/bf23844b260b Refactor PushElementsAsArguments r=jandem https://hg.mozilla.org/integration/autoland/rev/adaf366a60fa Support FunApplyArgsObj in Warp r=jandem https://hg.mozilla.org/integration/autoland/rev/375186706cae Recover CreateArgumentsObject on bailout r=nbp https://hg.mozilla.org/integration/autoland/rev/776c08d542f8 Support scalar replacement of ApplyArgsObj r=jandem
Regressions: 1692861

This is the simplest feasible approach to codegen: arguments are passed to LCreateInlinedArgumentsObject as value operands, pushed on the stack, and passed to ArgumentsObject::create. The number of operands is constrained by register pressure on x86 (and arm32 is up against the limit with 3).

MCreateArgumentsObject has an optimization where we allocate the ArgumentsObject in jitcode and only call into C++ to fill it in. In the interest of simplicity and keeping register pressure down, I didn't try implementing that approach for MCreateInlinedArgumentsObject. Marginal improvements in performance for CreateInlinedArgumentsObject don't seem very valuable because our hope is to remove it via scalar replacement.

Depends on D106385

The commented-out line in the testcase will be uncommented in a subsequent patch once we support scalar replacement of inlined arguments and can replace a use.

Depends on D106707

recover-inline-arguments.js was added in the previous patch. We can uncomment the second half now that scalar replacement is supported.

Depends on D106708

Depends on D106709

Attachment #9205853 - Attachment description: Bug 1688033: Recover MCreateInlinedArgumentsObject on bailout r=nbp → Bug 1688033: Recover MCreateInlinedArgumentsObject on bailout r=jandem
Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/bbf4cf1321b7 Add MCreateInlinedArgumentsObject r=jandem https://hg.mozilla.org/integration/autoland/rev/52dd0e379bf2 Compute callee argc explicitly r=jandem

I hoisted makeCall out of WarpBuilderShared. The only changes are adding addUndefined and passing in alloc.

The pc argument to the CallInfo constructor was only used for setting the apply_ flag. Outside of assertions, the only use for this flag was in dead code in pushCallStack. (The code was originally designed to support inlining foo.apply(..., arguments). We don't currently support that, and we won't be able to support it in the future because trial inlining doesn't know where arguments comes from without escape analysis.) Instead of trying to smuggle pc into ScalarReplacement, I just removed apply_ entirely and replaced the assertions with a comment.

Depends on D106956

Depends on D106957

Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/f029f97be867 Add MCreateInlinedArgumentsObject r=jandem https://hg.mozilla.org/integration/autoland/rev/189922696db5 Compute callee argc explicitly r=jandem https://hg.mozilla.org/integration/autoland/rev/235652e53614 Recover MCreateInlinedArgumentsObject on bailout r=jandem https://hg.mozilla.org/integration/autoland/rev/82808be2d113 Scalar replace inlined arguments length r=jandem https://hg.mozilla.org/integration/autoland/rev/e57fcca626d0 Scalar replace GetArg for inlined arguments r=jandem
Regressions: 1696181
Flags: needinfo?(iireland)

Depends on D107303

If we use arguments in a loop, the transpiled GuardToObject sees a value-typed phi node and emits an MUnbox. GVN eventually cleans it up, but not before it blocks scalar replacement of arguments.

(Something similar seems to be happening in escape analysis for arrays and objects. I'm going to do a more systematic investigation of whether/how Warp broke escape analysis for objects and arrays once I'm done with arguments.)

Depends on D107304

Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/43ce6ea2f963 Scalar replace applyArgsObj for inlined arguments r=jandem https://hg.mozilla.org/integration/autoland/rev/2e361f7da898 Scalar replace arguments[i] for inlined arguments r=jandem https://hg.mozilla.org/integration/autoland/rev/b483df09813b Optimize inlined arguments[i] for constant i r=jandem
Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/42f205050335 Optimize arguments.callee in CacheIR r=jandem https://hg.mozilla.org/integration/autoland/rev/a6a48aa425d6 Scalar replace arguments.callee r=jandem https://hg.mozilla.org/integration/autoland/rev/92752f60ee8d Support trivial unboxing r=jandem

Tom pointed out in #warpbuilder that SkipUninterestingInstructions unwraps MToNumberInt32, so in theory we could have a non-int32 constant. I don't think it can happen in practice, but better safe than sorry.

Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/dc090a337afa Check type in MGetInlinedArgument::foldsTo r=jandem
Blocks: 1687025
Regressions: 1697451
Regressions: 1697483
Regressions: 1697816
Regressions: 1698126

Now that the the train has left for 88, we can turn this on by default to get as much testing as possible.

Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/a2e2f181d820 Use scalar replacement of arguments by default r=jandem

Removing leave-open tag. I'll open a follow-up bug to remove the old arguments analysis code after the next release.

Keywords: leave-open
Blocks: 1700443
Status: NEW → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → 89 Branch
Regressions: 1699910
Regressions: 1702465
Regressions: 1711414
Regressions: 1692833
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: