Index: src/parser-symbol-table.cc |
diff --git a/src/parser-symbol-table.cc b/src/parser-symbol-table.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e0e4a357ae1aabc1416475885cffd3570eb227c7 |
--- /dev/null |
+++ b/src/parser-symbol-table.cc |
@@ -0,0 +1,283 @@ |
+// Copyright 2014 the V8 project authors. All rights reserved. |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
+// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following |
+// disclaimer in the documentation and/or other materials provided |
+// with the distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived |
+// from this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+#include "parser-symbol-table.h" |
+ |
+#include "api.h" |
+#include "objects.h" |
+ |
+namespace v8 { |
+namespace internal { |
+ |
+namespace { |
+ |
+template <typename Char> |
+int vector_hash(Vector<const Char> string) { |
+ int hash = 0; |
+ for (int i = 0; i < string.length(); i++) { |
+ int c = static_cast<int>(string[i]); |
+ hash += c; |
+ hash += (hash << 10); |
+ hash ^= (hash >> 6); |
+ } |
+ return hash; |
+} |
+ |
+ |
+bool vector_compare(void* a, void* b) { |
+ ParserSymbolTable::Symbol* string1 = |
+ reinterpret_cast<ParserSymbolTable::Symbol*>(a); |
+ ParserSymbolTable::Symbol* string2 = |
+ reinterpret_cast<ParserSymbolTable::Symbol*>(b); |
+ if (string1->is_one_byte != string2->is_one_byte) return false; |
+ if (string1->hash != string2->hash) return false; |
ulan
2014/05/21 15:01:22
I think HashMap guarantees that the hashes are equ
marja
2014/05/21 17:16:45
Actually, not. Turns out this case is sometimes hi
|
+ int length = string1->literal_bytes.length(); |
+ if (string2->literal_bytes.length() != length) return false; |
+ return memcmp(string1->literal_bytes.start(), |
+ string2->literal_bytes.start(), length) == 0; |
+} |
+ |
+} |
+ |
+ |
+ParserSymbolTable::ParserSymbolTable() |
+ : literal_chars_(0), |
+ symbol_keys_(0), |
+ string_table_(vector_compare), |
+ isolate_(NULL) { |
+ { |
ulan
2014/05/21 15:01:22
How about second order macro for this? :)
|
+ const char* data = "(anonymous function)"; |
+ anonymous_function_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 20)); |
+ } |
+ { |
+ const char* data = "arguments"; |
+ arguments_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 9)); |
+ } |
+ { |
+ const char* data = ".for"; |
+ dot_for_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 4)); |
+ } |
+ { |
+ const char* data = ".iterator"; |
+ dot_iterator_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 9)); |
+ } |
+ { |
+ const char* data = ".module"; |
+ dot_module_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 7)); |
+ } |
+ { |
+ const char* data = ".result"; |
+ dot_result_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 7)); |
+ } |
+ { |
+ const char* data = ""; |
+ empty_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 0)); |
+ } |
+ { |
+ const char* data = "eval"; |
+ eval_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 4)); |
+ } |
+ { |
+ const char* data = "InitializeConstGlobal"; |
+ initialize_const_global_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 21)); |
+ } |
+ { |
+ const char* data = "InitializeVarGlobal"; |
+ initialize_var_global_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 19)); |
+ } |
+ { |
+ const char* data = "MakeReferenceError"; |
+ make_reference_error_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 18)); |
+ } |
+ { |
+ const char* data = "MakeSyntaxError"; |
+ make_syntax_error_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 15)); |
+ } |
+ { |
+ const char* data = "MakeTypeError"; |
+ make_type_error_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 13)); |
+ } |
+ { |
+ const char* data = "module"; |
+ module_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 6)); |
+ } |
+ { |
+ const char* data = "native"; |
+ native_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 6)); |
+ } |
+ { |
+ const char* data = "prototype"; |
+ prototype_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 9)); |
+ } |
+ { |
+ const char* data = "this"; |
+ this_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 4)); |
+ } |
+ { |
+ const char* data = "use strict"; |
+ use_strict_string_ = GetOneByteSymbol( |
+ Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), 10)); |
+ } |
+} |
+ |
+ |
+ParserSymbolTable::Symbol* ParserSymbolTable::GetOneByteSymbol( |
+ Vector<const uint8_t> literal) { |
+ return GetSymbol(vector_hash(literal), true, literal); |
+} |
+ |
+ |
+ParserSymbolTable::Symbol* ParserSymbolTable::GetTwoByteSymbol( |
+ Vector<const uint16_t> literal) { |
+ return GetSymbol(vector_hash(literal), false, |
+ Vector<const byte>::cast(literal)); |
+} |
+ |
+ |
+ParserSymbolTable::Symbol* ParserSymbolTable::GetSymbol( |
+ Handle<String> literal) { |
+ DisallowHeapAllocation no_gc; |
+ String::FlatContent content = literal->GetFlatContent(); |
+ if (content.IsAscii()) { |
+ return GetOneByteSymbol(content.ToOneByteVector()); |
+ } |
+ ASSERT(content.IsTwoByte()); |
+ return GetTwoByteSymbol(content.ToUC16Vector()); |
+} |
+ |
+ |
+bool ParserSymbolTable::SymbolMatches(Symbol* symbol, const char* data, |
+ int length) { |
+ if (symbol != NULL && symbol->is_one_byte && |
+ symbol->literal_bytes.length() == length) { |
+ const char* token = |
+ reinterpret_cast<const char*>(symbol->literal_bytes.start()); |
+ return !strncmp(token, data, length); |
+ } |
+ return false; |
+} |
+ |
+ |
+void ParserSymbolTable::Internalize(Isolate* isolate) { |
+ for (HashMap::Entry* p = string_table_.Start(); p != NULL; |
+ p = string_table_.Next(p)) { |
+ ParserSymbolTable::Symbol* symbol = |
+ reinterpret_cast<ParserSymbolTable::Symbol*>(p->key); |
+ Internalize(symbol, isolate); |
+ } |
+ // FIXME: can we free the backing store now? Maybe not. |
+ isolate_ = isolate; |
+} |
+ |
+ |
+bool ParserSymbolTable::IsArrayIndexSlow(Symbol* symbol, uint32_t* index) { |
+ ASSERT(symbol != NULL); |
+ if (!symbol->is_one_byte) return false; |
+ if (symbol->literal_bytes.length() == 0 || |
+ symbol->literal_bytes.length() > String::kMaxArrayIndexSize) |
+ return false; |
+ |
+ uint16_t ch = symbol->literal_bytes.at(0); |
+ // If the string begins with a '0' character, it must only consist |
+ // of it to be a legal array index. |
+ if (ch == '0') { |
+ if (index != NULL) *index = 0; |
+ return symbol->literal_bytes.length() == 1; |
+ } |
+ |
+ int d = ch - '0'; |
+ if (d < 0 || d > 9) return false; |
+ uint32_t result = d; |
+ for (int i = 1; i < symbol->literal_bytes.length(); ++i) { |
+ d = symbol->literal_bytes.at(i) - '0'; |
+ if (d < 0 || d > 9) return false; |
+ // Check that the new result is below the 32 bit limit. |
+ if (result > 429496729U - ((d > 5) ? 1 : 0)) return false; |
+ result = (result * 10) + d; |
+ } |
+ if (index != NULL) *index = result; |
+ return true; |
+} |
+ |
+ |
+ParserSymbolTable::Symbol* ParserSymbolTable::GetSymbol( |
+ int hash, bool is_one_byte, Vector<const byte> literal_bytes) { |
+ // literal_bytes here points to whatever the user passed, and this is OK |
+ // because we use vector_compare (which checks the contents) to compare |
+ // against the Symbols which are in the string_table_. We should not return |
+ // this Symbol. |
+ Symbol key(is_one_byte, literal_bytes, hash); |
+ HashMap::Entry* entry = string_table_.Lookup(&key, hash, true); |
+ if (entry->value == NULL) { |
+ // Copy literal contents for later comparison. |
+ key.literal_bytes = |
+ Vector<const byte>::cast(literal_chars_.AddBlock(literal_bytes)); |
+ // This Vector will be valid as long as the Collector is alive (meaning that |
+ // the Symbol will not be moved). |
+ Vector<Symbol> symbol = symbol_keys_.AddBlock(1, key); |
+ entry->key = &symbol[0]; |
+ if (isolate_) { |
+ Internalize(&symbol[0], isolate_); |
+ } |
+ entry->value = reinterpret_cast<void*>(1); |
+ } |
+ return reinterpret_cast<Symbol*>(entry->key); |
+} |
+ |
+ |
+void ParserSymbolTable::Internalize(ParserSymbolTable::Symbol* symbol, Isolate* isolate) { |
+ ASSERT(symbol != NULL); |
+ if (symbol->literal_bytes.length() == 0) { |
+ symbol->string_ = isolate->factory()->empty_string(); |
+ } |
+ else if (symbol->is_one_byte) { |
+ symbol->string_ = isolate->factory()->InternalizeOneByteString(symbol->literal_bytes); |
+ } else { |
+ symbol->string_ = isolate->factory()->InternalizeTwoByteString( |
+ Vector<const uint16_t>::cast(symbol->literal_bytes)); |
+ } |
+} |
+ |
+ |
+} } // namespace v8::internal |