Open
Bug 1222086
Opened 10 years ago
Updated 3 years ago
Block JavaScript parser thread when source code characters are not available
Categories
(Core :: JavaScript Engine, defect)
Core
JavaScript Engine
Tracking
()
NEW
| Performance Impact | low |
People
(Reporter: yury, Unassigned)
References
(Blocks 1 open bug)
Details
(Keywords: perf)
Attachments
(4 files, 16 obsolete files)
|
175 bytes,
application/x-javascript
|
Details | |
|
30.82 KB,
patch
|
djvj
:
review+
|
Details | Diff | Splinter Review |
|
12.47 KB,
patch
|
djvj
:
review+
|
Details | Diff | Splinter Review |
|
42.60 KB,
patch
|
djvj
:
review+
|
Details | Diff | Splinter Review |
So the idea is to block parsing thread when end of available source code stream is found. Currently the Parser logic depends on a JavaScript source code to be a continuous char16 buffer -- we either need to replace the initial buffer or pre-allocate enough characters to fit at the beginning. Problem with the latter is that nsIChannel cannot guarantee or does not know total length (hints like Content-Length do not work since they are reflect the encoded content length -- zipped or charset).
Pros:
- Minimal change in the Parser code base
- Practically no impact on the parsing speed
- No intermediate state to save
Cons:
- Available single Parser thread will be blocked
- Hence more than one Parsing thread must be created (bad due to thread memory overheads) and use additional heuristic needed to detect which files will be processed using this mode
| Reporter | ||
Comment 1•10 years ago
|
||
| Reporter | ||
Updated•10 years ago
|
Attachment #8683948 -
Attachment description: Pass JS source as CharsStream object. → [WIP] 1. Pass JS source as CharsStream object.
| Reporter | ||
Comment 2•10 years ago
|
||
| Reporter | ||
Comment 3•10 years ago
|
||
| Reporter | ||
Comment 4•10 years ago
|
||
| Reporter | ||
Comment 5•10 years ago
|
||
Attachment #8683948 -
Attachment is obsolete: true
| Reporter | ||
Comment 6•10 years ago
|
||
Attachment #8683949 -
Attachment is obsolete: true
| Reporter | ||
Comment 7•10 years ago
|
||
Attachment #8683951 -
Attachment is obsolete: true
| Reporter | ||
Comment 8•10 years ago
|
||
Attachment #8688180 -
Attachment is obsolete: true
| Reporter | ||
Comment 9•10 years ago
|
||
Attachment #8688181 -
Attachment is obsolete: true
| Reporter | ||
Comment 10•10 years ago
|
||
Attachment #8688182 -
Attachment is obsolete: true
| Reporter | ||
Comment 11•10 years ago
|
||
https://treeherder.mozilla.org/#/jobs?repo=try&revision=1033608147f9
I run Parsemark to see if there is a side effect from the TokenStream redesign -- there was no regression, "Meh." on all files.
| Reporter | ||
Updated•10 years ago
|
Attachment #8689048 -
Flags: review?(kvijayan)
| Reporter | ||
Updated•10 years ago
|
Attachment #8689049 -
Flags: review?(kvijayan)
| Reporter | ||
Updated•10 years ago
|
Attachment #8689052 -
Flags: review?(kvijayan)
Comment 12•10 years ago
|
||
Ah! Just saw these review requests. Will do them next week. Sorry for lateness.
Comment 13•10 years ago
|
||
Comment on attachment 8689048 [details] [diff] [review]
1. Pass JS source as CharsStream object.
Review of attachment 8689048 [details] [diff] [review]:
-----------------------------------------------------------------
Nice. Very clean and easy to understand.
::: js/src/builtin/RegExp.cpp
@@ +172,5 @@
> }
>
> /* Steps 9-10. */
> CompileOptions options(cx);
> + frontend::TokenStream dummyTokenStream(cx, options, &frontend::NullCharsStream::null(), nullptr);
It seems slightly more readable here to have the NullCharsStream usage reflect the same syntactic structure as the usage of StaticCharsStream: namely, it gets stack-allocated and a pointer gets passed to the stack-allocated item.
::: js/src/frontend/TokenStream.h
@@ +309,5 @@
> + *start = *end = nullptr;
> + *final = true;
> + }
> +
> + static NullCharsStream& null() {
I'd remove this method and use the same calling convention for NullCharsStream as users of StaticCharsStream do: stack-allocate-and-pass-pointer, instead of having a single statically allocated instance.
Minor nit, though. I don't feel strongly about it.
@@ +926,5 @@
> + if (MOZ_LIKELY(ptr < limit_))
> + return true;
> + if (final_)
> + return false;
> + requestMoreChars();
|requestMoreChars| is guaranteed to grow the buffer, right? Might be good to assert that after the call, just to make sure that implementors of |CharsStream| are fulfilling that contract.
Attachment #8689048 -
Flags: review?(kvijayan) → review+
Comment 14•10 years ago
|
||
Comment on attachment 8689048 [details] [diff] [review]
1. Pass JS source as CharsStream object.
Review of attachment 8689048 [details] [diff] [review]:
-----------------------------------------------------------------
One additional note: The |final| parameter/field might better be named something like |streamComplete|.
Comment 15•10 years ago
|
||
Comment on attachment 8689049 [details] [diff] [review]
2. Allows OffThreadCompileCallback handle chars in chunks
Review of attachment 8689049 [details] [diff] [review]:
-----------------------------------------------------------------
::: js/src/jsapi.h
@@ +746,5 @@
> length_(dataLength),
> + requestChars_(requestChars),
> + requestCharsData_(requestCharsData),
> + ownsChars_(ownership == GiveOwnership),
> + final_(!requestChars)
Nit: |final_| might be better named |streamComplete_|.
@@ +796,5 @@
> ownsChars_ = false;
> return const_cast<char16_t*>(data_);
> }
>
> + bool final() const {
see above comment about naming (streamComplete()).
Attachment #8689049 -
Flags: review?(kvijayan) → review+
Comment 16•10 years ago
|
||
Comment on attachment 8689052 [details] [diff] [review]
3. jsshell integration
Review of attachment 8689052 [details] [diff] [review]:
-----------------------------------------------------------------
::: js/src/jit-test/tests/basic/offThreadCompileScript-03.js
@@ +12,5 @@
> +
> +if (helperThreadCount() === 0)
> + quit(0);
> +
> +offThreadCompileScript('Math.sin(M', {}, false);
This test case would be clearer if the entire "subscript" being compiled was a single string, and there was an array that listed the indexes at which the script should be split up into pieces, and the repeated calls to |appendOffThreadScript| and |waitSome| were instead a loop over that index array, using substring() to pick off pieces of the script to submit in parts.
::: js/src/shell/js.cpp
@@ +5090,5 @@
> " Wait for off-thread compilation to complete. If an error occurred,\n"
> " throw the appropriate exception; otherwise, run the script and return\n"
> " its value."),
>
> +JS_FN_HELP("appendOffThreadScript", appendOffThreadScript, 0, 0,
Nice. This is very clever.
Attachment #8689052 -
Flags: review?(kvijayan) → review+
| Reporter | ||
Comment 17•10 years ago
|
||
Attachment #8689048 -
Attachment is obsolete: true
| Reporter | ||
Comment 18•10 years ago
|
||
(In reply to Kannan Vijayan [:djvj] from comment #14)
> Comment on attachment 8689048 [details] [diff] [review]
> 1. Pass JS source as CharsStream object.
>
> Review of attachment 8689048 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> One additional note: The |final| parameter/field might better be named
> something like |streamComplete|.
Fixed.
(In reply to Kannan Vijayan [:djvj] from comment #13)
> Comment on attachment 8689048 [details] [diff] [review]
> 1. Pass JS source as CharsStream object.
>
> Review of attachment 8689048 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> Nice. Very clean and easy to understand.
>
> ::: js/src/builtin/RegExp.cpp
> @@ +172,5 @@
> > }
> >
> > /* Steps 9-10. */
> > CompileOptions options(cx);
> > + frontend::TokenStream dummyTokenStream(cx, options, &frontend::NullCharsStream::null(), nullptr);
>
> It seems slightly more readable here to have the NullCharsStream usage
> reflect the same syntactic structure as the usage of StaticCharsStream:
> namely, it gets stack-allocated and a pointer gets passed to the
> stack-allocated item.
>
> ::: js/src/frontend/TokenStream.h
> @@ +309,5 @@
> > + *start = *end = nullptr;
> > + *final = true;
> > + }
> > +
> > + static NullCharsStream& null() {
>
> I'd remove this method and use the same calling convention for
> NullCharsStream as users of StaticCharsStream do:
> stack-allocate-and-pass-pointer, instead of having a single statically
> allocated instance.
>
> Minor nit, though. I don't feel strongly about it.
Fixed.
>
> @@ +926,5 @@
> > + if (MOZ_LIKELY(ptr < limit_))
> > + return true;
> > + if (final_)
> > + return false;
> > + requestMoreChars();
>
> |requestMoreChars| is guaranteed to grow the buffer, right? Might be good
> to assert that after the call, just to make sure that implementors of
> |CharsStream| are fulfilling that contract.
requestMoreChars is non-virtual, so it's safe to add this check at the requestMoreChars method body.
And the described check is already present there. Is it what you had in mind?
Flags: needinfo?(kvijayan)
| Reporter | ||
Comment 19•10 years ago
|
||
(In reply to Kannan Vijayan [:djvj] from comment #15)
> Comment on attachment 8689049 [details] [diff] [review]
> 2. Allows OffThreadCompileCallback handle chars in chunks
>
> Review of attachment 8689049 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> ::: js/src/jsapi.h
> @@ +746,5 @@
> > length_(dataLength),
> > + requestChars_(requestChars),
> > + requestCharsData_(requestCharsData),
> > + ownsChars_(ownership == GiveOwnership),
> > + final_(!requestChars)
>
> Nit: |final_| might be better named |streamComplete_|.
>
> @@ +796,5 @@
> > ownsChars_ = false;
> > return const_cast<char16_t*>(data_);
> > }
> >
> > + bool final() const {
>
> see above comment about naming (streamComplete()).
Fixed.
Attachment #8689049 -
Attachment is obsolete: true
| Reporter | ||
Comment 20•10 years ago
|
||
(In reply to Kannan Vijayan [:djvj] from comment #16)
> Comment on attachment 8689052 [details] [diff] [review]
> 3. jsshell integration
>
> Review of attachment 8689052 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> ::: js/src/jit-test/tests/basic/offThreadCompileScript-03.js
> @@ +12,5 @@
> > +
> > +if (helperThreadCount() === 0)
> > + quit(0);
> > +
> > +offThreadCompileScript('Math.sin(M', {}, false);
>
> This test case would be clearer if the entire "subscript" being compiled was
> a single string, and there was an array that listed the indexes at which the
> script should be split up into pieces, and the repeated calls to
> |appendOffThreadScript| and |waitSome| were instead a loop over that index
> array, using substring() to pick off pieces of the script to submit in parts.
>
Fixed.
Last try https://treeherder.mozilla.org/#/jobs?repo=try&revision=4228eb759fbd
Attachment #8689052 -
Attachment is obsolete: true
| Reporter | ||
Comment 21•10 years ago
|
||
Fixed "js/src/frontend/BytecodeCompiler.cpp:49:5: error: bad implicit conversion constructor for 'SourceBufferCharsStream'"
(https://treeherder.mozilla.org/#/jobs?repo=try&revision=9d2607159a52)
Attachment #8693845 -
Attachment is obsolete: true
| Reporter | ||
Comment 22•10 years ago
|
||
The hazards test was failing (https://treeherder.mozilla.org/#/jobs?repo=try&revision=4228eb759fbd&selectedJob=14272132):
Function '_ZN2js8frontend6ParserINS0_16FullParseHandlerEEC1EPNS_16ExclusiveContextEPNS_9LifoAllocERKN2JS22ReadOnlyCompileOptionsEPNS0_11CharsStreamEbPNS1_INS0_18SyntaxParseHandlerEEEPNS_10LazyScriptE *INTERNAL* |js::frontend::Parser<ParseHandler>::Parser(js::ExclusiveContext*, js::LifoAlloc*, const JS::ReadOnlyCompileOptions&, js::frontend::CharsStream*, bool, js::frontend::Parser<js::frontend::SyntaxParseHandler>*, js::LazyScript*) [with ParseHandler = js::frontend::FullParseHandler]' has unrooted 'lazyOuterFunction' of type 'js::LazyScript*' live across GC call '_ZN2js8frontend11TokenStreamC1EPNS_16ExclusiveContextERKN2JS22ReadOnlyCompileOptionsEPNS0_11CharsStreamEPNS0_16StrictModeGetterE|void js::frontend::TokenStream::TokenStream(js::ExclusiveContext*, JS::ReadOnlyCompileOptions*, js::frontend::CharsStream*, js::frontend::StrictModeGetter*)' at js/src/frontend/Parser.cpp:662
...
js/src/frontend/Parser.cpp:662: Call(6,7, this*.tokenStream.TokenStream(cx*,options*,chars*,__temp_1*.field:0)) [[GC call]]
....
js/src/frontend/Parser.cpp:662: Call(22,23, this*.handler.FullParseHandler(cx*,alloc*,this*.tokenStream,syntaxParser*,lazyOuterFunction*))
I changed the lazyOuterFunction type from LazyScript* to Handle<LazyScript*> for the ParseHandler
(Please also find requestMoreChars body for contract verification of CharsStream.request implementation)
Attachment #8693804 -
Attachment is obsolete: true
Flags: needinfo?(kvijayan)
Attachment #8694406 -
Flags: review?(kvijayan)
| Reporter | ||
Comment 24•10 years ago
|
||
rebased, new try https://treeherder.mozilla.org/#/jobs?repo=try&revision=39643287908a
Attachment #8693848 -
Attachment is obsolete: true
Updated•10 years ago
|
Attachment #8694406 -
Flags: review?(kvijayan) → review+
| Reporter | ||
Comment 25•10 years ago
|
||
Found an issue with lazy function parsing: ScriptSource::setSourceCopy was getting initial/incomplete portion of the source and it was never updated. Fixing that by calling setSourceCopy after entire source is loaded.
Attachment #8694407 -
Attachment is obsolete: true
Attachment #8700597 -
Flags: review?(kvijayan)
| Reporter | ||
Comment 26•10 years ago
|
||
Updated/added a test cases for the finding above.
https://treeherder.mozilla.org/#/jobs?repo=try&revision=a4f9bb47eb0c
Attachment #8694408 -
Attachment is obsolete: true
Attachment #8700599 -
Flags: review?(kvijayan)
Updated•10 years ago
|
Attachment #8700597 -
Flags: review?(kvijayan) → review+
Updated•10 years ago
|
Attachment #8700599 -
Flags: review?(kvijayan) → review+
| Reporter | ||
Comment 27•10 years ago
|
||
Found yesterday that the similar lazy function parsing issue happens when TokenStream's seek/tell are used. The TokenBuf.setOffsetOfNextRawChar (and requestMoreChars) is modified to sync chars buffer.
https://treeherder.mozilla.org/#/jobs?repo=try&revision=4b98db5f463d
Attachment #8694406 -
Attachment is obsolete: true
Attachment #8702607 -
Flags: review?(kvijayan)
Comment 28•10 years ago
|
||
Comment on attachment 8702607 [details] [diff] [review]
1-bug1222086-charsstream.patch
Review of attachment 8702607 [details] [diff] [review]:
-----------------------------------------------------------------
::: js/src/frontend/BytecodeCompiler.cpp
@@ +233,2 @@
> /* foldConstants = */ false, (Parser<SyntaxParseHandler>*) nullptr,
> + Handle<LazyScript*>(nullptr));
Just a question. There are many places where you convert lazyscript from being a raw pointer to rooted behaviour (using Rooted and Handle<LazyScript*>). Why is this necessary now when it wasn't before?
Attachment #8702607 -
Flags: review?(kvijayan) → review+
Updated•9 years ago
|
Whiteboard: [qf]
Updated•9 years ago
|
Whiteboard: [qf] → [qf-]
Updated•9 years ago
|
Whiteboard: [qf-] → [qf:p1]
Updated•9 years ago
|
Whiteboard: [qf:p1] → [qf:p3]
Updated•4 years ago
|
Performance Impact: --- → P3
Whiteboard: [qf:p3]
| Reporter | ||
Updated•4 years ago
|
Assignee: ydelendik → nobody
Updated•3 years ago
|
Severity: normal → S3
You need to log in
before you can comment on or make changes to this bug.
Description
•