Chromium Code Reviews| Index: src/parser.cc |
| diff --git a/src/parser.cc b/src/parser.cc |
| index f9fdf28ef19f7e3700bf44e1bc3b7583f8164462..c05f22b6c5ede8118f3802c95de1f87ed6951b87 100644 |
| --- a/src/parser.cc |
| +++ b/src/parser.cc |
| @@ -5214,7 +5214,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(); |
| @@ -5230,6 +5231,7 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, |
| factory()->NewArrayLiteral( |
| const_cast<ZoneList<Expression*>*>(raw_strings), raw_idx, pos), |
| zone()); |
| + args->Add(factory()->NewSmiLiteral(hash, pos), zone()); |
| this->CheckPossibleEvalCall(tag, scope_); |
| Expression* call_site = factory()->NewCallRuntime( |
| ast_value_factory()->get_template_callsite_string(), NULL, args, start); |
| @@ -5244,7 +5246,66 @@ Expression* Parser::CloseTemplateLiteral(TemplateLiteralState* state, int start, |
| } |
| -ZoneList<Expression*>* Parser::TemplateRawStrings(const TemplateLiteral* lit) { |
| +// MurmurHash (Public Domain) |
| +// TODO(caitp): use std::hash if available? |
| +static uint32_t MurmurHash(Vector<uint8_t> chars, int length) { |
| + // TODO(caitp): Do we want to seed this to improve randomness? I'm not sure |
| + // it matters. |
| + uint32_t hash = 0; |
| + |
| + Vector<const uint32_t> chunks = Vector<const uint32_t>::cast(chars); |
| + int num_chunks = chunks.length(); |
| + |
| + // MurmurHash magic numbers |
| + static const uint32_t c1 = 0xcc9e2d51; |
| + static const uint32_t c2 = 0x1b873593; |
| + static const uint32_t r1 = 15; |
| + static const uint32_t r2 = 13; |
| + static const uint32_t m = 5; |
| + static const uint32_t n = 0xe6546b64; |
| + static const uint32_t f1 = 0x85ebca6b; |
| + static const uint32_t f2 = 0xc2b2ae35; |
| + |
| + for (int i = 0; i < num_chunks; ++i) { |
| + uint32_t k = chunks[i]; |
| + |
| + k *= c1; |
| + k = (k << r1) | (k >> (32 - r1)); |
| + k *= c2; |
| + |
| + hash ^= k; |
| + hash = ((hash << r2) | (hash >> (32 - r2))) * m + n; |
| + } |
| + |
| + const uint8_t *tail = chars.start() + num_chunks * 4; |
| + uint32_t k1 = 0; |
| + |
| + switch (length & 3) { |
| + case 3: |
| + k1 ^= tail[2] << 16; |
| + case 2: |
| + k1 ^= tail[1] << 8; |
| + case 1: |
| + k1 ^= tail[0]; |
| + k1 *= c1; |
| + k1 = (k1 << r1) | (k1 >> (32 - r1)); |
| + k1 *= c2; |
| + hash ^= k1; |
| + } |
| + |
| + hash ^= length; |
| + hash ^= (hash >> 16); |
| + hash *= f1; |
| + hash ^= (hash >> 13); |
| + hash *= f2; |
| + hash ^= (hash >> 16); |
| + |
| + return hash; |
| +} |
| + |
| + |
| +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(); |
| @@ -5264,12 +5325,27 @@ ZoneList<Expression*>* Parser::TemplateRawStrings(const TemplateLiteral* lit) { |
| raw_strings = new (zone()) ZoneList<Expression*>(total, zone()); |
| + int num_dummy_chars = (total - 1) * 4; |
| + for (int index = 0; index < total; ++index) { |
| + num_dummy_chars += lengths->at(index); |
| + } |
| + |
| + Vector<uint8_t> hash_string = Vector<uint8_t>::New(num_dummy_chars); |
|
arv (Not doing code reviews)
2014/11/19 06:09:11
What about two byte strings?
Can we use StringHas
caitp (gmail)
2014/11/19 07:15:05
String::ToCString claims to return a UTF8 represen
|
| + num_dummy_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_dummy_chars++] = '$'; |
| + hash_string[num_dummy_chars++] = '{'; |
| + hash_string[num_dummy_chars++] = '.'; |
| + hash_string[num_dummy_chars++] = '}'; |
| + } |
| + |
| SmartArrayPointer<char> raw_chars = |
| source->ToCString(ALLOW_NULLS, FAST_STRING_TRAVERSAL, span_start, |
| span_end, &length); |
| @@ -5284,6 +5360,7 @@ ZoneList<Expression*>* Parser::TemplateRawStrings(const TemplateLiteral* lit) { |
| ++from_index; |
| } |
| } |
| + hash_string[num_dummy_chars++] = ch; |
| raw_chars[to_index++] = ch; |
| } |
| @@ -5293,6 +5370,9 @@ ZoneList<Expression*>* Parser::TemplateRawStrings(const TemplateLiteral* lit) { |
| raw_strings->Add(raw_lit, zone()); |
| } |
| + *hash = MurmurHash(hash_string, num_dummy_chars); |
| + hash_string.Dispose(); |
| + |
| return raw_strings; |
| } |
| } } // namespace v8::internal |