Generating JS Warnings is very slow, profile shows js::mjit::ExpandInlineFrames and NS_ScriptErrorReporter

NEW
Unassigned

Status

()

7 years ago
4 years ago

People

(Reporter: bjacob, Unassigned)

Tracking

Firefox Tracking Flags

(Not tracked)

Details

(Whiteboard: [js:p2])

Attachments

(1 attachment)

Created attachment 622698 [details]
profile (inverted call-graph)

This has been a problem for a long time and the reason why the webgl.verbose preference exists, rather than always generating JS Warnings on WebGL errors.

STR:
 1. set webgl.verbose = true
 2. go to https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/tests/conformance/state/gl-object-get-calls.html

Expected: should be almost as fast as with webgl.verbose = false.

Actual: browser freezes for several seconds, sometimes shows 'unresponsive script' warning.

A minimal testcase could be obtained by simply doing

  for (var i = 0; i < 100000; i++) {
    do_something_that_causes_a_js_warning();
  }

The attached profile shows that we're spending most of our time in js::mjit::ExpandInlineFrames.

Could we cache some results, as, when there are large numbers of warnings, it's often the same warning that's being repeated?

Could we avoid doing work? Defer doing work until the Web Console is opened?

Could we set a global default limit on the number of warnings that a single script can generate? (Of course I'm going to do this manually for WebGL, on a per-context basis).
The profile also shows significant amounts of time spent under NS_ScriptErrorReporter.
Summary: Generating JS Warnings is very slow, profile shows js::mjit::ExpandInlineFrames → Generating JS Warnings is very slow, profile shows js::mjit::ExpandInlineFrames and NS_ScriptErrorReporter
Blocks: 743753
Is this with the error console and web console both closed?
Yes, both closed. The STR in comment 0 should be complete.
OK.  So there are two things going on here:

1)  The ExpandInlineFrames bit: JS Errors carry a callstack, so generating an Error object requires creation of said callstack; I assume that's what's going on there.

2)  NS_ScriptErrorReporter.  This is not part of the JS engine; this is the DOM error reporter that actually reports things to the error console.  Unfortunately, the error console API (or more precisely nsIScriptError) is dumb and takes PRUnichar* and char*, so we end up with strings in the JS Error, then we make _another_ copy of the strings for the ErrorEvent that the DOM reporter uses, and that has to then pass raw underlying pointers to the nsIScriptError which then copies _again_.  Plus there's the creation of nsIScriptErrors via do_CreateInstance, etc, etc.

Basically, none of these codepaths are really optimized for performance: uncaught exception performance doesn't matter too much, and no warnings are generated in normal operation, usually....

For what it's worth, for purposes of WebGL it might be worth looking into just generating warnings directly using the nsContentUtils APIs we have for this, unless you really need the "make them exceptions if the pref to make warnings fatal" behavior.
I'll look into the nsContentUtils APIs but  I believe that there are valid use cases for causing many JS warnings/errors, for example: fuzzing.

The above testcase could be handled by switching the WebGL impl  to use nsContentUtils (we don't need these to be real JS warnings)  but there should exist valid fuzzing use cases where real JS warnings happen, no?
Not really.  The JS engine really doesn't generate any warnings by default unless a pref for it is flipped.  It does generate exceptions, of course, but caught ones never end up in NS_ScriptErrorReporter, and uncaught ones are not often generated in huge quantities.

Not to say we shouldn't make this stuff faster, of course.  ;)
Whiteboard: [js:p2]
Assignee: general → nobody
You need to log in before you can comment on or make changes to this bug.