WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
Bug 190756
TemplateObject passed to template literal tags are not always identical for the same source location.
https://bugs.webkit.org/show_bug.cgi?id=190756
Summary
TemplateObject passed to template literal tags are not always identical for t...
Justin Fagnani
Reported
2018-10-19 11:10:03 PDT
The first argument to template literal tags should be identical for repeated evaluations of the same template literal:
https://www.ecma-international.org/ecma-262/9.0/index.html#sec-gettemplateobject
This is usually the case in WebKit, but sometimes a new template object will be passed. I made a reproduction here:
https://jsbin.com/peniburaho/1/edit?html,console,output
Usually, sometime in the first 20 iterations, the message "New ref 😢" will be written to the console, indicating that the identity of the template object has changed. On some runs I don't see the message. I've tested this on Safari 12 and Safari TP. We have multiple user reports of the issue on iOS too. We have not seen similar reports for other browsers. This is a *critical* problem for libraries that use the identity of the template object as a cache key to keep from doing duplicated work. lit-html for example uses the template object to not only cache expensive template preparation work, but to determine when a template is being re-rendered to a location in DOM vs. when a new template is being rendered to that location. If it incorrectly determines that a new template is being rendered, it destroys and recreates the DOM, causing focus, scroll position and other DOM state to be lost.
Attachments
Patch
(51.13 KB, patch)
2019-05-03 21:06 PDT
,
Yusuke Suzuki
no flags
Details
Formatted Diff
Diff
Patch
(51.13 KB, patch)
2019-05-03 21:08 PDT
,
Yusuke Suzuki
no flags
Details
Formatted Diff
Diff
Patch
(51.48 KB, patch)
2019-05-03 21:29 PDT
,
Yusuke Suzuki
no flags
Details
Formatted Diff
Diff
Patch
(65.28 KB, patch)
2019-05-03 21:50 PDT
,
Yusuke Suzuki
no flags
Details
Formatted Diff
Diff
Patch
(70.04 KB, patch)
2019-05-03 22:10 PDT
,
Yusuke Suzuki
no flags
Details
Formatted Diff
Diff
Patch
(71.20 KB, patch)
2019-05-03 23:16 PDT
,
Yusuke Suzuki
no flags
Details
Formatted Diff
Diff
Archive of layout-test-results from ews211 for win-future
(13.87 MB, application/zip)
2019-05-04 01:43 PDT
,
EWS Watchlist
no flags
Details
Patch
(71.22 KB, patch)
2019-05-04 15:53 PDT
,
Yusuke Suzuki
no flags
Details
Formatted Diff
Diff
Archive of layout-test-results from ews211 for win-future
(13.40 MB, application/zip)
2019-05-04 20:12 PDT
,
EWS Watchlist
no flags
Details
Patch
(73.66 KB, patch)
2019-05-07 14:06 PDT
,
Yusuke Suzuki
saam
: review+
Details
Formatted Diff
Diff
Show Obsolete
(7)
View All
Add attachment
proposed patch, testcase, etc.
Radar WebKit Bug Importer
Comment 1
2018-10-19 12:32:35 PDT
<
rdar://problem/45413383
>
Ryosuke Niwa
Comment 2
2018-10-19 12:49:56 PDT
Note this is affecting Google's Polymer library.
Yusuke Suzuki
Comment 3
2018-10-19 12:52:57 PDT
Hmm, I can't access to
https://jsbin.com/peniburaho/1/edit?html,console,output
now (is jsbin.com down?). Could you attach the test to this bug?
Justin Fagnani
Comment 4
2018-10-19 13:02:01 PDT
Yeah, jsbin looks down. I don't have the tab open anymore, but the code was like this: ``` const getStrings = (strings, ...values) => strings; const getRef = () => getStrings`test`; const ref = getRef(); let wait = 0; const go = () => { const newRef = getRef(); if (ref !== newRef) { console.log('New ref 😢'); } console.log(`wait ${wait}`); wait += 100; setTimeout(go, wait); }; go(); ``` Trying this now in the console just now I haven't seen the bug happen. Maybe the source needs to be in a script tag to trigger it?
Yusuke Suzuki
Comment 5
2018-10-19 13:04:22 PDT
(In reply to Justin Fagnani from
comment #4
)
> Yeah, jsbin looks down. I don't have the tab open anymore, but the code was > like this: > > ``` > const getStrings = (strings, ...values) => strings; > const getRef = () => getStrings`test`; > const ref = getRef(); > let wait = 0; > > const go = () => { > const newRef = getRef(); > if (ref !== newRef) { > console.log('New ref 😢'); > } > console.log(`wait ${wait}`); > wait += 100; > setTimeout(go, wait); > }; > go(); > ``` > > Trying this now in the console just now I haven't seen the bug happen. Maybe > the source needs to be in a script tag to trigger it?
Super nice! Reproduced. Investigating :)
Yusuke Suzuki
Comment 6
2018-10-20 10:24:47 PDT
Found the issue. CodeBlock::finishCreation perform linking. In this phase, we materialize an actual object for tagged template call site from unlinked tagged template descriptor. The problem is that the same JSFunction can discard and recreate CodeBlock multiple times. Everytime we create a new CodeBlock for the same JSFunction, we create a new object, which will break the identity.
Yusuke Suzuki
Comment 7
2018-10-22 08:28:25 PDT
Working on this. My plan is adding a new side data which holds template object information to ScriptExecutable.
Justin Fagnani
Comment 8
2019-02-04 12:25:47 PST
Yusuke Suzuki, any update here? Thanks!
Ryosuke Niwa
Comment 9
2019-02-04 14:42:35 PST
***
Bug 193764
has been marked as a duplicate of this bug. ***
Sergey Rubanov
Comment 10
2019-02-28 12:33:19 PST
Was this fixed? Can't reproduce bug on Version 12.1 (14607.1.35.1) and Release 76 (Safari 12.2, WebKit 14608.1.6.2)
https://github.com/kangax/compat-table/pull/1427#discussion_r261365767
Sergey Rubanov
Comment 11
2019-02-28 12:48:43 PST
Actually it seems that it's not fixed
https://user-images.githubusercontent.com/1507086/53596846-c6149a80-3bb1-11e9-845a-cc318123753b.png
https://user-images.githubusercontent.com/1507086/53597245-be092a80-3bb2-11e9-878b-bc967e76e7aa.png
Justin Ridgewell
Comment 12
2019-03-21 19:06:49 PDT
This is still broken in TP 78
Yusuke Suzuki
Comment 13
2019-05-03 21:06:12 PDT
Created
attachment 369041
[details]
Patch
Yusuke Suzuki
Comment 14
2019-05-03 21:08:02 PDT
Created
attachment 369042
[details]
Patch
Yusuke Suzuki
Comment 15
2019-05-03 21:29:53 PDT
Created
attachment 369043
[details]
Patch
Yusuke Suzuki
Comment 16
2019-05-03 21:50:07 PDT
Created
attachment 369047
[details]
Patch
Yusuke Suzuki
Comment 17
2019-05-03 22:10:26 PDT
Created
attachment 369049
[details]
Patch
Yusuke Suzuki
Comment 18
2019-05-03 23:16:37 PDT
Created
attachment 369058
[details]
Patch
EWS Watchlist
Comment 19
2019-05-04 01:43:55 PDT
Comment on
attachment 369058
[details]
Patch
Attachment 369058
[details]
did not pass win-ews (win): Output:
https://webkit-queues.webkit.org/results/12097754
New failing tests: legacy-animation-engine/imported/blink/compositing/layer-creation/incremental-destruction.html svg/repaint/remove-background-property-on-root.html
EWS Watchlist
Comment 20
2019-05-04 01:43:57 PDT
Created
attachment 369066
[details]
Archive of layout-test-results from ews211 for win-future The attached test failures were seen while running run-webkit-tests on the win-ews. Bot: ews211 Port: win-future Platform: CYGWIN_NT-10.0-17763-3.0.5-338.x86_64-x86_64-64bit
Yusuke Suzuki
Comment 21
2019-05-04 15:53:36 PDT
Created
attachment 369074
[details]
Patch
EWS Watchlist
Comment 22
2019-05-04 20:12:13 PDT
Comment on
attachment 369074
[details]
Patch
Attachment 369074
[details]
did not pass win-ews (win): Output:
https://webkit-queues.webkit.org/results/12102284
New failing tests: security/contentSecurityPolicy/video-with-file-url-allowed-by-media-src-star.html
EWS Watchlist
Comment 23
2019-05-04 20:12:15 PDT
Created
attachment 369081
[details]
Archive of layout-test-results from ews211 for win-future The attached test failures were seen while running run-webkit-tests on the win-ews. Bot: ews211 Port: win-future Platform: CYGWIN_NT-10.0-17763-3.0.5-338.x86_64-x86_64-64bit
Yusuke Suzuki
Comment 24
2019-05-05 01:02:23 PDT
(In reply to Build Bot from
comment #22
)
> Comment on
attachment 369074
[details]
> Patch > >
Attachment 369074
[details]
did not pass win-ews (win): > Output:
https://webkit-queues.webkit.org/results/12102284
> > New failing tests: > security/contentSecurityPolicy/video-with-file-url-allowed-by-media-src-star. > html
This is unrelated.
Saam Barati
Comment 25
2019-05-06 12:26:37 PDT
Comment on
attachment 369074
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=369074&action=review
r=me
> Source/JavaScriptCore/ChangeLog:16 > + But the top-level one is not created by CodeBlock. This top-level ScriptExecutable is well-aligned to the Script itself. The top-level ScriptExecutable has now HashMap,
has now => now has
> Source/JavaScriptCore/runtime/FunctionExecutable.h:339 > + // FIXME: We can merge rareData pointer and top-level executable pointer. First time, setting parent. If RareData is required, materialize RareData, swap it, and store > + // top-level executable pointer inside RareData.
If you think we should do this, please file a bug and link it here. Otherwise, if you don't think it's important, let's remove this FIXME
> Source/JavaScriptCore/runtime/ModuleProgramExecutable.cpp:96 > +auto ModuleProgramExecutable::ensureTemplateObjectMap(VM&) -> TemplateObjectMap& > +{ > + if (m_templateObjectMap) > + return *m_templateObjectMap; > + auto result = std::make_unique<TemplateObjectMap>(); > + WTF::storeStoreFence(); > + m_templateObjectMap = WTFMove(result); > + return *m_templateObjectMap; > +}
You have this more or less implemented four times. Maybe you can do: static TemplateObjectMap& ensureTemplateObjectMapImpl(std::unique_ptr<TemplateObjectMap>& dst) { if (dst) return *dst; auto result = std::make_unique<TemplateObjectMap>(); WTF::storeStoreFence(); dst = WTFMove(result); return *dst; } And then call this as appropriate from four places.
> Source/JavaScriptCore/runtime/ScriptExecutable.cpp:463 > + RETURN_IF_EXCEPTION(scope, nullptr);
I think you have a bug if this exception is thrown. Because the next time this is called, you'll end up returning a null array. I think you might want the above "!result.isNewEntry" to also check the value in the hashmap. Would be good to add a test if it's possible.
> Source/JavaScriptCore/runtime/ScriptExecutable.cpp:480 > + ASSERT(type() == ModuleProgramExecutableType); > + return static_cast<ModuleProgramExecutable*>(this)->ensureTemplateObjectMap(vm);
nit: this styling feels weird. Why not just ASSERT_NOT_REACHED() in "default" case and move this logic up to ModuleProgramExecutableType?
Yusuke Suzuki
Comment 26
2019-05-06 13:35:57 PDT
Comment on
attachment 369074
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=369074&action=review
Thanks!
>> Source/JavaScriptCore/ChangeLog:16 >> + But the top-level one is not created by CodeBlock. This top-level ScriptExecutable is well-aligned to the Script itself. The top-level ScriptExecutable has now HashMap, > > has now => now has
Fixed.
>> Source/JavaScriptCore/runtime/FunctionExecutable.h:339 >> + // top-level executable pointer inside RareData. > > If you think we should do this, please file a bug and link it here. Otherwise, if you don't think it's important, let's remove this FIXME
Added URL.
>> Source/JavaScriptCore/runtime/ModuleProgramExecutable.cpp:96 >> +} > > You have this more or less implemented four times. Maybe you can do: > > static TemplateObjectMap& ensureTemplateObjectMapImpl(std::unique_ptr<TemplateObjectMap>& dst) > { > if (dst) > return *dst; > auto result = std::make_unique<TemplateObjectMap>(); > WTF::storeStoreFence(); > dst = WTFMove(result); > return *dst; > } > > And then call this as appropriate from four places.
Fixed.
>> Source/JavaScriptCore/runtime/ScriptExecutable.cpp:463 >> + RETURN_IF_EXCEPTION(scope, nullptr); > > I think you have a bug if this exception is thrown. Because the next time this is called, you'll end up returning a null array. I think you might want the above "!result.isNewEntry" to also check the value in the hashmap. Would be good to add a test if it's possible.
Nice catch! Yeah, correct. We can do, if (JSArray* array = result.iterator->value.get()) return array; instead. Fixed.
>> Source/JavaScriptCore/runtime/ScriptExecutable.cpp:480 >> + return static_cast<ModuleProgramExecutable*>(this)->ensureTemplateObjectMap(vm); > > nit: this styling feels weird. Why not just ASSERT_NOT_REACHED() in "default" case and move this logic up to ModuleProgramExecutableType?
This is because we need to return some `TemplateObjectMap&` even in ASSERT_NOT_REACHED() case to make the compiler happy. But we do not have a good thing to be returned at `default:` case. That's why I merge default and the last case, and putting ASSERT inside it. If we change TemplateObjectMap& to TemplateObjectMap*, we can return `nullptr` from the default: clause, but I prefer using TemplateObjectMap& than TemplateObjectMap* here since ensureXXX should return non-null thing.
Yusuke Suzuki
Comment 27
2019-05-06 14:33:40 PDT
Committed
r244978
: <
https://trac.webkit.org/changeset/244978
>
Ryan Haddad
Comment 28
2019-05-06 16:06:16 PDT
This change caused two test262 failures: ---------------NEW FAILING TESTS SUMMARY--------------- FAIL test/language/expressions/tagged-template/chained-application.js (default) Full Output: Exception: Test262Error: Expected SameValue(«x», «y») to be true FAIL test/language/expressions/tagged-template/chained-application.js (strict mode) Full Output: Exception: Test262Error: Expected SameValue(«x», «y») to be true
https://build.webkit.org/builders/Apple%20High%20Sierra%20Debug%20Test262%20%28Tests%29/builds/2203
Yusuke Suzuki
Comment 29
2019-05-07 11:31:16 PDT
(In reply to Ryan Haddad from
comment #28
)
> This change caused two test262 failures: > > ---------------NEW FAILING TESTS SUMMARY--------------- > > FAIL test/language/expressions/tagged-template/chained-application.js > (default) > Full Output: > Exception: Test262Error: Expected SameValue(«x», «y») to be true > > FAIL test/language/expressions/tagged-template/chained-application.js > (strict mode) > Full Output: > Exception: Test262Error: Expected SameValue(«x», «y») to be true > > >
https://build.webkit.org/builders/
> Apple%20High%20Sierra%20Debug%20Test262%20%28Tests%29/builds/2203
Look into it, thanks!
Yusuke Suzuki
Comment 30
2019-05-07 12:01:26 PDT
(In reply to Yusuke Suzuki from
comment #29
)
> (In reply to Ryan Haddad from
comment #28
) > > This change caused two test262 failures: > > > > ---------------NEW FAILING TESTS SUMMARY--------------- > > > > FAIL test/language/expressions/tagged-template/chained-application.js > > (default) > > Full Output: > > Exception: Test262Error: Expected SameValue(«x», «y») to be true > > > > FAIL test/language/expressions/tagged-template/chained-application.js > > (strict mode) > > Full Output: > > Exception: Test262Error: Expected SameValue(«x», «y») to be true > > > > > >
https://build.webkit.org/builders/
> > Apple%20High%20Sierra%20Debug%20Test262%20%28Tests%29/builds/2203 > > Look into it, thanks!
OK, bug is found, I'll quickly upload the follow-up fix.
WebKit Commit Bot
Comment 31
2019-05-07 12:22:37 PDT
Re-opened since this is blocked by
bug 197671
Yusuke Suzuki
Comment 32
2019-05-07 14:06:01 PDT
Created
attachment 369324
[details]
Patch
Yusuke Suzuki
Comment 33
2019-05-07 15:16:09 PDT
Committed
r245040
: <
https://trac.webkit.org/changeset/245040
>
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug