-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Normative: Cache templates per site, rather than by contents #890
Conversation
@littledan The behavior in SM was recently patched to be per-content and live-forever. Though I'd be very, very happy to revert this. :) |
FWIW the eshost test
hangs on three engines, apparently as they fight over allocating more system memory, but completes cleanly in the older version of SM that I'm running. |
@caitp implemented V8's template literals, she may have thoughts here. |
The template object caching landed separately from the main feature (https://codereview.chromium.org/742643003). Though there's no mention of it on the CL, there had been some discussion at the time about it off of rietveld. I believe the rationalization for the caching was to help some tagged template literal functions do their work faster. It's still unclear to me how caching would help userspace code at all, since the substitution values aren't taken into account. From v8's POV, I think I would prefer if template objects were not cached, and I'm not sure any actual applications are doing any kind of caching (as noted above, not useful because substitutions not considered). |
@caitp on userspace use cases: Helper tag that removes comments/whitespaces from regexp patterns, like Ruby's extended flag. It should not care about substitutions, only strings in EDIT: I've measured 5-6x perf boost in patterns with > 5 substitutions because of caching, V8. |
Right, but those are still fairly limited uses. Thanks for mentioning it, though. I appreciate seeing uses in the wild. |
@caitp Caching was a core feature that @erights and Mike Samuel had in the original proposal. It is useful for memoizing expensive work. We used this feature effectively in traceur to not have to reparse parse trees. https://github.com/google/traceur-compiler/blob/master/src/codegeneration/PlaceholderParser.js |
@arv Do you think this PR leaves enough caching in place to be a benefit to the way Traceur took advantage of it here? |
I concede the point, thanks for taking the time to explain the need for the cache, guys. Based on the examples I've seen, I think the proposed change to the lifetime of cached entries makes sense, and shouldn't hurt code using that style in the wild. |
I just looked at the pull request itself. What determines when two Parse Nodes are the same? What does Parse Node mean precisely in the context of the rest of the spec? |
(reentering comment so I can use markdown)
Hi @caitp , The whole point of the design is to enable the tag to parse and preparation See https://github.com/erights/quasiParserGenerator for a good example. var arith = bnf`
start ::= expr EOF ${(v,_) => v};
expr ::=
term "+" expr ${(a,_,b) => (...subs) => a(...subs) + b(...subs)}
/ term;
term ::=
NUMBER ${n => (..._) => JSON.parse(n)}
/ HOLE ${h => (...subs) => subs[h]}
/ "(" expr ")" ${(_,v,_2) => v};
`;
} Does one parser generation from the literally described grammar, and can The tag it generates can be used function foo(i) {
return arith`1 + (2 + ${i} + ${i+1}) + 4`;
} to reuse the parse and preparation from the literal parts of the DSL, and |
@erights Parse Node is a concept used around the spec; it was already the input to the modified abstract algorithm. For equality, I want to say that this is by identity, that is, whenever a different string is parsed as ECMAScript source text, it generates new Parse Nodes with a distinct identity that is being tested here. Do you have suggestions for wording to clarify that? |
Actually, if made explicit, I think that's a great clarification. Each act of parsing endows the resulting parse nodes with unique identities. To avoid muddying your otherwise great clarification, I would delete the "different" in
It does not matter whether the string is different. What matters is each time the spec calls for the act of parsing this string. In particular: eval(str); eval(str); causes str to be parsed twice, resulting in parse nodes with distinct identities, even though the string is not different. With the identity issue made explicit, and perhaps even illustrated with this example in a note, I like this PR. It repairs all the problems you pointed out with the content-based caching and opens the door to the addition of a source map. The loss of memo hits that would result is of no consequence whatever. Tags would still get the memo hit they need --- from successive evaluation of the "same" template literal expression, for an adequate sense of "same". Thanks! |
The place where the concept of "Parse Node" probably should be clarified is in [5.2]{https://tc39.github.io/ecma262/#sec-algorithm-conventions) which currently says:
The term"parse node" is used several times in ECMA-262 but currently does not have a definition. In the current spec. parsing takes place in step 2 ParseScript and step 2 of ParseModule. Also in step 6 of PerformEval. The two step 2s should probably be refactored into a common ParseSourceText abstract operation parameterized with the goal symbol and PerfomEval step 6 should be rewritten to use that abstract operation. Then a "parse node" can be defined as a node of the parse tree produced by ParseSourceText. And the above coded paragraph of 5.2 might be rewritten as (added text in italic):
|
There's been a definition (in The Syntactic Grammar) since #804 was merged two months ago.
Also in:
(but this is maybe getting a little off-topic) |
@erights Great example, I completely agree that those should be separate Parse Nodes. Thanks for the correction. |
@jmdyck Thanks for doing the hard work of building the basis for describing parse nodes around the spec. I uploaded a patch which uses that to define the "same parse node", as used in template caching in this PR. What do you think? |
spec.html
Outdated
</td> | ||
<td> | ||
Template objects are canonicalized separately for each realm using its Realm Record's [[TemplateMap]]. Each [[Strings]] value is a List containing, in source text order, the raw String values of a |TemplateLiteral| that has been evaluated. The associated [[Array]] value is the corresponding template object that is passed to a tag function. | ||
Template objects are canonicalized separately for each realm using its Realm Record's [[TemplateMap]]. Each [[Site]] value is a Parse Node containing a |TemplateLiteral|. The associated [[Array]] value is the corresponding template object that is passed to a tag function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than "a Parse Node containing a |TemplateLiteral|", it would be more consistent (with usage in the rest of the spec) to say something like:
- "a Parse Node that is a |TemplateLiteral|", or
- "a Parse Node that is an instance of |TemplateLiteral|", or
- "a |TemplateLiteral| (i.e., a Parse Node)".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
FWIW, I think the current text is now better WRT @allenwb's feedback: https://tc39.github.io/ecma262/#sec-syntactic-grammar paragraph 3 defines parse nodes in a way that I think doesn't require further abstraction into an explicit ParseSourceText AO. Let me know if you disagree. |
Do you think that it makes the freshness requirement explicit? Perhaps I am missing something? |
spec.html
Outdated
@@ -440,6 +440,8 @@ | |||
<p>The <em>syntactic grammar</em> for ECMAScript is given in clauses 11, 12, 13, 14, and 15. This grammar has ECMAScript tokens defined by the lexical grammar as its terminal symbols (<emu-xref href="#sec-lexical-and-regexp-grammars"></emu-xref>). It defines a set of productions, starting from two alternative goal symbols |Script| and |Module|, that describe how sequences of tokens form syntactically correct independent components of ECMAScript programs.</p> | |||
<p>When a stream of code points is to be parsed as an ECMAScript |Script| or |Module|, it is first converted to a stream of input elements by repeated application of the lexical grammar; this stream of input elements is then parsed by a single application of the syntactic grammar. The input stream is syntactically in error if the tokens in the stream of input elements cannot be parsed as a single instance of the goal nonterminal (|Script| or |Module|), with no tokens left over.</p> | |||
<p>When a parse is successful, it constructs a <em>parse tree</em>, a rooted tree structure in which each node is a <dfn>Parse Node</dfn>. Each Parse Node is an <em>instance</em> of a symbol in the grammar; it represents a span of the source text that can be derived from that symbol. The root node of the parse tree, representing the whole of the source text, is an instance of the parse's goal symbol. When a Parse Node is an instance of a nonterminal, it is also an instance of some production that has that nonterminal as its left-hand side. Moreover, it has zero or more <em>children</em>, one for each symbol on the production's right-hand side: each child is a Parse Node that is an instance of the corresponding symbol.</p> | |||
<p>Each time a stream of code points is parsed, it produces Parse Nodes with a fresh identity. Two Parse Nodes are considered <dfn>the same Parse Node</dfn> if they have the same identity, that is, that they resulted from the same invocation the grammar.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this clarification confusing personally. Suggestions (not sure if I like them, but here they are):
Add to previous graph a note about fresh instances:
Each Parse Node is an instance of a symbol in the grammar; Parse Nodes represent a span of the source text that can be derived from that symbol. New Parse Nodes are newly instantiated for each invocation of the parser and never reused between parses even of identical source text.
Then...
Parse nodes are considered identical if and only if they are the same instance. Thus, two parse nodes are identical if and only if they represent the same span of source text, are instances of the same grammar symbol, and resulted from the same parser invocation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(In "Parse Nodes represent", the plural doesn't make sense, because the rest of the sentence is singular. You could change it to "the Parse Node represents" or just leave it as "it represents".)
"New ... newly" is redundant.
I can imagine an implementer balking at the suggestion they can't reuse the results of a previous parse, so you might want to add a note saying why it's specified that way. Or at least a cross-reference to places in the spec where the identity of Parse Nodes is important.
Have you convinced yourself that no-reuse doesn't have unintended consequences? I.e., that there aren't places in the spec that already implicitly assume 'reuse' of parse nodes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can imagine an implementer balking at the suggestion they can't reuse the results of a previous parse
Implementations are free to do anything that doesn't observably violate the specification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, so my imagined implementor would want to know how reusing the result of a previous parse would observably violate the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would still prefer my proposed tweak here (with updates from @jmdyck) - thoughts @littledan?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@erights I don't think it does - I was only commenting on the need to define Parse Nodes. Just pointing out I've since added a definition (with a dfn and all!) so further abstraction isn't necessary. But if you think explicit ParseSourceText AO is warranted for clarifying "Freshness" I'd be ok with that. I proposed some alternative language above you might find acceptable, too... |
+1 |
We discussed this PR at the July TC39 meeting. @allenwb seemed to argue (please correct me if I'm misunderstanding) that it may be OK if not all of this memory is collectable, and that this "leak" is by-design behavior. The memory is collected when the realm dies, which should be enough for applications which consist of many short-lived realms. Even if it was by design, I still think this issue is worth discussing further. I believe this is the only piece of memory associated with running code which cannot be collected if the function becomes unreachable. For a long-running JavaScript application, which may load various pieces of code and then move onto other pieces of code, without creating new realms for the new code and discarding old realms, this could be a serious issue. |
@waldemarhorwat pointed out that we need to clarify how ParseNode behaves in the presence of cover grammars, which trigger reparsing. Modulo that, this proposal reached consensus at the September 2017 TC39 meeting. |
who on earth would do anything different from that? I don't distribute multiple Babel patches per file, I bundle all at once and babel once the result. Babel is not the issue here, Babel tries its best to provide what's defined in here. |
Also, I don't get to know how 3rd parts use my code so none of you has any solution to the problem I am describing:
None of this has ever been my problem for my 100% code covered library that works in every browser, so thanks again for considering improving the way you break specifications. |
The majority of people use
Yup! Just wanted to clarify that I'd never expect the average user of Babel to be able to share template instances beyond the file level. |
|
Bundlers babel each file separately and then bundle the result - webpack and browserify specifically. |
I don't know how you configured that, that's not what I do, neither what my WebPack or Rollup do, but on top of that, I don't care. If interested, we can have a conversation a part where I explain you how to bundle without babel in the middle and then bundle, if needed, only the result at once, not per file (per file is silly) |
I'd like to remind everyone that we have a code of conduct. We're getting to a point of being aggressive with our responses, and that won't fly. To address a few points:
Using a
Discussing Babel's processing of files seems off-topic.
We made a breaking change in an attempt to prevent a pretty easy memory leak. Out intuition was that this was not a going to cause much pain, because any significant length template strings would not be duplicated in source code. It certainly might bite devs who duplicate shorter templates strings. Additionally, Firefox seems not to have implemented the correct behavior, and Babel/TypeScript didn't. So we really didn't see this as too badly breaking. A pretty simple solution for detecting let MapConstructor;
try {
const map = new WeakMap();
const frozen = Object.freeze({});
map.add(frozen, 1);
if (map.get(frozen) !== 1) {
throw new Error('sham');
}
MapConstructor = WeakMap;
} catch (e) {
MapConstructor = Map;
} |
I am already doing shimming the WeakMap but if I fallback to Map, since Babel 7 will not return always the same object, I will cause inevitably leaks, the reason this change was proposed, to legacy browsers, those already slow, those with usually less RAM to spare. This is not a solution for me, just a work around to not have breaking code. I have leaking code now, while before the leak was contained in an easy to measure amount of template literals. Now leaks in legacy browsers are unpredictable due new transpiler behavior (that simply follows specs updates) |
You have the same source text for a couple reasons:
As prior art v8 and other engines all cache regexes based on text not source location.
Ex. You might write: element.append(html`<p>${user.name}`);
if (user.email) {
element.append(html`<p>${user.email}`);
}
// ... And so on with lots of repeated markup. And it's also natural for multiple components to use the same markup. For example different form widgets would do: root.append(html`<label for=input>${this.label}</label>`); (Note with shadow roots ids are not unique, so this is totally fine to reuse the same id inside every component). It's also natural to create web components this way: button1 = html`<app-button>${text}`;
// In another part of the program
button2 = html`<app-button>${otherText}` I'd just caution about making assumptions about there not being lots of repeated tagged templates, that's a pretty reasonable way to use them. :) |
I think that the discussion should be more about how changes like this one can have very drastic compounding effects downstream. When a spec changes, implementers have all the capabilities they need to manage efficiencies. Then we hit the very visible barriers that are enforced on JavaScript execution in browsers (for everyone's benefit). So, if an opportunity presented itself to come up with a very reliable caching/mapping mechanism, which was to spec for more than 1 revision of the standard, it obviously cannot be not breaking, or at the very least worthy of a mitigating alternative other than reliance on the notion that polyfills are actually solutions. The little interaction from the rest of the community is not necessarily approval, this ecosystem is built on the notion of compartmentalization, and people don't often realize what the package they use really does internally or how it relates to specs. In fact, I know of a similar library which was a mainstream buzz for a while, and if anything, at least some of their team had no idea how the spec related to what they were putting inside their blackbox for us users to use "reliably". The specs are for implementers, but they ultimately and far more importantly define the limitations that are imposed on the rest of the JavaScript community who actually use the features as they are made available. Let's not just create a new concept with this kind of change, but if we do, I suggest we use the term For this I think that RegExp's |
just to clarify, it looks like I was the only one out there using |
@esprehn I don't think anything in the new design makes it impossible or even very difficult to do caching based on source text, and I don't debate that caching based on source text can be useful. This change just doesn't make the default behavior to require this caching and, as such, create a guaranteed memory leak (even if you clear out the not-recently-used elements of your Map, the system has to keep the mapping from strings to template objects eternally). |
compat-table#1424 for context. The Safari bug revealed that `getStrings() !== new getStrings()`, making this easily testable. I've separated the original test into two: 1. Test TemplateStrings call site [revision](tc39/ecma262#890) 2. Test the buggy Safari behavior explicitly
- 2016: the Unicode change affected what was considered whitespace (tc39#300 / 24dad16) - 2018: changed tagged template literal objects to be cached per source location rather than per realm (tc39#890) - 2019: Atomics.wake was renamed to Atomics.notify (tc39#1220) - 2019: `await` was changed to require fewer ticks (tc39#1250)
- 2016: the Unicode change affected what was considered whitespace (tc39#300 / 24dad16) - 2018: changed tagged template literal objects to be cached per source location rather than per realm (tc39#890) - 2019: Atomics.wake was renamed to Atomics.notify (tc39#1220) - 2019: `await` was changed to require fewer ticks (tc39#1250)
- 2016: the Unicode change affected what was considered whitespace (tc39#300 / 24dad16) - 2017: the latest version of Unicode is mandated (tc39#620) - 2018: changed tagged template literal objects to be cached per source location rather than per realm (tc39#890) - 2019: Atomics.wake was renamed to Atomics.notify (tc39#1220) - 2019: `await` was changed to require fewer ticks (tc39#1250)
- 2016: the Unicode change affected what was considered whitespace (tc39#300 / 24dad16) - 2017: the latest version of Unicode is mandated (tc39#620) - 2018: changed tagged template literal objects to be cached per source location rather than per realm (tc39#890) - 2019: Atomics.wake was renamed to Atomics.notify (tc39#1220) - 2019: `await` was changed to require fewer ticks (tc39#1250)
…ns (tc39#1698) - 2016: the Unicode change affected what was considered whitespace (tc39#300 / 24dad16) - 2017: the latest version of Unicode is mandated (tc39#620) - 2018: changed tagged template literal objects to be cached per source location rather than per realm (tc39#890) - 2019: Atomics.wake was renamed to Atomics.notify (tc39#1220) - 2019: `await` was changed to require fewer ticks (tc39#1250)
…ns (tc39#1698) - 2016: the Unicode change affected what was considered whitespace (tc39#300 / 24dad16) - 2017: the latest version of Unicode is mandated (tc39#620) - 2018: changed tagged template literal objects to be cached per source location rather than per realm (tc39#890) - 2019: Atomics.wake was renamed to Atomics.notify (tc39#1220) - 2019: `await` was changed to require fewer ticks (tc39#1250)
…ns (tc39#1698) - 2016: the Unicode change affected what was considered whitespace (tc39#300 / 24dad16) - 2017: the latest version of Unicode is mandated (tc39#620) - 2018: changed tagged template literal objects to be cached per source location rather than per realm (tc39#890) - 2019: Atomics.wake was renamed to Atomics.notify (tc39#1220) - 2019: `await` was changed to require fewer ticks (tc39#1250)
…than by contents https://bugs.webkit.org/show_bug.cgi?id=182717 Reviewed by Yusuke Suzuki. tc39/ecma262#890 imposes a change to template literals, to allow template callsite arrays to be collected when the code containing the tagged template call is collected. This spec change has received concensus and been ratified. This change eliminates the eternal map associating template contents with arrays. JSTests: * stress/tagged-template-object-collect.js: Renamed from JSTests/stress/tagged-template-registry-key-collect.js. * stress/tagged-template-object.js: Renamed from JSTests/stress/tagged-template-registry-key.js. * stress/tagged-templates-identity.js: * stress/template-string-tags-eval.js: * test262.yaml: Source/JavaScriptCore: * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * Sources.txt: * bytecode/CodeBlock.cpp: (JSC::CodeBlock::setConstantRegisters): * bytecode/DirectEvalCodeCache.cpp: (JSC::DirectEvalCodeCache::setSlow): * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::allowDirectEvalCache const): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::addTemplateObjectConstant): (JSC::BytecodeGenerator::emitGetTemplateObject): (JSC::BytecodeGenerator::addTemplateRegistryKeyConstant): Deleted. * bytecompiler/BytecodeGenerator.h: * parser/Parser.cpp: (JSC::Parser<LexerType>::parseInner): (JSC::Parser<LexerType>::parseMemberExpression): * parser/Parser.h: * parser/ParserModes.h: * runtime/EvalExecutable.h: (JSC::EvalExecutable::allowDirectEvalCache const): * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::JSGlobalObject): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::templateRegistry): Deleted. * runtime/JSTemplateObjectDescriptor.cpp: Renamed from Source/JavaScriptCore/runtime/TemplateRegistry.cpp. (JSC::JSTemplateObjectDescriptor::JSTemplateObjectDescriptor): (JSC::JSTemplateObjectDescriptor::create): (JSC::JSTemplateObjectDescriptor::destroy): (JSC::JSTemplateObjectDescriptor::createTemplateObject): * runtime/JSTemplateObjectDescriptor.h: Renamed from Source/JavaScriptCore/runtime/JSTemplateRegistryKey.h. (JSC::isTemplateObjectDescriptor): * runtime/JSTemplateRegistryKey.cpp: Removed. * runtime/TemplateObjectDescriptor.cpp: Renamed from Source/JavaScriptCore/runtime/TemplateRegistryKey.cpp. (JSC::TemplateObjectDescriptor::~TemplateObjectDescriptor): * runtime/TemplateObjectDescriptor.h: Renamed from Source/JavaScriptCore/runtime/TemplateRegistryKey.h. (JSC::TemplateObjectDescriptor::operator== const): (JSC::TemplateObjectDescriptor::operator!= const): (JSC::TemplateObjectDescriptor::Hasher::hash): (JSC::TemplateObjectDescriptor::Hasher::equal): (JSC::TemplateObjectDescriptor::create): (JSC::TemplateObjectDescriptor::TemplateObjectDescriptor): (JSC::TemplateObjectDescriptor::calculateHash): * runtime/TemplateRegistry.h: Removed. * runtime/TemplateRegistryKeyTable.cpp: Removed. * runtime/TemplateRegistryKeyTable.h: Removed. * runtime/VM.cpp: (JSC::VM::VM): * runtime/VM.h: (JSC::VM::templateRegistryKeyTable): Deleted. * runtime/VMEntryScope.cpp: * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * Sources.txt: * bytecode/CodeBlock.cpp: (JSC::CodeBlock::setConstantRegisters): * bytecode/DirectEvalCodeCache.cpp: (JSC::DirectEvalCodeCache::setSlow): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::allowDirectEvalCache const): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::addTemplateObjectConstant): (JSC::BytecodeGenerator::emitGetTemplateObject): (JSC::BytecodeGenerator::addTemplateRegistryKeyConstant): Deleted. * bytecompiler/BytecodeGenerator.h: * parser/Parser.cpp: (JSC::Parser<LexerType>::parseInner): (JSC::Parser<LexerType>::parseMemberExpression): * parser/Parser.h: * parser/ParserModes.h: * runtime/EvalExecutable.h: (JSC::EvalExecutable::allowDirectEvalCache const): * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::JSGlobalObject): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::templateRegistry): Deleted. * runtime/JSTemplateObjectDescriptor.cpp: Renamed from Source/JavaScriptCore/runtime/TemplateRegistry.cpp. (JSC::JSTemplateObjectDescriptor::JSTemplateObjectDescriptor): (JSC::JSTemplateObjectDescriptor::create): (JSC::JSTemplateObjectDescriptor::destroy): (JSC::JSTemplateObjectDescriptor::createTemplateObject): * runtime/JSTemplateObjectDescriptor.h: Renamed from Source/JavaScriptCore/runtime/JSTemplateRegistryKey.h. (JSC::isTemplateObjectDescriptor): * runtime/JSTemplateRegistryKey.cpp: Removed. * runtime/TemplateObjectDescriptor.cpp: Renamed from Source/JavaScriptCore/runtime/TemplateRegistryKey.cpp. (JSC::TemplateObjectDescriptor::~TemplateObjectDescriptor): * runtime/TemplateObjectDescriptor.h: Renamed from Source/JavaScriptCore/runtime/TemplateRegistryKey.h. (JSC::TemplateObjectDescriptor::operator== const): (JSC::TemplateObjectDescriptor::operator!= const): (JSC::TemplateObjectDescriptor::Hasher::hash): (JSC::TemplateObjectDescriptor::Hasher::equal): (JSC::TemplateObjectDescriptor::create): (JSC::TemplateObjectDescriptor::TemplateObjectDescriptor): (JSC::TemplateObjectDescriptor::calculateHash): * runtime/TemplateRegistry.h: Removed. * runtime/TemplateRegistryKeyTable.cpp: Removed. * runtime/TemplateRegistryKeyTable.h: Removed. * runtime/VM.cpp: (JSC::VM::VM): * runtime/VM.h: (JSC::VM::templateRegistryKeyTable): Deleted. * runtime/VMEntryScope.cpp: * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * Sources.txt: * bytecode/CodeBlock.cpp: (JSC::CodeBlock::setConstantRegisters): * bytecode/DirectEvalCodeCache.cpp: (JSC::DirectEvalCodeCache::setSlow): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::allowDirectEvalCache const): * bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::addTemplateObjectConstant): (JSC::BytecodeGenerator::emitGetTemplateObject): (JSC::BytecodeGenerator::addTemplateRegistryKeyConstant): Deleted. * bytecompiler/BytecodeGenerator.h: * parser/Parser.cpp: (JSC::Parser<LexerType>::parseInner): (JSC::Parser<LexerType>::parseMemberExpression): * parser/Parser.h: * parser/ParserModes.h: * runtime/EvalExecutable.h: (JSC::EvalExecutable::allowDirectEvalCache const): * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::JSGlobalObject): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::templateRegistry): Deleted. * runtime/JSTemplateObjectDescriptor.cpp: Renamed from Source/JavaScriptCore/runtime/TemplateRegistry.cpp. (JSC::JSTemplateObjectDescriptor::JSTemplateObjectDescriptor): (JSC::JSTemplateObjectDescriptor::create): (JSC::JSTemplateObjectDescriptor::destroy): (JSC::JSTemplateObjectDescriptor::createTemplateObject): * runtime/JSTemplateObjectDescriptor.h: Renamed from Source/JavaScriptCore/runtime/JSTemplateRegistryKey.h. (JSC::isTemplateObjectDescriptor): * runtime/JSTemplateRegistryKey.cpp: Removed. * runtime/TemplateObjectDescriptor.cpp: Renamed from Source/JavaScriptCore/runtime/TemplateRegistryKey.cpp. (JSC::TemplateObjectDescriptor::~TemplateObjectDescriptor): * runtime/TemplateObjectDescriptor.h: Renamed from Source/JavaScriptCore/runtime/TemplateRegistryKey.h. (JSC::TemplateObjectDescriptor::operator== const): (JSC::TemplateObjectDescriptor::operator!= const): (JSC::TemplateObjectDescriptor::Hasher::hash): (JSC::TemplateObjectDescriptor::Hasher::equal): (JSC::TemplateObjectDescriptor::create): (JSC::TemplateObjectDescriptor::TemplateObjectDescriptor): (JSC::TemplateObjectDescriptor::calculateHash): * runtime/TemplateRegistry.h: Removed. * runtime/TemplateRegistryKeyTable.cpp: Removed. * runtime/TemplateRegistryKeyTable.h: Removed. * runtime/VM.cpp: (JSC::VM::VM): * runtime/VM.h: (JSC::VM::templateRegistryKeyTable): Deleted. * runtime/VMEntryScope.cpp:
The previous definition of template caching had a few issues:
in a WeakMap
implement any GC at all of template objects
to expose anything about the site, as it's site-independent
This patch makes template caching key off the Parse Node where the
template occurs in source, rather than the List of Strings that the
template evaluates into.
These semantics seem to match SpiderMonkey's implementation of templates.
V8, ChakraCore and JSC, on the other hand, implement the prior semantics.
Resolves #840
Edit: The version of SpiderMonkey I was running is two months old.