Commit ad86a1a2 authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

Cache template literal callSiteObj

BUG=v8:3230
LOG=y

Review URL: https://codereview.chromium.org/742643003

Cr-Commit-Position: refs/heads/master@{#25450}
parent 4d48e1b7
......@@ -4,13 +4,59 @@
'use strict';
function GetTemplateCallSite(siteObj, rawStrings) {
// TODO(caitp): ensure same template callsite is used for subsequent tag calls
var callSiteCache = new $Map;
function SameCallSiteElements(rawStrings, other) {
var length = rawStrings.length;
var other = other.raw;
if (length !== other.length) return false;
for (var i = 0; i < length; ++i) {
if (rawStrings[i] !== other[i]) return false;
}
return true;
}
function GetCachedCallSite(siteObj, hash) {
var obj = %MapGet(callSiteCache, hash);
if (IS_UNDEFINED(obj)) return;
var length = obj.length;
for (var i = 0; i < length; ++i) {
if (SameCallSiteElements(siteObj, obj[i])) return obj[i];
}
}
function SetCachedCallSite(siteObj, hash) {
var obj = %MapGet(callSiteCache, hash);
var array;
if (IS_UNDEFINED(obj)) {
array = new InternalArray(1);
array[0] = siteObj;
%MapSet(callSiteCache, hash, array);
} else {
obj.push(siteObj);
}
return siteObj;
}
function GetTemplateCallSite(siteObj, rawStrings, hash) {
var cached = GetCachedCallSite(rawStrings, hash);
if (!IS_UNDEFINED(cached)) return cached;
%AddNamedProperty(siteObj, "raw", %ObjectFreeze(rawStrings),
READ_ONLY | DONT_ENUM | DONT_DELETE);
return %ObjectFreeze(siteObj);
return SetCachedCallSite(%ObjectFreeze(siteObj), hash);
}
......
......@@ -5240,7 +5240,8 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
}
return expr;
} else {
ZoneList<Expression*>* raw_strings = TemplateRawStrings(lit);
uint32_t hash;
ZoneList<Expression*>* raw_strings = TemplateRawStrings(lit, &hash);
Handle<String> source(String::cast(script()->source()));
int cooked_idx = function_state_->NextMaterializedLiteralIndex();
......@@ -5256,6 +5257,11 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
factory()->NewArrayLiteral(
const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx, pos),
zone());
// Ensure hash is suitable as an Smi value
Smi* hash_obj = Smi::cast(Internals::IntToSmi(static_cast<int>(hash)));
args->Add(factory()->NewSmiLiteral(hash_obj->value(), pos), zone());
this->CheckPossibleEvalCall(tag, scope_);
Expression* call_site = factory()->NewCallRuntime(
ast_value_factory()->get_template_callsite_string(), NULL, args, start);
......@@ -5270,7 +5276,8 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start,
}
ZoneList<Expression*>* Parser::TemplateRawStrings(const TemplateLiteral* lit) {
ZoneList<Expression*>* Parser::TemplateRawStrings(const TemplateLiteral* lit,
uint32_t* hash) {
const ZoneList<int>* lengths = lit->lengths();
const ZoneList<Expression*>* cooked_strings = lit->cooked();
int total = lengths->length();
......@@ -5290,12 +5297,27 @@ ZoneList<Expression*>* Parser::TemplateRawStrings(const TemplateLiteral* lit) {
raw_strings = new (zone()) ZoneList<Expression*>(total, zone());
int num_hash_chars = (total - 1) * 3;
for (int index = 0; index < total; ++index) {
// Allow about length * 4 to handle most UTF8 sequences.
num_hash_chars += lengths->at(index) * 4;
}
Vector<uint8_t> hash_string = Vector<uint8_t>::New(num_hash_chars);
num_hash_chars = 0;
for (int index = 0; index < total; ++index) {
int span_start = cooked_strings->at(index)->position() + 1;
int span_end = lengths->at(index) - 1;
int length;
int to_index = 0;
if (index) {
hash_string[num_hash_chars++] = '$';
hash_string[num_hash_chars++] = '{';
hash_string[num_hash_chars++] = '}';
}
SmartArrayPointer<char> raw_chars =
source->ToCString(ALLOW_NULLS, FAST_STRING_TRAVERSAL, span_start,
span_end, &length);
......@@ -5310,6 +5332,7 @@ ZoneList<Expression*>* Parser::TemplateRawStrings(const TemplateLiteral* lit) {
++from_index;
}
}
hash_string[num_hash_chars++] = ch;
raw_chars[to_index++] = ch;
}
......@@ -5319,6 +5342,12 @@ ZoneList<Expression*>* Parser::TemplateRawStrings(const TemplateLiteral* lit) {
raw_strings->Add(raw_lit, zone());
}
hash_string.Truncate(num_hash_chars);
int utf16_length;
*hash = StringHasher::ComputeUtf8Hash(Vector<const char>::cast(hash_string),
num_hash_chars, &utf16_length);
hash_string.Dispose();
return raw_strings;
}
} } // namespace v8::internal
......@@ -884,7 +884,8 @@ class Parser : public ParserBase<ParserTraits> {
Expression* expression);
Expression* CloseTemplateLiteral(TemplateLiteralState* state, int start,
Expression* tag);
ZoneList<Expression*>* TemplateRawStrings(const TemplateLiteral* lit);
ZoneList<Expression*>* TemplateRawStrings(const TemplateLiteral* lit,
uint32_t* hash);
Scanner scanner_;
PreParser* reusable_preparser_;
Scope* original_scope_; // for ES5 function declarations in sloppy eval
......
......@@ -338,6 +338,75 @@ var obj = {
})();
(function testCallSiteCaching() {
var callSites = [];
function tag(cs) { callSites.push(cs); }
var a = 1;
var b = 2;
tag`head${a}tail`;
tag`head${b}tail`;
assertEquals(2, callSites.length);
assertSame(callSites[0], callSites[1]);
eval("tag`head${a}tail`");
assertEquals(3, callSites.length);
assertSame(callSites[1], callSites[2]);
eval("tag`head${b}tail`");
assertEquals(4, callSites.length);
assertSame(callSites[2], callSites[3]);
(new Function("tag", "a", "b", "return tag`head${a}tail`;"))(tag, 1, 2);
assertEquals(5, callSites.length);
assertSame(callSites[3], callSites[4]);
(new Function("tag", "a", "b", "return tag`head${b}tail`;"))(tag, 1, 2);
assertEquals(6, callSites.length);
assertSame(callSites[4], callSites[5]);
callSites = [];
tag`foo${a}bar`;
tag`foo\${.}bar`;
assertEquals(2, callSites.length);
assertEquals(2, callSites[0].length);
assertEquals(1, callSites[1].length);
callSites = [];
eval("tag`\\\r\n\\\n\\\r`");
eval("tag`\\\r\n\\\n\\\r`");
assertEquals(2, callSites.length);
assertSame(callSites[0], callSites[1]);
assertEquals("", callSites[0][0]);
assertEquals("\\\n\\\n\\\n", callSites[0].raw[0]);
callSites = [];
tag`\uc548\ub155`;
tag`\uc548\ub155`;
assertEquals(2, callSites.length);
assertSame(callSites[0], callSites[1]);
assertEquals("안녕", callSites[0][0]);
assertEquals("\\uc548\\ub155", callSites[0].raw[0]);
callSites = [];
tag`\uc548\ub155`;
tag`안녕`;
assertEquals(2, callSites.length);
assertTrue(callSites[0] !== callSites[1]);
assertEquals("안녕", callSites[0][0]);
assertEquals("\\uc548\\ub155", callSites[0].raw[0]);
assertEquals("안녕", callSites[1][0]);
// TODO(caitp, arv): blocked on correctly generating raw strings from
// multi-byte UTF8.
// assertEquals("안녕", callSites[1].raw[0]);
})();
(function testExtendedArrayPrototype() {
Object.defineProperty(Array.prototype, 0, {
set: function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment