Last Comment Bug 1235046 - Make code poisoning in JitCode::finalize faster with W^X
: Make code poisoning in JitCode::finalize faster with W^X
Status: RESOLVED FIXED
:
Product: Core
Classification: Components
Component: JavaScript Engine: JIT (show other bugs)
: unspecified
: All All
-- normal (vote)
: mozilla46
Assigned To: Jan de Mooij [:jandem]
:
: Hannes Verschore [:h4writer]
Mentors:
Depends on:
Blocks: 1215479
  Show dependency treegraph
 
Reported: 2015-12-24 04:02 PST by Jan de Mooij [:jandem]
Modified: 2016-03-14 04:31 PDT (History)
2 users (show)
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---
fixed


Attachments
Patch (14.11 KB, patch)
2015-12-24 04:02 PST, Jan de Mooij [:jandem]
bhackett1024: review+
Details | Diff | Splinter Review

Description User image Jan de Mooij [:jandem] 2015-12-24 04:02:26 PST
Created attachment 8701814 [details] [diff] [review]
Patch

We poison JIT code (in JitCode::finalize) in all builds. With W^X enabled that can be pretty slow: we often mprotect the exact same pages while we finalize different JitCodes.

The attached patch optimizes this: JitCode::finalize adds a JitPoisonRange entry to a Vector stored in FreeOp (similar to the freeLater Vector there). Then in ~FreeOp, we pass this Vector to ExecutableAllocator::poisonCode, where we can do the poisoning much more efficiently by ensuring each ExecutablePool is made writable only once.

On a pretty worst-case benchmark, this reduces the time spent poisoning from 57 ms to 2 ms or so.
Comment 1 User image Jan de Mooij [:jandem] 2015-12-24 04:06:11 PST
Comment on attachment 8701814 [details] [diff] [review]
Patch

Review of attachment 8701814 [details] [diff] [review]:
-----------------------------------------------------------------

::: js/src/vm/Runtime.h
@@ +1600,5 @@
> +inline bool
> +FreeOp::appendJitPoisonRange(const jit::JitPoisonRange& range)
> +{
> +    // FreeOps other than the defaultFreeOp() are constructed on the stack,
> +    // and won't hold onto the pointers to free indefinitely.

Ugh, copy/paste typo. s/pointers to free/ranges to poison/
Comment 2 User image Brian Hackett (:bhackett) 2015-12-24 04:32:46 PST
Comment on attachment 8701814 [details] [diff] [review]
Patch

Review of attachment 8701814 [details] [diff] [review]:
-----------------------------------------------------------------

::: js/src/jit/ExecutableAllocator.cpp
@@ +370,5 @@
> +
> +    // Don't race with reprotectAll called from the signal handler.
> +    JitRuntime::AutoPreventBackedgePatching apbp(rt);
> +
> +    for (size_t i = 0; i < ranges.length(); i++) {

Maybe have an #ifdef DEBUG loop before this one that asserts the mark bits are clear on all the pools?

::: js/src/jit/Ion.cpp
@@ +873,5 @@
> +    MOZ_ASSERT(pool_);
> +
> +    // With W^X JIT code, reprotecting memory for each JitCode instance is
> +    // slow, so we just record the ranges and poison them later all at once.
> +    if (fop->appendJitPoisonRange(JitPoisonRange(pool_, code_, bufferSize_)))

A note about why it's ok to ignore append failure would be good here.
Comment 4 User image Jan de Mooij [:jandem] 2015-12-24 08:57:05 PST
(In reply to Brian Hackett (:bhackett) from comment #2)
> Maybe have an #ifdef DEBUG loop before this one that asserts the mark bits
> are clear on all the pools?

Good idea, done.
Comment 5 User image Ryan VanderMeulen [:RyanVM] 2015-12-25 17:24:36 PST
https://hg.mozilla.org/mozilla-central/rev/dd9728713ebb

Note You need to log in before you can comment on or make changes to this bug.