From: yangguo@chromium.org Date: Tue, 4 Sep 2012 12:23:22 +0000 (+0000) Subject: Revert r12430, r12432, r12433 (basic support for Latin1). X-Git-Tag: upstream/4.7.83~16051 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5ac2a5d22e6426dd7b887adca131a822679a2842;p=platform%2Fupstream%2Fv8.git Revert r12430, r12432, r12433 (basic support for Latin1). BUG= Review URL: https://chromiumcodereview.appspot.com/10905075 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12438 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/include/v8.h b/include/v8.h index 42aaabf..3e1b427 100644 --- a/include/v8.h +++ b/include/v8.h @@ -1069,48 +1069,19 @@ class String : public Primitive { PRESERVE_ASCII_NULL = 4 }; - - enum StringEncoding { - INVALID_ENCODING = 0, - UTF_8_ENCODING = 1, - LATIN1_ENCODING = 2, - UTF_16_ENCODING = 3, - - ASCII_HINT = 1 << 16, - NOT_ASCII_HINT = 1 << 17 - }; - - static const int kStringEncodingMask = 3; - static const int kAsciiHintMask = String::ASCII_HINT | String::NOT_ASCII_HINT; - - static const int kUndefinedLength = -1; - - - // 16-bit UTF16 code units. PRESERVE_ASCII_NULL is not supported as option, - // null-characters are never converted to spaces. + // 16-bit character codes. V8EXPORT int Write(uint16_t* buffer, int start = 0, - int length = kUndefinedLength, + int length = -1, int options = NO_OPTIONS) const; - - // ASCII characters. Null-characters are converted to spaces unless - // PRESERVE_ASCII_NULL is set as option. + // ASCII characters. V8EXPORT int WriteAscii(char* buffer, int start = 0, - int length = kUndefinedLength, + int length = -1, int options = NO_OPTIONS) const; - - // Latin1 characters. PRESERVE_ASCII_NULL is not supported as option, - // null-characters are never converted to spaces. - V8EXPORT int WriteLatin1(char* buffer, - int start = 0, - int length = kUndefinedLength, - int options = NO_OPTIONS) const; - - // UTF-8 encoded characters. PRESERVE_ASCII_NULL is not supported as option, - // null-characters are never converted to spaces. + // UTF-8 encoded characters. V8EXPORT int WriteUtf8(char* buffer, - int length = kUndefinedLength, + int length = -1, int* nchars_ref = NULL, int options = NO_OPTIONS) const; @@ -1151,7 +1122,6 @@ class String : public Primitive { void operator=(const ExternalStringResourceBase&); friend class v8::internal::Heap; - friend class v8::String; }; /** @@ -1211,16 +1181,6 @@ class String : public Primitive { }; /** - * An ExternalLatin1StringResource is a wrapper around an Latin1-encoded - * string buffer that resides outside V8's heap. For usage in V8, a Latin1 - * string is converted to ASCII or two-byte string depending on whether - * it contains non-ASCII characters. - */ - class V8EXPORT ExternalLatin1StringResource - : public ExternalAsciiStringResource { - }; - - /** * Get the ExternalStringResource for an external string. Returns * NULL if IsExternal() doesn't return true. */ @@ -1233,44 +1193,24 @@ class String : public Primitive { V8EXPORT const ExternalAsciiStringResource* GetExternalAsciiStringResource() const; - /** - * If the string is external, return its encoding (Latin1 or UTF16) - * and possibly a hint on whether the content is ASCII. - * Return String::INVALID_ENCODING otherwise. - */ - inline int GetExternalStringEncoding() const; - - - /** - * Return the resource of the external string regardless of encoding. - * Call this only after having made sure that the string is indeed external! - */ - inline ExternalStringResourceBase* GetExternalStringResourceBase() const; - static inline String* Cast(v8::Value* obj); /** - * Allocates a new string from either UTF-8 or Latin1-encoded data. - * The second parameter 'length' gives the buffer length. If the data may - * contain zero bytes, the caller must be careful to supply the length - * parameter. If it is not given, the function calls 'strlen' to determine - * the buffer length, it might be wrong if 'data' contains a null character. - * The third parameter specifies the encoding, which may include an hint - * whether the string contains ASCII characters. In the case of Latin1, the - * appropriate internal representation (UTF16 or ASCII) is chosen. + * Allocates a new string from either UTF-8 encoded or ASCII data. + * The second parameter 'length' gives the buffer length. + * If the data is UTF-8 encoded, the caller must + * be careful to supply the length parameter. + * If it is not given, the function calls + * 'strlen' to determine the buffer length, it might be + * wrong if 'data' contains a null character. */ - V8EXPORT static Local New(const char* data, - int length = kUndefinedLength, - int encoding = UTF_8_ENCODING); + V8EXPORT static Local New(const char* data, int length = -1); - /** Allocates a new string from 16-bit UTF-16 code units.*/ - V8EXPORT static Local New(const uint16_t* data, - int length = kUndefinedLength); + /** Allocates a new string from 16-bit character codes.*/ + V8EXPORT static Local New(const uint16_t* data, int length = -1); /** Creates a symbol. Returns one if it exists already.*/ - V8EXPORT static Local NewSymbol(const char* data, - int length = kUndefinedLength, - int encoding = UTF_8_ENCODING); + V8EXPORT static Local NewSymbol(const char* data, int length = -1); /** * Creates a new string by concatenating the left and the right strings @@ -1307,8 +1247,7 @@ class String : public Primitive { * this function should not otherwise delete or modify the resource. Neither * should the underlying buffer be deallocated or modified except through the * destructor of the external string resource. - */ - V8EXPORT static Local NewExternal( + */ V8EXPORT static Local NewExternal( ExternalAsciiStringResource* resource); /** @@ -1322,24 +1261,6 @@ class String : public Primitive { */ V8EXPORT bool MakeExternal(ExternalAsciiStringResource* resource); - - /** - * Creates a new external string using the Latin1-encoded data defined in the - * given resource. When the external string is no longer live on V8's heap - * the resource will be disposed by calling its Dispose method. The caller of - * this function should not otherwise delete or modify the resource. Neither - * should the underlying buffer be deallocated or modified except through the - * destructor of the external string resource. - * If the data contains a non-ASCII character, the string is created as a new - * string object on the V8 heap and the Dispose method is called on the - * resource immediately. This is because V8 is unable to handle non-ASCII - * Latin1-encoded strings internally. - */ - V8EXPORT static Local NewExternal( - ExternalLatin1StringResource* resource, - int encoding = String::LATIN1_ENCODING); - - /** * Returns true if this string can be made external. */ @@ -1347,13 +1268,11 @@ class String : public Primitive { /** Creates an undetectable string from the supplied ASCII or UTF-8 data.*/ V8EXPORT static Local NewUndetectable(const char* data, - int length = kUndefinedLength, - int encoding = UTF_8_ENCODING); + int length = -1); - /** Creates an undetectable string from the supplied 16-bit UTF16 code units. - */ + /** Creates an undetectable string from the supplied 16-bit character codes.*/ V8EXPORT static Local NewUndetectable(const uint16_t* data, - int length = kUndefinedLength); + int length = -1); /** * Converts an object to a UTF-8-encoded character array. Useful if @@ -1424,9 +1343,7 @@ class String : public Primitive { }; private: - V8EXPORT void VerifyExternalStringEncoding(int encoding) const; - V8EXPORT void VerifyExternalStringResourceBase( - ExternalStringResourceBase* val) const; + V8EXPORT void VerifyExternalStringResource(ExternalStringResource* val) const; V8EXPORT static void CheckCast(v8::Value* obj); }; @@ -4117,9 +4034,6 @@ class Internals { static const int kJSObjectHeaderSize = 3 * kApiPointerSize; static const int kFullStringRepresentationMask = 0x07; static const int kExternalTwoByteRepresentationTag = 0x02; - static const int kExternalAsciiRepresentationTag = 0x06; - static const int kExternalAsciiDataHintMask = 0x08; - static const int kExternalAsciiDataHintTag = 0x08; static const int kIsolateStateOffset = 0; static const int kIsolateEmbedderDataOffset = 1 * kApiPointerSize; @@ -4177,6 +4091,11 @@ class Internals { } } + static inline bool IsExternalTwoByteString(int instance_type) { + int representation = (instance_type & kFullStringRepresentationMask); + return representation == kExternalTwoByteRepresentationTag; + } + static inline bool IsInitialized(v8::Isolate* isolate) { uint8_t* addr = reinterpret_cast(isolate) + kIsolateStateOffset; return *reinterpret_cast(addr) == 1; @@ -4454,56 +4373,16 @@ Local String::Empty(Isolate* isolate) { String::ExternalStringResource* String::GetExternalStringResource() const { typedef internal::Object O; typedef internal::Internals I; - String::ExternalStringResource* result = NULL; O* obj = *reinterpret_cast(const_cast(this)); - if ((I::GetInstanceType(obj) & I::kFullStringRepresentationMask) == - I::kExternalTwoByteRepresentationTag) { - result = reinterpret_cast( - GetExternalStringResourceBase()); - } - return result; -} - - -int String::GetExternalStringEncoding() const { - typedef internal::Object O; - typedef internal::Internals I; - O* obj = *reinterpret_cast(const_cast(this)); - static const int kRepresentationAndHintMask = - I::kFullStringRepresentationMask | I::kExternalAsciiDataHintMask; - - int encoding; - switch (I::GetInstanceType(obj) & kRepresentationAndHintMask) { - case I::kExternalTwoByteRepresentationTag | I::kExternalAsciiDataHintTag: - encoding = UTF_16_ENCODING | ASCII_HINT; - break; - case I::kExternalTwoByteRepresentationTag: - encoding = UTF_16_ENCODING | NOT_ASCII_HINT; - break; - case I::kExternalAsciiRepresentationTag: - encoding = LATIN1_ENCODING | ASCII_HINT; - break; - default: - encoding = INVALID_ENCODING; - break; + String::ExternalStringResource* result; + if (I::IsExternalTwoByteString(I::GetInstanceType(obj))) { + void* value = I::ReadField(obj, I::kStringResourceOffset); + result = reinterpret_cast(value); + } else { + result = NULL; } #ifdef V8_ENABLE_CHECKS - VerifyExternalStringEncoding(encoding); -#endif - return encoding; -} - - -String::ExternalStringResourceBase* String::GetExternalStringResourceBase() - const { - typedef internal::Object O; - typedef internal::Internals I; - O* obj = *reinterpret_cast(const_cast(this)); - void* value = I::ReadField(obj, I::kStringResourceOffset); - ExternalStringResourceBase* result = - reinterpret_cast(value); -#ifdef V8_ENABLE_CHECKS - VerifyExternalStringResourceBase(result); + VerifyExternalStringResource(result); #endif return result; } diff --git a/src/api.cc b/src/api.cc index bbed610..65b544c 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3857,7 +3857,7 @@ int String::WriteUtf8(char* buffer, int string_length = str->length(); if (str->IsAsciiRepresentation()) { int len; - if (capacity == kUndefinedLength) { + if (capacity == -1) { capacity = str->length() + 1; len = string_length; } else { @@ -3872,7 +3872,7 @@ int String::WriteUtf8(char* buffer, return len; } - if (capacity == kUndefinedLength || capacity / 3 >= string_length) { + if (capacity == -1 || capacity / 3 >= string_length) { int32_t previous = unibrow::Utf16::kNoPreviousCharacter; const int kMaxRecursion = 100; int utf8_bytes = @@ -3903,7 +3903,7 @@ int String::WriteUtf8(char* buffer, int utf8_bytes = i::Utf8Length(str); if ((options & NO_NULL_TERMINATION) == 0) utf8_bytes++; if (utf8_bytes <= capacity) { - return WriteUtf8(buffer, kUndefinedLength, nchars_ref, options); + return WriteUtf8(buffer, -1, nchars_ref, options); } } @@ -3921,9 +3921,7 @@ int String::WriteUtf8(char* buffer, int pos = 0; int nchars = 0; int previous = unibrow::Utf16::kNoPreviousCharacter; - for (i = 0; - i < len && (capacity == kUndefinedLength || pos < fast_end); - i++) { + for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) { i::uc32 c = write_input_buffer.GetNext(); int written = unibrow::Utf8::Encode(buffer + pos, c, previous); pos += written; @@ -3969,7 +3967,7 @@ int String::WriteUtf8(char* buffer, } if (nchars_ref != NULL) *nchars_ref = nchars; if (!(options & NO_NULL_TERMINATION) && - (i == len && (capacity == kUndefinedLength || pos < capacity))) { + (i == len && (capacity == -1 || pos < capacity))) { buffer[pos++] = '\0'; } return pos; @@ -3984,7 +3982,7 @@ int String::WriteAscii(char* buffer, if (IsDeadCheck(isolate, "v8::String::WriteAscii()")) return 0; LOG_API(isolate, "String::WriteAscii"); ENTER_V8(isolate); - ASSERT(start >= 0 && length >= kUndefinedLength); + ASSERT(start >= 0 && length >= -1); i::Handle str = Utils::OpenHandle(this); isolate->string_tracker()->RecordWrite(str); if (options & HINT_MANY_WRITES_EXPECTED) { @@ -3993,7 +3991,7 @@ int String::WriteAscii(char* buffer, if (str->IsAsciiRepresentation()) { // WriteToFlat is faster than using the StringInputBuffer. - if (length == kUndefinedLength) length = str->length() + 1; + if (length == -1) length = str->length() + 1; int len = i::Min(length, str->length() - start); i::String::WriteToFlat(*str, buffer, start, start + len); if (!(options & PRESERVE_ASCII_NULL)) { @@ -4009,7 +4007,7 @@ int String::WriteAscii(char* buffer, i::StringInputBuffer& write_input_buffer = *isolate->write_input_buffer(); int end = length; - if ((length == kUndefinedLength) || (length > str->length() - start)) { + if ((length == -1) || (length > str->length() - start)) { end = str->length() - start; } if (end < 0) return 0; @@ -4027,31 +4025,6 @@ int String::WriteAscii(char* buffer, } -int String::WriteLatin1(char* buffer, - int start, - int length, - int options) const { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - if (IsDeadCheck(isolate, "v8::String::WriteLatin1()")) return 0; - LOG_API(isolate, "String::WriteLatin1"); - ENTER_V8(isolate); - ASSERT(start >= 0 && length >= kUndefinedLength); - i::Handle str = Utils::OpenHandle(this); - isolate->string_tracker()->RecordWrite(str); - if (options & HINT_MANY_WRITES_EXPECTED) { - FlattenString(str); // Flatten the string for efficiency. - } - - if (length == kUndefinedLength) length = str->length() + 1; - int len = i::Min(length, str->length() - start); - i::String::WriteToFlat(*str, buffer, start, start + len); - if (!(options & NO_NULL_TERMINATION) && length > len) { - buffer[len] = '\0'; - } - return len; -} - - int String::Write(uint16_t* buffer, int start, int length, @@ -4060,7 +4033,7 @@ int String::Write(uint16_t* buffer, if (IsDeadCheck(isolate, "v8::String::Write()")) return 0; LOG_API(isolate, "String::Write"); ENTER_V8(isolate); - ASSERT(start >= 0 && length >= kUndefinedLength); + ASSERT(start >= 0 && length >= -1); i::Handle str = Utils::OpenHandle(this); isolate->string_tracker()->RecordWrite(str); if (options & HINT_MANY_WRITES_EXPECTED) { @@ -4069,7 +4042,7 @@ int String::Write(uint16_t* buffer, FlattenString(str); } int end = start + length; - if ((length == kUndefinedLength) || (length > str->length() - start) ) + if ((length == -1) || (length > str->length() - start) ) end = str->length(); if (end < 0) return 0; i::String::WriteToFlat(*str, buffer, start, end); @@ -4100,43 +4073,18 @@ bool v8::String::IsExternalAscii() const { } -void v8::String::VerifyExternalStringEncoding(int encoding) const { - typedef internal::Internals I; +void v8::String::VerifyExternalStringResource( + v8::String::ExternalStringResource* value) const { i::Handle str = Utils::OpenHandle(this); - switch (encoding) { - case UTF_16_ENCODING | ASCII_HINT: - CHECK(str->HasOnlyAsciiChars()); - // Fall through - case UTF_16_ENCODING | NOT_ASCII_HINT : - CHECK(str->IsExternalTwoByteString()); - break; - case LATIN1_ENCODING | ASCII_HINT: - CHECK(str->IsExternalAsciiString()); - break; - default: - CHECK_EQ(INVALID_ENCODING, encoding); - CHECK(!str->IsExternalString()); - break; - } -} - - -void v8::String::VerifyExternalStringResourceBase( - v8::String::ExternalStringResourceBase* value) const { - i::Handle str = Utils::OpenHandle(this); - i::StringShape shape(*str); - const void* expected; - // We expect an external string at this point since GetExternalStringEncoding - // should have already been called to rule out non-external strings. + const v8::String::ExternalStringResource* expected; if (i::StringShape(*str).IsExternalTwoByte()) { - expected = i::ExternalTwoByteString::cast(*str)->resource(); + const void* resource = + i::Handle::cast(str)->resource(); + expected = reinterpret_cast(resource); } else { - ASSERT(i::StringShape(*str).IsExternalAscii()); - expected = i::ExternalAsciiString::cast(*str)->resource(); + expected = NULL; } - - CHECK_EQ(expected, - reinterpret_cast(value)); + CHECK_EQ(expected, value); } @@ -4753,44 +4701,17 @@ Local v8::String::Empty() { } -static i::Handle NewOneByteEncodedString( - i::Factory* factory, const char* data, int length, int encoding) { - if (length == String::kUndefinedLength) length = i::StrLength(data); - typedef v8::String S; - - static const int kAsciiHintShift = 16; - ASSERT(IS_POWER_OF_TWO(encoding & S::kAsciiHintMask)); - i::String::AsciiHint ascii_hint = - static_cast(encoding >> kAsciiHintShift); - STATIC_ASSERT(i::String::MAYBE_ASCII == 0); - STATIC_ASSERT(i::String::NOT_ASCII == - (v8::String::NOT_ASCII_HINT >> kAsciiHintShift)); - STATIC_ASSERT(i::String::ASCII == - (v8::String::ASCII_HINT >> kAsciiHintShift)); - - int masked_encoding = encoding & S::kStringEncodingMask; - - if (masked_encoding == S::UTF_8_ENCODING) { - return factory->NewStringFromUtf8( - i::Vector(data, length), i::NOT_TENURED, ascii_hint); - } else if (masked_encoding == S::LATIN1_ENCODING) { - return factory->NewStringFromLatin1( - i::Vector(data, length), i::NOT_TENURED, ascii_hint); - } else { // Wrong encoding. - return i::Handle(); - } -} - - -Local v8::String::New( - const char* data, int length, int encoding) { +Local v8::String::New(const char* data, int length) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::String::New()"); LOG_API(isolate, "String::New(char)"); if (length == 0) return Empty(); ENTER_V8(isolate); - return Utils::ToLocal( - NewOneByteEncodedString(isolate->factory(), data, length, encoding)); + if (length == -1) length = i::StrLength(data); + i::Handle result = + isolate->factory()->NewStringFromUtf8( + i::Vector(data, length)); + return Utils::ToLocal(result); } @@ -4807,14 +4728,15 @@ Local v8::String::Concat(Handle left, Handle right) { } -Local v8::String::NewUndetectable( - const char* data, int length, int encoding) { +Local v8::String::NewUndetectable(const char* data, int length) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::String::NewUndetectable()"); LOG_API(isolate, "String::NewUndetectable(char)"); ENTER_V8(isolate); + if (length == -1) length = i::StrLength(data); i::Handle result = - NewOneByteEncodedString(isolate->factory(), data, length, encoding); + isolate->factory()->NewStringFromUtf8( + i::Vector(data, length)); result->MarkAsUndetectable(); return Utils::ToLocal(result); } @@ -4833,7 +4755,7 @@ Local v8::String::New(const uint16_t* data, int length) { LOG_API(isolate, "String::New(uint16_)"); if (length == 0) return Empty(); ENTER_V8(isolate); - if (length == kUndefinedLength) length = TwoByteStringLength(data); + if (length == -1) length = TwoByteStringLength(data); i::Handle result = isolate->factory()->NewStringFromTwoByte( i::Vector(data, length)); @@ -4846,7 +4768,7 @@ Local v8::String::NewUndetectable(const uint16_t* data, int length) { EnsureInitializedForIsolate(isolate, "v8::String::NewUndetectable()"); LOG_API(isolate, "String::NewUndetectable(uint16_)"); ENTER_V8(isolate); - if (length == kUndefinedLength) length = TwoByteStringLength(data); + if (length == -1) length = TwoByteStringLength(data); i::Handle result = isolate->factory()->NewStringFromTwoByte( i::Vector(data, length)); @@ -4884,43 +4806,29 @@ Local v8::String::NewExternal( } -template -static bool MakeStringExternal( - i::Handle string, StringResourceType* resource) { - i::Isolate* isolate = string->GetIsolate(); +bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { + i::Handle obj = Utils::OpenHandle(this); + i::Isolate* isolate = obj->GetIsolate(); if (IsDeadCheck(isolate, "v8::String::MakeExternal()")) return false; - if (i::StringShape(*string).IsExternal()) { + if (i::StringShape(*obj).IsExternalTwoByte()) { return false; // Already an external string. } ENTER_V8(isolate); - if (isolate->string_tracker()->IsFreshUnusedString(string)) { + if (isolate->string_tracker()->IsFreshUnusedString(obj)) { return false; } if (isolate->heap()->IsInGCPostProcessing()) { return false; } CHECK(resource && resource->data()); - bool result = string->MakeExternal(resource); - if (result && !string->IsSymbol()) { - isolate->heap()->external_string_table()->AddString(*string); + bool result = obj->MakeExternal(resource); + if (result && !obj->IsSymbol()) { + isolate->heap()->external_string_table()->AddString(*obj); } return result; } -bool v8::String::MakeExternal(ExternalStringResource* resource) { - i::Handle obj = Utils::OpenHandle(this); - return MakeStringExternal(obj, resource); -} - - -bool v8::String::MakeExternal(ExternalAsciiStringResource* resource) { - i::Handle obj = Utils::OpenHandle(this); - ASSERT(obj->HasOnlyAsciiChars()); - return MakeStringExternal(obj, resource); -} - - Local v8::String::NewExternal( v8::String::ExternalAsciiStringResource* resource) { i::Isolate* isolate = i::Isolate::Current(); @@ -4934,40 +4842,27 @@ Local v8::String::NewExternal( } -Local v8::String::NewExternal(ExternalLatin1StringResource* resource, - int encoding) { - typedef v8::internal::Internals I; - i::Isolate* isolate = i::Isolate::Current(); - EnsureInitializedForIsolate(isolate, "v8::String::NewExternal()"); - LOG_API(isolate, "String::NewExternal"); +bool v8::String::MakeExternal( + v8::String::ExternalAsciiStringResource* resource) { + i::Handle obj = Utils::OpenHandle(this); + i::Isolate* isolate = obj->GetIsolate(); + if (IsDeadCheck(isolate, "v8::String::MakeExternal()")) return false; + if (i::StringShape(*obj).IsExternalTwoByte()) { + return false; // Already an external string. + } ENTER_V8(isolate); - ASSERT((encoding & kStringEncodingMask) == LATIN1_ENCODING); + if (isolate->string_tracker()->IsFreshUnusedString(obj)) { + return false; + } + if (isolate->heap()->IsInGCPostProcessing()) { + return false; + } CHECK(resource && resource->data()); - int ascii_hint = (encoding & kAsciiHintMask); - i::Handle result; - - if (ascii_hint == ASCII_HINT || - (ascii_hint != NOT_ASCII_HINT && - i::String::IsAscii(resource->data(), - static_cast(resource->length())))) { - // Assert that the ascii hint is correct. - ASSERT(ascii_hint != ASCII_HINT || - i::String::IsAscii(resource->data(), - static_cast(resource->length()))); - result = NewExternalAsciiStringHandle(isolate, resource); - isolate->heap()->external_string_table()->AddString(*result); - } else { - // We cannot simply take the backing store and use it as an ASCII string, - // since it's not. Instead, we convert it to an internal string and dispose - // the external resource. - result = isolate->factory()->NewStringFromLatin1( - i::Vector(resource->data(), - static_cast(resource->length())), - i::NOT_TENURED, - i::String::NOT_ASCII); - resource->Dispose(); + bool result = obj->MakeExternal(resource); + if (result && !obj->IsSymbol()) { + isolate->heap()->external_string_table()->AddString(*obj); } - return Utils::ToLocal(result); + return result; } @@ -5230,28 +5125,14 @@ Local Array::CloneElementAt(uint32_t index) { } -Local v8::String::NewSymbol( - const char* data, int length, int encoding) { +Local v8::String::NewSymbol(const char* data, int length) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::String::NewSymbol()"); LOG_API(isolate, "String::NewSymbol(char)"); ENTER_V8(isolate); - if (length == kUndefinedLength) length = i::StrLength(data); - i::Handle result; - - ASSERT(IS_POWER_OF_TWO(encoding & kAsciiHintMask)); - if (((encoding & kStringEncodingMask) == LATIN1_ENCODING) && - ((encoding & kAsciiHintMask) == NOT_ASCII_HINT || - !i::String::IsAscii(data, length))) { - result = isolate->factory()->NewStringFromLatin1( - i::Vector(data, length), - i::NOT_TENURED, - i::String::NOT_ASCII); - result = isolate->factory()->LookupSymbol(result); - } else { // We can handle UTF8 and ASCII strings here. - result = - isolate->factory()->LookupSymbol(i::Vector(data, length)); - } + if (length == -1) length = i::StrLength(data); + i::Handle result = + isolate->factory()->LookupSymbol(i::Vector(data, length)); return Utils::ToLocal(result); } diff --git a/src/factory.cc b/src/factory.cc index 69b9d29..462af59 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -204,23 +204,10 @@ Handle Factory::NewStringFromAscii(Vector string, } Handle Factory::NewStringFromUtf8(Vector string, - PretenureFlag pretenure, - String::AsciiHint ascii_hint) { + PretenureFlag pretenure) { CALL_HEAP_FUNCTION( isolate(), - isolate()->heap()->AllocateStringFromUtf8( - string, pretenure, ascii_hint), - String); -} - - -Handle Factory::NewStringFromLatin1(Vector string, - PretenureFlag pretenure, - String::AsciiHint ascii_hint) { - CALL_HEAP_FUNCTION( - isolate(), - isolate()->heap()->AllocateStringFromLatin1( - string, pretenure, ascii_hint), + isolate()->heap()->AllocateStringFromUtf8(string, pretenure), String); } diff --git a/src/factory.h b/src/factory.h index 6411d8e..e617abb 100644 --- a/src/factory.h +++ b/src/factory.h @@ -120,13 +120,7 @@ class Factory { // flags in the parser. Handle NewStringFromUtf8( Vector str, - PretenureFlag pretenure = NOT_TENURED, - String::AsciiHint ascii_hint = String::MAYBE_ASCII); - - Handle NewStringFromLatin1( - Vector str, - PretenureFlag pretenure = NOT_TENURED, - String::AsciiHint ascii_hint = String::MAYBE_ASCII); + PretenureFlag pretenure = NOT_TENURED); Handle NewStringFromTwoByte( Vector str, diff --git a/src/heap-inl.h b/src/heap-inl.h index 1bc6e8d..4a827fe 100644 --- a/src/heap-inl.h +++ b/src/heap-inl.h @@ -83,14 +83,9 @@ void PromotionQueue::ActivateGuardIfOnTheSamePage() { MaybeObject* Heap::AllocateStringFromUtf8(Vector str, - PretenureFlag pretenure, - String::AsciiHint ascii_hint) { - if ((ascii_hint == String::MAYBE_ASCII && - String::IsAscii(str.start(), str.length())) || - ascii_hint == String::ASCII) { - // Assert that the ASCII-hint is correct. - ASSERT(ascii_hint != String::ASCII || - String::IsAscii(str.start(), str.length())); + PretenureFlag pretenure) { + // Check for ASCII first since this is the common case. + if (String::IsAscii(str.start(), str.length())) { // If the string is ASCII, we do not need to convert the characters // since UTF8 is backwards compatible with ASCII. return AllocateStringFromAscii(str, pretenure); @@ -100,24 +95,6 @@ MaybeObject* Heap::AllocateStringFromUtf8(Vector str, } -MaybeObject* Heap::AllocateStringFromLatin1(Vector str, - PretenureFlag pretenure, - String::AsciiHint ascii_hint) { - if ((ascii_hint == String::MAYBE_ASCII && - String::IsAscii(str.start(), str.length())) || - ascii_hint == String::ASCII) { - // Assert that the strict ASCII-hint is correct. - ASSERT(ascii_hint != String::ASCII || - String::IsAscii(str.start(), str.length())); - // If the string is ASCII, we do not need to convert the characters - // since Latin1 is backwards compatible with ASCII. - return AllocateStringFromAscii(str, pretenure); - } - // Non-ASCII and we need to decode. - return AllocateStringFromLatin1Slow(str, pretenure); -} - - MaybeObject* Heap::AllocateSymbol(Vector str, int chars, uint32_t hash_field) { diff --git a/src/heap.cc b/src/heap.cc index 20921d0..9ba7692 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -48,7 +48,6 @@ #include "snapshot.h" #include "store-buffer.h" #include "v8threads.h" -#include "v8utils.h" #include "vm-state-inl.h" #if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP #include "regexp-macro-assembler.h" @@ -4391,8 +4390,7 @@ MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor, MaybeObject* Heap::AllocateStringFromAscii(Vector string, PretenureFlag pretenure) { - int length = string.length(); - if (length == 1) { + if (string.length() == 1) { return Heap::LookupSingleCharacterStringFromCode(string[0]); } Object* result; @@ -4401,10 +4399,11 @@ MaybeObject* Heap::AllocateStringFromAscii(Vector string, if (!maybe_result->ToObject(&result)) return maybe_result; } - isolate_->counters()->string_length_ascii()->Increment(length); - // Copy the characters into the new object. - CopyChars(SeqAsciiString::cast(result)->GetChars(), string.start(), length); + SeqAsciiString* string_result = SeqAsciiString::cast(result); + for (int i = 0; i < string.length(); i++) { + string_result->SeqAsciiStringSet(i, string[i]); + } return result; } @@ -4431,63 +4430,41 @@ MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector string, if (!maybe_result->ToObject(&result)) return maybe_result; } - isolate_->counters()->string_length_utf8()->Increment(chars); - // Convert and copy the characters into the new object. - SeqTwoByteString* twobyte = SeqTwoByteString::cast(result); + String* string_result = String::cast(result); decoder->Reset(string.start(), string.length()); int i = 0; while (i < chars) { uint32_t r = decoder->GetNext(); if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) { - twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::LeadSurrogate(r)); - twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::TrailSurrogate(r)); + string_result->Set(i++, unibrow::Utf16::LeadSurrogate(r)); + string_result->Set(i++, unibrow::Utf16::TrailSurrogate(r)); } else { - twobyte->SeqTwoByteStringSet(i++, r); + string_result->Set(i++, r); } } return result; } -MaybeObject* Heap::AllocateStringFromLatin1Slow(Vector string, - PretenureFlag pretenure) { - int chars = string.length(); - Object* result; - { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure); - if (!maybe_result->ToObject(&result)) return maybe_result; - } - - isolate_->counters()->string_length_latin1()->Increment(chars); - - // Convert and copy the characters into the new object. - SeqTwoByteString* string_result = SeqTwoByteString::cast(result); - CopyChars(string_result->GetChars(), - reinterpret_cast(string.start()), - chars); - return result; -} - - MaybeObject* Heap::AllocateStringFromTwoByte(Vector string, PretenureFlag pretenure) { // Check if the string is an ASCII string. - Object* result; - int length = string.length(); - const uc16* start = string.start(); - - if (String::IsAscii(start, length)) { - MaybeObject* maybe_result = AllocateRawAsciiString(length, pretenure); - if (!maybe_result->ToObject(&result)) return maybe_result; - isolate_->counters()->string_length_ascii()->Increment(length); - CopyChars(SeqAsciiString::cast(result)->GetChars(), start, length); + MaybeObject* maybe_result; + if (String::IsAscii(string.start(), string.length())) { + maybe_result = AllocateRawAsciiString(string.length(), pretenure); } else { // It's not an ASCII string. - MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure); - if (!maybe_result->ToObject(&result)) return maybe_result; - isolate_->counters()->string_length_utf16()->Increment(length); - CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length); + maybe_result = AllocateRawTwoByteString(string.length(), pretenure); } + Object* result; + if (!maybe_result->ToObject(&result)) return maybe_result; + // Copy the characters into the new object, which may be either ASCII or + // UTF-16. + String* string_result = String::cast(result); + for (int i = 0; i < string.length(); i++) { + string_result->Set(i, string[i]); + } return result; } diff --git a/src/heap.h b/src/heap.h index a27fb0c..ba340a2 100644 --- a/src/heap.h +++ b/src/heap.h @@ -679,16 +679,8 @@ class Heap { PretenureFlag pretenure = NOT_TENURED); MUST_USE_RESULT inline MaybeObject* AllocateStringFromUtf8( Vector str, - PretenureFlag pretenure = NOT_TENURED, - String::AsciiHint ascii_hint = String::MAYBE_ASCII); - MUST_USE_RESULT MaybeObject* AllocateStringFromUtf8Slow( - Vector str, PretenureFlag pretenure = NOT_TENURED); - MUST_USE_RESULT inline MaybeObject* AllocateStringFromLatin1( - Vector str, - PretenureFlag pretenure = NOT_TENURED, - String::AsciiHint ascii_hint = String::MAYBE_ASCII); - MUST_USE_RESULT MaybeObject* AllocateStringFromLatin1Slow( + MUST_USE_RESULT MaybeObject* AllocateStringFromUtf8Slow( Vector str, PretenureFlag pretenure = NOT_TENURED); MUST_USE_RESULT MaybeObject* AllocateStringFromTwoByte( diff --git a/src/objects.h b/src/objects.h index 1f74a1b..720d96e 100644 --- a/src/objects.h +++ b/src/objects.h @@ -7128,10 +7128,6 @@ class String: public HeapObject { friend class String; }; - enum AsciiHint { MAYBE_ASCII = 0, - ASCII = 1, - NOT_ASCII = 2 }; - // Get and set the length of the string. inline int length(); inline void set_length(int value); diff --git a/src/v8-counters.h b/src/v8-counters.h index 76be0a2..fad3454 100644 --- a/src/v8-counters.h +++ b/src/v8-counters.h @@ -252,10 +252,6 @@ namespace internal { SC(string_add_make_two_char, V8.StringAddMakeTwoChar) \ SC(string_compare_native, V8.StringCompareNative) \ SC(string_compare_runtime, V8.StringCompareRuntime) \ - SC(string_length_utf8, V8.StringLengthUtf8) \ - SC(string_length_ascii, V8.StringLengthAScii) \ - SC(string_length_latin1, V8.StringLengthLatin1) \ - SC(string_length_utf16, V8.StringLengthUtf16) \ SC(regexp_entry_runtime, V8.RegExpEntryRuntime) \ SC(regexp_entry_native, V8.RegExpEntryNative) \ SC(number_to_string_native, V8.NumberToStringNative) \ diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 9b02791..689286f 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -714,298 +714,9 @@ TEST(ExternalStringWithDisposeHandling) { } -static void TestNewLatin1String(int encoding1, int encoding2) { - const char* chars1 = "ASCII 123"; - const char* chars1js = "'ASCII 123'"; - int str1_len = static_cast(strlen(chars1)); - const char* chars2 = "Non-ASCII \xAB\xCD\xEF"; - const char* chars2js = "'Non-ASCII \\u00ab\\u00cd\\u00ef'"; - int str2_len = static_cast(strlen(chars2)); - - Local str1 = String::New(chars1, str1_len, encoding1); - Local str2 = String::New(chars2, str2_len, encoding2); - Local str1_compare = CompileRun(chars1js)->ToString(); - Local str2_compare = CompileRun(chars2js)->ToString(); - - if (encoding1 & String::NOT_ASCII_HINT) { - CHECK(v8::Utils::OpenHandle(*str1)->IsSeqTwoByteString()); - } else { - CHECK(v8::Utils::OpenHandle(*str1)->IsSeqAsciiString()); - } - CHECK(v8::Utils::OpenHandle(*str1_compare)->IsSeqAsciiString()); - CHECK(v8::Utils::OpenHandle(*str2)->IsSeqTwoByteString()); - CHECK(v8::Utils::OpenHandle(*str2_compare)->IsSeqTwoByteString()); - - CHECK(str1_compare->Equals(str1)); - CHECK(str2_compare->Equals(str2)); -} - - -TEST(CreateLatin1String) { - v8::HandleScope scope; - LocalContext env; - - int latin1 = String::LATIN1_ENCODING; - int l_noascii = String::LATIN1_ENCODING | String::NOT_ASCII_HINT; - int l_ascii = String::LATIN1_ENCODING | String::ASCII_HINT; - - TestNewLatin1String(latin1, latin1); - TestNewLatin1String(l_ascii, latin1); - TestNewLatin1String(l_noascii, l_noascii); -} - - -TEST(ExternalStringEncoding) { - v8::HandleScope scope; - LocalContext env; - int counter = 0; - - { HandleScope scope; - uint16_t* two_byte_ascii = AsciiToTwoByteString("two byte ascii"); - uint16_t* two_byte = AsciiToTwoByteString("two byte non-ascii \x99"); - char* ascii = i::StrDup("ascii"); - - TestResource* two_byte_resource = new TestResource(two_byte, &counter); - TestResource* two_byte_ascii_resource = - new TestResource(two_byte_ascii, &counter); - TestAsciiResource* ascii_resource = - new TestAsciiResource(ascii, &counter); - - Local two_byte_external = String::NewExternal(two_byte_resource); - Local two_byte_ascii_external = - String::NewExternal(two_byte_ascii_resource); - Local ascii_external = String::NewExternal(ascii_resource); - Local not_external = v8_str("not external"); - - CHECK_EQ(String::UTF_16_ENCODING | String::NOT_ASCII_HINT, - two_byte_external->GetExternalStringEncoding()); - CHECK_EQ(String::UTF_16_ENCODING | String::ASCII_HINT, - two_byte_ascii_external->GetExternalStringEncoding()); - CHECK_EQ(String::LATIN1_ENCODING | String::ASCII_HINT, - ascii_external->GetExternalStringEncoding()); - CHECK_EQ(String::INVALID_ENCODING, - not_external->GetExternalStringEncoding()); - - CHECK_EQ(two_byte_resource, two_byte_external->GetExternalStringResource()); - CHECK_EQ(two_byte_ascii_resource, - two_byte_ascii_external->GetExternalStringResourceBase()); - CHECK_EQ(ascii_resource, ascii_external->GetExternalStringResourceBase()); - - CHECK_EQ(0, counter); - } - - HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); - - CHECK_EQ(3, counter); -} - - -TEST(WriteLatin1String) { - HandleScope scope; - LocalContext env; - const char* latin1_ascii = "latin1 ascii"; - const char* latin1 = "\x99 latin1 non-ascii \xF8"; - const char* concat = "latin1 ascii\x99 latin1 non-ascii \xF8"; - const char* sub = "latin1 non-ascii \xF8"; - - Local latin1_ascii_string = String::New(latin1_ascii, - String::kUndefinedLength, - String::LATIN1_ENCODING); - Local latin1_string = String::New(latin1, - String::kUndefinedLength, - String::LATIN1_ENCODING); - Local concat_string = String::Concat(latin1_ascii_string, - latin1_string); - Local sub_string = v8::Utils::ToLocal( - FACTORY->NewSubString( - v8::Utils::OpenHandle(*latin1_string), 2, latin1_string->Length())); - - CHECK(v8::Utils::OpenHandle(*latin1_ascii_string)->IsSeqAsciiString()); - CHECK(v8::Utils::OpenHandle(*latin1_string)->IsSeqTwoByteString()); - CHECK(v8::Utils::OpenHandle(*concat_string)->IsConsString()); - CHECK(v8::Utils::OpenHandle(*sub_string)->IsSlicedString()); - - char buffer[64]; - CHECK_EQ(static_cast(strlen(latin1_ascii)), - latin1_ascii_string->WriteLatin1(buffer)); - CHECK_EQ(0, strcmp(latin1_ascii, buffer)); - CHECK_EQ(static_cast(strlen(latin1)), - latin1_string->WriteLatin1(buffer)); - CHECK_EQ(0, strcmp(latin1, buffer)); - CHECK_EQ(static_cast(strlen(concat)), - concat_string->WriteLatin1(buffer)); - CHECK_EQ(0, strcmp(concat, buffer)); - CHECK_EQ(static_cast(strlen(sub)), - sub_string->WriteLatin1(buffer)); - CHECK_EQ(0, strcmp(sub, buffer)); - - memset(buffer, 0x1, sizeof(buffer)); - CHECK_EQ(static_cast(strlen(latin1)), - latin1_string->WriteLatin1(buffer, - 0, - String::kUndefinedLength, - String::NO_NULL_TERMINATION)); - CHECK_EQ(0, strncmp(latin1, buffer, strlen(latin1))); - CHECK_NE(0, strcmp(latin1, buffer)); - buffer[strlen(latin1)] = '\0'; - CHECK_EQ(0, strcmp(latin1, buffer)); - - CHECK_EQ(static_cast(strlen(latin1)) - 2, - latin1_string->WriteLatin1(buffer, 2)); - CHECK_EQ(0, strncmp(latin1 + 2, buffer, strlen(latin1))); -} - - -class TestLatin1Resource: public String::ExternalLatin1StringResource { - public: - explicit TestLatin1Resource(const char* data, int* counter = NULL) - : data_(data), length_(strlen(data)), counter_(counter) { } - - ~TestLatin1Resource() { - i::DeleteArray(data_); - if (counter_ != NULL) ++*counter_; - } - - const char* data() const { - return data_; - } - - size_t length() const { - return length_; - } - private: - const char* data_; - size_t length_; - int* counter_; -}; - - -TEST(ExternalLatin1String) { - HandleScope scope; - LocalContext env; - int counter = 0; - - { HandleScope scope; - char* latin1_ascii_a = i::StrDup("latin1 ascii a"); - char* latin1_ascii_b = i::StrDup("latin1 ascii b"); - char* latin1_a = i::StrDup("latin non-ascii \xAA"); - char* latin1_b = i::StrDup("latin non-ascii \xBB"); - - TestLatin1Resource* latin1_ascii_a_resource = - new TestLatin1Resource(latin1_ascii_a, &counter); - TestLatin1Resource* latin1_ascii_b_resource = - new TestLatin1Resource(latin1_ascii_b, &counter); - TestLatin1Resource* latin1_a_resource = - new TestLatin1Resource(latin1_a, &counter); - TestLatin1Resource* latin1_b_resource = - new TestLatin1Resource(latin1_b, &counter); - - Local latin1_ascii_a_external = - String::NewExternal(latin1_ascii_a_resource); - Local latin1_ascii_b_external = String::NewExternal( - latin1_ascii_b_resource, - String::LATIN1_ENCODING | String::ASCII_HINT); - CHECK_EQ(0, counter); - - // Non-ascii latin1 strings are internalized immediately as two-byte - // string and the external resource is disposed. - Local latin1_a_external = String::NewExternal(latin1_a_resource); - Local latin1_b_external = String::NewExternal( - latin1_b_resource, String::LATIN1_ENCODING | String::NOT_ASCII_HINT); - CHECK(v8::Utils::OpenHandle(*latin1_a_external)->IsSeqTwoByteString()); - CHECK(v8::Utils::OpenHandle(*latin1_b_external)->IsSeqTwoByteString()); - CHECK_EQ(2, counter); - - CHECK_EQ(latin1_ascii_a_external->GetExternalStringEncoding(), - (v8::String::LATIN1_ENCODING | v8::String::ASCII_HINT)); - CHECK_EQ(latin1_ascii_b_external->GetExternalStringEncoding(), - (v8::String::LATIN1_ENCODING | v8::String::ASCII_HINT)); - CHECK_EQ(latin1_a_external->GetExternalStringEncoding(), - v8::String::INVALID_ENCODING); - CHECK_EQ(latin1_b_external->GetExternalStringEncoding(), - v8::String::INVALID_ENCODING); - - CHECK_EQ(latin1_ascii_a_resource, - latin1_ascii_a_external->GetExternalStringResourceBase()); - CHECK_EQ(latin1_ascii_b_resource, - latin1_ascii_b_external->GetExternalStringResourceBase()); - } - - HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); - CHECK_EQ(4, counter); -} - - -TEST(ExternalizeLatin1String) { - HandleScope scope; - LocalContext env; - int counter = 0; - - { HandleScope scope; - Local latin1_a_ascii = String::New("latin1 a ascii"); - Local latin1_b_ascii = String::New("latin1 b ascii"); - Local latin1 = String::New("latin1 non-ascii \xAA", - String::kUndefinedLength, - String::LATIN1_ENCODING); - - CHECK(v8::Utils::OpenHandle(*latin1_a_ascii)->IsSeqAsciiString()); - CHECK(v8::Utils::OpenHandle(*latin1_b_ascii)->IsSeqAsciiString()); - CHECK(v8::Utils::OpenHandle(*latin1)->IsSeqTwoByteString()); - - // Run GC twice to put those strings into old space for externalizing. - HEAP->CollectGarbage(i::NEW_SPACE); - HEAP->CollectGarbage(i::NEW_SPACE); - - char* latin1_a_ascii_chars = i::NewArray(64); - uint16_t* latin1_b_ascii_chars = i::NewArray(64); - uint16_t* latin1_chars = i::NewArray(64); - - latin1_a_ascii->WriteLatin1(latin1_a_ascii_chars); - latin1_b_ascii->Write(latin1_b_ascii_chars); - latin1->Write(latin1_chars); - - TestLatin1Resource* latin1_a_ascii_resource = - new TestLatin1Resource(latin1_a_ascii_chars, &counter); - TestResource* latin1_b_ascii_resource = - new TestResource(latin1_b_ascii_chars, &counter); - TestResource* latin1_resource = - new TestResource(latin1_chars, &counter); - - CHECK(latin1_a_ascii->MakeExternal(latin1_a_ascii_resource)); - CHECK(latin1_a_ascii->IsExternalAscii()); - CHECK_EQ(latin1_a_ascii->GetExternalStringEncoding(), - (v8::String::LATIN1_ENCODING | v8::String::ASCII_HINT)); - CHECK_EQ(latin1_a_ascii_resource, - latin1_a_ascii->GetExternalStringResourceBase()); - CHECK(latin1_a_ascii->Equals(String::New("latin1 a ascii"))); - - CHECK(latin1_b_ascii->MakeExternal(latin1_b_ascii_resource)); - CHECK(latin1_b_ascii->IsExternal()); - CHECK_EQ(latin1_b_ascii->GetExternalStringEncoding(), - (v8::String::UTF_16_ENCODING | v8::String::ASCII_HINT)); - CHECK_EQ(latin1_b_ascii_resource, - latin1_b_ascii->GetExternalStringResourceBase()); - CHECK(latin1_b_ascii->Equals(String::New("latin1 b ascii"))); - - CHECK(latin1->MakeExternal(latin1_resource)); - CHECK(latin1->IsExternal()); - CHECK_EQ(latin1->GetExternalStringEncoding(), - (v8::String::UTF_16_ENCODING | v8::String::NOT_ASCII_HINT)); - CHECK_EQ(latin1_resource, - latin1->GetExternalStringResourceBase()); - CHECK(latin1->Equals(String::New("latin1 non-ascii \xAA", - String::kUndefinedLength, - String::LATIN1_ENCODING))); - } - - HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); - CHECK_EQ(3, counter); -} - - THREADED_TEST(StringConcat) { { - HandleScope scope; + v8::HandleScope scope; LocalContext env; const char* one_byte_string_1 = "function a_times_t"; const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";