V8EXPORT int Utf8Length() const;
/**
+ * Returns the hash of this string.
+ */
+ V8EXPORT uint32_t Hash() const;
+
+ struct CompleteHashData {
+ CompleteHashData() : length(0), hash(0), symbol_id(0) {}
+ int length;
+ uint32_t hash;
+ uint32_t symbol_id;
+ };
+
+ /**
+ * Returns the "complete" hash of the string. This is
+ * all the information about the string needed to implement
+ * a very efficient hash keyed on the string.
+ *
+ * The members of CompleteHashData are:
+ * length: The length of the string. Equivalent to Length()
+ * hash: The hash of the string. Equivalent to Hash()
+ * symbol_id: If the string is a sequential symbol, the symbol
+ * id, otherwise 0. If the symbol ids of two strings are
+ * the same (and non-zero) the two strings are identical.
+ * If the symbol ids are different the strings may still be
+ * identical, but an Equals() check must be performed.
+ */
+ V8EXPORT CompleteHashData CompleteHash() const;
+
+ /**
+ * Compute a hash value for the passed UTF16 string
+ * data.
+ */
+ V8EXPORT static uint32_t ComputeHash(uint16_t *string, int length);
+ V8EXPORT static uint32_t ComputeHash(char *string, int length);
+
+ /**
+ * Returns true if this string is equal to the external
+ * string data provided.
+ */
+ V8EXPORT bool Equals(uint16_t *string, int length);
+ V8EXPORT bool Equals(char *string, int length);
+ inline bool Equals(Handle<Value> that) const { return v8::Value::Equals(that); }
+
+ /**
* Write the contents of the string to an external buffer.
* If no arguments are given, expects the buffer to be large
* enough to hold the entire string and NULL terminator. Copies
NO_NULL_TERMINATION = 2
};
+ V8EXPORT uint16_t GetCharacter(int index);
+
// 16-bit character codes.
V8EXPORT int Write(uint16_t* buffer,
int start = 0,
}
+uint32_t String::Hash() const {
+ i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0;
+ return str->Hash();
+}
+
+
+String::CompleteHashData String::CompleteHash() const {
+ i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::CompleteHash()")) return CompleteHashData();
+ CompleteHashData result;
+ result.length = str->length();
+ result.hash = str->Hash();
+ if (str->IsSeqString())
+ result.symbol_id = i::SeqString::cast(*str)->symbol_id();
+ return result;
+}
+
+
+uint32_t String::ComputeHash(uint16_t *string, int length) {
+ return i::HashSequentialString<i::uc16>(string, length) >> i::String::kHashShift;
+}
+
+
+uint32_t String::ComputeHash(char *string, int length) {
+ return i::HashSequentialString<char>(string, length) >> i::String::kHashShift;
+}
+
+
+uint16_t String::GetCharacter(int index)
+{
+ i::Handle<i::String> str = Utils::OpenHandle(this);
+ return str->Get(index);
+}
+
+
+bool String::Equals(uint16_t *string, int length) {
+ i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0;
+ return str->SlowEqualsExternal(string, length);
+}
+
+
+bool String::Equals(char *string, int length)
+{
+ i::Handle<i::String> str = Utils::OpenHandle(this);
+ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0;
+ return str->SlowEqualsExternal(string, length);
+}
+
+
int String::WriteUtf8(char* buffer,
int capacity,
int* nchars_ref,
String* answer = String::cast(result);
answer->set_length(str.length());
answer->set_hash_field(hash_field);
+ SeqString::cast(answer)->set_symbol_id(0);
ASSERT_EQ(size, answer->Size());
String* answer = String::cast(result);
answer->set_length(str.length());
answer->set_hash_field(hash_field);
+ SeqString::cast(answer)->set_symbol_id(0);
ASSERT_EQ(size, answer->Size());
String* answer = String::cast(result);
answer->set_length(chars);
answer->set_hash_field(hash_field);
+ SeqString::cast(answer)->set_symbol_id(0);
ASSERT_EQ(size, answer->Size());
HeapObject::cast(result)->set_map(ascii_string_map());
String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField);
+ SeqString::cast(result)->set_symbol_id(0);
ASSERT_EQ(size, HeapObject::cast(result)->Size());
return result;
}
HeapObject::cast(result)->set_map(string_map());
String::cast(result)->set_length(length);
String::cast(result)->set_hash_field(String::kEmptyHashField);
+ SeqString::cast(result)->set_symbol_id(0);
ASSERT_EQ(size, HeapObject::cast(result)->Size());
return result;
}
SMI_ACCESSORS(FreeSpace, size, kSizeOffset)
SMI_ACCESSORS(String, length, kLengthOffset)
+SMI_ACCESSORS(SeqString, symbol_id, kSymbolIdOffset)
uint32_t String::hash_field() {
}
+bool String::SlowEqualsExternal(uc16 *string, int length) {
+ int len = this->length();
+ if (len != length) return false;
+ if (len == 0) return true;
+
+ // We know the strings are both non-empty. Compare the first chars
+ // before we try to flatten the strings.
+ if (this->Get(0) != string[0]) return false;
+
+ String* lhs = this->TryFlattenGetString();
+
+ if (lhs->IsFlat()) {
+ String::FlatContent lhs_content = lhs->GetFlatContent();
+ if (lhs->IsAsciiRepresentation()) {
+ Vector<const char> vec1 = lhs_content.ToAsciiVector();
+ VectorIterator<char> buf1(vec1);
+ VectorIterator<uc16> ib(string, length);
+ return CompareStringContents(&buf1, &ib);
+ } else {
+ Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
+ Vector<const uc16> vec2(string, length);
+ return CompareRawStringContents(vec1, vec2);
+ }
+ } else {
+ Isolate* isolate = GetIsolate();
+ isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
+ VectorIterator<uc16> ib(string, length);
+ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib);
+ }
+}
+
+
+bool String::SlowEqualsExternal(char *string, int length)
+{
+ int len = this->length();
+ if (len != length) return false;
+ if (len == 0) return true;
+
+ // We know the strings are both non-empty. Compare the first chars
+ // before we try to flatten the strings.
+ if (this->Get(0) != string[0]) return false;
+
+ String* lhs = this->TryFlattenGetString();
+
+ if (StringShape(lhs).IsSequentialAscii()) {
+ const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
+ return CompareRawStringContents(Vector<const char>(str1, len),
+ Vector<const char>(string, len));
+ }
+
+ if (lhs->IsFlat()) {
+ String::FlatContent lhs_content = lhs->GetFlatContent();
+ Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
+ VectorIterator<const uc16> buf1(vec1);
+ VectorIterator<char> buf2(string, length);
+ return CompareStringContents(&buf1, &buf2);
+ } else {
+ Isolate* isolate = GetIsolate();
+ isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
+ VectorIterator<char> ib(string, length);
+ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib);
+ }
+}
+
+
bool String::SlowEquals(String* other) {
// Fast check: negative check with lengths.
int len = length();
MaybeObject* AsObject() {
if (hash_field_ == 0) Hash();
- return HEAP->AllocateAsciiSymbol(string_, hash_field_);
+ MaybeObject *result = HEAP->AllocateAsciiSymbol(string_, hash_field_);
+ if (!result->IsFailure() && result->ToObjectUnchecked()->IsSeqString()) {
+ while (true) {
+ Atomic32 my_symbol_id = next_symbol_id;
+ if (my_symbol_id > Smi::kMaxValue)
+ break;
+ if (my_symbol_id == NoBarrier_CompareAndSwap(&next_symbol_id, my_symbol_id, my_symbol_id + 1)) {
+ SeqString::cast(result->ToObjectUnchecked())->set_symbol_id(my_symbol_id);
+ break;
+ }
+ }
+ }
+ return result;
}
+
+ static Atomic32 next_symbol_id;
};
+Atomic32 AsciiSymbolKey::next_symbol_id = 1;
class SubStringAsciiSymbolKey : public HashTableKey {
bool IsAsciiEqualTo(Vector<const char> str);
bool IsTwoByteEqualTo(Vector<const uc16> str);
+ bool SlowEqualsExternal(uc16 *string, int length);
+ bool SlowEqualsExternal(char *string, int length);
+
// Return a UTF8 representation of the string. The string is null
// terminated but may optionally contain nulls. Length is returned
// in length_output if length_output is not a null pointer The string
// Casting.
static inline SeqString* cast(Object* obj);
+ // Get and set the symbol id of the string
+ inline int symbol_id();
+ inline void set_symbol_id(int value);
+
// Layout description.
- static const int kHeaderSize = String::kSize;
+ static const int kSymbolIdOffset = String::kSize;
+ static const int kHeaderSize = kSymbolIdOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString);