From ebc0f85e40675a673d0348da5982b58211c7010f Mon Sep 17 00:00:00 2001 From: "lrn@chromium.org" Date: Wed, 5 Oct 2011 11:09:34 +0000 Subject: [PATCH] Revert "Added ability to lock strings to prevent their representation or encoding from changing." This reverts r9424. Review URL: http://codereview.chromium.org/8143018 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9529 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/api.cc | 3 - src/handles.cc | 16 --- src/handles.h | 26 +---- src/heap.cc | 71 ------------ src/heap.h | 20 ---- src/json-parser.h | 249 +++++++++++++++------------------------- src/objects-inl.h | 27 +++-- src/objects.cc | 11 +- src/objects.h | 67 +---------- src/runtime.cc | 21 +--- test/cctest/test-api.cc | 221 ----------------------------------- 11 files changed, 129 insertions(+), 603 deletions(-) diff --git a/src/api.cc b/src/api.cc index ee0645651..7266390a4 100644 --- a/src/api.cc +++ b/src/api.cc @@ -4451,9 +4451,6 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { if (isolate->string_tracker()->IsFreshUnusedString(obj)) { return false; } - if (isolate->heap()->IsStringLocked(*obj)) { - return false; - } if (isolate->heap()->IsInGCPostProcessing()) { return false; } diff --git a/src/handles.cc b/src/handles.cc index d3fd12635..407a3b59a 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -944,20 +944,4 @@ bool CompileOptimized(Handle function, return CompileLazyHelper(&info, flag); } - -void LockString(Handle string) { - CALL_HEAP_FUNCTION_VOID(string->GetHeap()->isolate(), - string->GetHeap()->LockString(*string)); -} - - -StringLock::StringLock(Handle string) : string_(string) { - LockString(string); -} - - -StringLock::~StringLock() { - string_->GetHeap()->UnlockString(*string_); -} - } } // namespace v8::internal diff --git a/src/handles.h b/src/handles.h index 31be71459..d5521f89c 100644 --- a/src/handles.h +++ b/src/handles.h @@ -163,11 +163,9 @@ class HandleScope { // ---------------------------------------------------------------------------- // Handle operations. -// They might invoke garbage collection. The result is an handle to an -// object of expected type, or the handle is a null handle if encountering -// an internal error. Will not return a null handle due to out-of-memory -// unless otherwise stated, but will instead try to do GC and die fatally -// if that doesn't help. +// They might invoke garbage collection. The result is an handle to +// an object of expected type, or the handle is an error if running out +// of space or encountering an internal error. void NormalizeProperties(Handle object, PropertyNormalizationMode mode, @@ -185,7 +183,7 @@ MUST_USE_RESULT Handle NumberDictionarySet( void FlattenString(Handle str); // Flattens a string and returns the underlying external or sequential -// string. Never returns a null handle. +// string. Handle FlattenGetString(Handle str); Handle SetProperty(Handle object, @@ -381,22 +379,6 @@ class NoHandleAllocation BASE_EMBEDDED { #endif }; - -// Prevents a (non-cons, non-slice) string from having its representation -// changed. This is just a Handle based wrapper around Heap::LockString. -// Use Heap::UnlockString to unlock (that one can't cause allocation, so -// it doesn't need a Handle wrapper). -void LockString(Handle string); - -// Scoped lock on a string. -class StringLock { - public: - explicit StringLock(Handle string); - ~StringLock(); - private: - Handle string_; -}; - } } // namespace v8::internal #endif // V8_HANDLES_H_ diff --git a/src/heap.cc b/src/heap.cc index 8674ba0f7..d1f48acbd 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2340,7 +2340,6 @@ bool Heap::CreateInitialObjects() { set_intrinsic_function_names(StringDictionary::cast(obj)); if (InitializeNumberStringCache()->IsFailure()) return false; - if (InitializeStringLocks()->IsFailure()) return false; // Allocate cache for single character ASCII strings. { MaybeObject* maybe_obj = @@ -2557,76 +2556,6 @@ MaybeObject* Heap::Uint32ToString(uint32_t value, } -MaybeObject* Heap::LockString(String* string) { - ASSERT(!string->IsConsString()); - FixedArray* locks = string_locks(); - ASSERT(locks->length() > 1); - int length = locks->length(); - int element_count = Smi::cast(locks->get(0))->value(); - int element_index = element_count + 1; - if (element_index >= length) { - int new_length = length * 2; - MaybeObject* allocation = AllocateFixedArray(new_length); - FixedArray* new_locks = NULL; // Initialized to please compiler. - if (!allocation->To(&new_locks)) return allocation; - for (int i = 1; i < length; i++) { - new_locks->set(i, locks->get(i)); - } - set_string_locks(new_locks); - locks = new_locks; - } - locks->set(element_index, string); - locks->set(0, Smi::FromInt(element_index)); - return string; -} - - -void Heap::UnlockString(String* string) { - FixedArray* locks = string_locks(); - ASSERT(locks->length() > 1); - int element_count = Smi::cast(locks->get(0))->value(); - ASSERT(element_count > 0); - ASSERT(element_count < locks->length()); - for (int i = 1; i <= element_count; i++) { - String* element = String::cast(locks->get(i)); - if (element == string) { - if (i < element_count) { - locks->set(i, locks->get(element_count)); - } - locks->set_undefined(element_count); - locks->set(0, Smi::FromInt(element_count - 1)); - return; - } - } - // We should have found the string. It's an error to try to unlock - // a string that hasn't been locked. - UNREACHABLE(); -} - - -bool Heap::IsStringLocked(String* string) { - if (string->IsConsString()) return false; - FixedArray* locks = string_locks(); - ASSERT(locks->length() > 1); - int element_count = Smi::cast(locks->get(0))->value(); - for (int i = 1; i <= element_count; i++) { - if (locks->get(i) == string) return true; - } - return false; -} - - -MaybeObject* Heap::InitializeStringLocks() { - const int kInitialSize = 6; - MaybeObject* allocation = AllocateFixedArray(kInitialSize); - if (allocation->IsFailure()) return allocation; - FixedArray* new_array = FixedArray::cast(allocation->ToObjectUnchecked()); - new_array->set(0, Smi::FromInt(0)); - set_string_locks(new_array); - return new_array; -} - - Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) { return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]); } diff --git a/src/heap.h b/src/heap.h index 499c30eca..8672db29a 100644 --- a/src/heap.h +++ b/src/heap.h @@ -77,7 +77,6 @@ inline Heap* _inline_get_heap_(); V(Map, hash_table_map, HashTableMap) \ V(Smi, stack_limit, StackLimit) \ V(FixedArray, number_string_cache, NumberStringCache) \ - V(FixedArray, string_locks, StringLocks) \ V(Object, instanceof_cache_function, InstanceofCacheFunction) \ V(Object, instanceof_cache_map, InstanceofCacheMap) \ V(Object, instanceof_cache_answer, InstanceofCacheAnswer) \ @@ -1200,25 +1199,6 @@ class Heap { // the string representation of the number. Otherwise return undefined. Object* GetNumberStringCache(Object* number); - // Locks a string to prevent changes to the string's representation or - // encoding, e.g., due to externalization. - // It does not prevent moving the string during a GC - // (i.e., it's not a way to keep a pointer to an underlying character - // sequence valid). Might fail if the underlying data structure can't - // grow to accomodate the string, otherwise returns the string itself. - // - // Stores data in Heap::string_locks(), a FixedArray with the number - // of filled in elements in the first position, and that number of - // string pointers in the following positions (in no particular order). - // The FixedArray is padded with undefined or similar uninteresting values. - MaybeObject* LockString(String* string); - // Removes the lock on the string. - void UnlockString(String* string); - // Check if a string is locked. - bool IsStringLocked(String* string); - // Initializes the data structure underlying LockString. - MaybeObject* InitializeStringLocks(); - // Update the cache with a new number-string pair. void SetNumberStringCache(Object* number, String* str); diff --git a/src/json-parser.h b/src/json-parser.h index 66478938f..ca796a699 100644 --- a/src/json-parser.h +++ b/src/json-parser.h @@ -39,45 +39,28 @@ namespace v8 { namespace internal { -// A simple JSON parser. -template +// A simple json parser. +template class JsonParser BASE_EMBEDDED { public: static Handle Parse(Handle source) { - return JsonParser(Handle::cast(source)).ParseJson(); + return JsonParser().ParseJson(source); } static const int kEndOfString = -1; private: - typedef typename StringType::CharType SourceChar; - - explicit JsonParser(Handle source) - : isolate_(source->GetHeap()->isolate()), - source_(source), - characters_(NULL), - source_length_(source->length()), - position_(-1) { - InitializeSource(); - } - - - // Parse the source string as containing a single JSON value. - Handle ParseJson(); - - // Set up the object so GetChar works, in case it needs more than just - // the constructor. - void InitializeSource(); - - inline uc32 GetChar(int position); - inline const SourceChar* GetChars(); + // Parse a string containing a single JSON value. + Handle ParseJson(Handle source); inline void Advance() { position_++; if (position_ >= source_length_) { c0_ = kEndOfString; + } else if (seq_ascii) { + c0_ = seq_source_->SeqAsciiStringGet(position_); } else { - c0_ = GetChar(position_); + c0_ = source_->Get(position_); } } @@ -85,20 +68,14 @@ class JsonParser BASE_EMBEDDED { // section 15.12.1.1. The only allowed whitespace characters between tokens // are tab, carriage-return, newline and space. - - static inline bool IsJsonWhitespace(uc32 ch) { - const char* whitespaces = "\x20\x09\x0a\0\0\x0d\0\0"; - return (static_cast(whitespaces[ch & 0x07]) == ch); - } - inline void AdvanceSkipWhitespace() { do { Advance(); - } while (IsJsonWhitespace(c0_)); + } while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' '); } inline void SkipWhitespace() { - while (IsJsonWhitespace(c0_)) { + while (c0_ == '\t' || c0_ == '\r' || c0_ == '\n' || c0_ == ' ') { Advance(); } } @@ -133,7 +110,7 @@ class JsonParser BASE_EMBEDDED { // Creates a new string and copies prefix[start..end] into the beginning // of it. Then scans the rest of the string, adding characters after the // prefix. Called by ScanJsonString when reaching a '\' or non-ASCII char. - template + template Handle SlowScanJsonString(Handle prefix, int start, int end); // A JSON number (production JSONNumber) is a subset of the valid JavaScript @@ -175,26 +152,37 @@ class JsonParser BASE_EMBEDDED { static const int kInitialSpecialStringLength = 1024; - Isolate* isolate_; - Handle source_; - // Used for external strings, to avoid going through the resource on - // every access. - const SourceChar* characters_; + + private: + Handle source_; int source_length_; - int position_; + Handle seq_source_; + + Isolate* isolate_; uc32 c0_; + int position_; }; -template -Handle JsonParser::ParseJson() { - // Initial position is right before the string. - ASSERT(position_ == -1); +template +Handle JsonParser::ParseJson(Handle source) { + isolate_ = source->map()->GetHeap()->isolate(); + FlattenString(source); + source_ = source; + source_length_ = source_->length(); + + // Optimized fast case where we only have ASCII characters. + if (seq_ascii) { + seq_source_ = Handle::cast(source_); + } + + // Set initial position right before the string. + position_ = -1; // Advance to the first character (posibly EOS) AdvanceSkipWhitespace(); - // ParseJsonValue also consumes following whitespace. Handle result = ParseJsonValue(); if (result.is_null() || c0_ != kEndOfString) { // Parse failed. Current character is the unexpected token. + const char* message; Factory* factory = isolate()->factory(); Handle array; @@ -231,7 +219,7 @@ Handle JsonParser::ParseJson() { break; } - MessageLocation location(factory->NewScript(source_), + MessageLocation location(factory->NewScript(source), position_, position_ + 1); Handle result = factory->NewSyntaxError(message, array); @@ -243,8 +231,8 @@ Handle JsonParser::ParseJson() { // Parse any JSON value. -template -Handle JsonParser::ParseJsonValue() { +template +Handle JsonParser::ParseJsonValue() { switch (c0_) { case '"': return ParseJsonString(); @@ -295,13 +283,13 @@ Handle JsonParser::ParseJsonValue() { // Parse a JSON object. Position must be right at '{'. -template -Handle JsonParser::ParseJsonObject() { +template +Handle JsonParser::ParseJsonObject() { Handle object_constructor( isolate()->global_context()->object_function()); Handle json_object = isolate()->factory()->NewJSObject(object_constructor); - ASSERT_EQ('{', c0_); + ASSERT_EQ(c0_, '{'); AdvanceSkipWhitespace(); if (c0_ != '}') { @@ -331,8 +319,8 @@ Handle JsonParser::ParseJsonObject() { } // Parse a JSON array. Position must be right at '['. -template -Handle JsonParser::ParseJsonArray() { +template +Handle JsonParser::ParseJsonArray() { ZoneScope zone_scope(isolate(), DELETE_ON_EXIT); ZoneList > elements(4); ASSERT_EQ(c0_, '['); @@ -359,8 +347,8 @@ Handle JsonParser::ParseJsonArray() { } -template -Handle JsonParser::ParseJsonNumber() { +template +Handle JsonParser::ParseJsonNumber() { bool negative = false; int beg_pos = position_; if (c0_ == '-') { @@ -403,12 +391,24 @@ Handle JsonParser::ParseJsonNumber() { } int length = position_ - beg_pos; double number; - - Vector chars(GetChars() + beg_pos, length); - number = StringToDouble(isolate()->unicode_cache(), - chars, - NO_FLAGS, // Hex, octal or trailing junk. - OS::nan_value()); + if (seq_ascii) { + Vector chars(seq_source_->GetChars() + beg_pos, length); + number = StringToDouble(isolate()->unicode_cache(), + chars, + NO_FLAGS, // Hex, octal or trailing junk. + OS::nan_value()); + } else { + Vector buffer = Vector::New(length); + String::WriteToFlat(*source_, buffer.start(), beg_pos, position_); + Vector result = + Vector(reinterpret_cast(buffer.start()), + length); + number = StringToDouble(isolate()->unicode_cache(), + result, + NO_FLAGS, // Hex, octal or trailing junk. + 0.0); + buffer.Dispose(); + } SkipWhitespace(); return isolate()->factory()->NewNumber(number); } @@ -444,17 +444,15 @@ inline Handle NewRawString(Factory* factory, int length) { // Scans the rest of a JSON string starting from position_ and writes // prefix[start..end] along with the scanned characters into a // sequential string of type StringType. -template -template -Handle JsonParser::SlowScanJsonString( +template +template +Handle JsonParser::SlowScanJsonString( Handle prefix, int start, int end) { - typedef typename SinkStringType::CharType SinkChar; int count = end - start; int max_length = count + source_length_ - position_; int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count)); - Handle seq_str = - NewRawString(isolate()->factory(), - length); + Handle seq_str = NewRawString(isolate()->factory(), + length); // Copy prefix into seq_str. SinkChar* dest = seq_str->GetChars(); String::WriteToFlat(*prefix, dest, start, end); @@ -464,7 +462,7 @@ Handle JsonParser::SlowScanJsonString( if (c0_ < 0x20) return Handle::null(); if (count >= length) { // We need to create a longer sequential string for the result. - return SlowScanJsonString(seq_str, 0, count); + return SlowScanJsonString(seq_str, 0, count); } if (c0_ != '\\') { // If the sink can contain UC16 characters, or source_ contains only @@ -472,16 +470,16 @@ Handle JsonParser::SlowScanJsonString( // character. Otherwise check whether the UC16 source character can fit // in the ASCII sink. if (sizeof(SinkChar) == kUC16Size || - sizeof(SourceChar) == kCharSize || + seq_ascii || c0_ <= kMaxAsciiCharCode) { SeqStringSet(seq_str, count++, c0_); Advance(); } else { - // SinkStringType is SeqAsciiString and we just read a non-ASCII char. - return SlowScanJsonString(seq_str, 0, count); + // StringType is SeqAsciiString and we just read a non-ASCII char. + return SlowScanJsonString(seq_str, 0, count); } } else { - Advance(); // Advance past the '\'. + Advance(); // Advance past the \. switch (c0_) { case '"': case '\\': @@ -520,9 +518,9 @@ Handle JsonParser::SlowScanJsonString( // StringType is SeqAsciiString and we just read a non-ASCII char. position_ -= 6; // Rewind position_ to \ in \uxxxx. Advance(); - return SlowScanJsonString(seq_str, - 0, - count); + return SlowScanJsonString(seq_str, + 0, + count); } } default: @@ -534,11 +532,11 @@ Handle JsonParser::SlowScanJsonString( // Shrink seq_string length to count. if (isolate()->heap()->InNewSpace(*seq_str)) { isolate()->heap()->new_space()-> - template ShrinkStringAtAllocationBoundary( + template ShrinkStringAtAllocationBoundary( *seq_str, count); } else { - int string_size = SinkStringType::SizeFor(count); - int allocated_string_size = SinkStringType::SizeFor(length); + int string_size = StringType::SizeFor(count); + int allocated_string_size = StringType::SizeFor(length); int delta = allocated_string_size - string_size; Address start_filler_object = seq_str->address() + string_size; seq_str->set_length(count); @@ -551,9 +549,9 @@ Handle JsonParser::SlowScanJsonString( } -template +template template -Handle JsonParser::ScanJsonString() { +Handle JsonParser::ScanJsonString() { ASSERT_EQ('"', c0_); Advance(); if (c0_ == '"') { @@ -566,24 +564,25 @@ Handle JsonParser::ScanJsonString() { // Check for control character (0x00-0x1f) or unterminated string (<0). if (c0_ < 0x20) return Handle::null(); if (c0_ != '\\') { - if (c0_ <= kMaxAsciiCharCode) { + if (seq_ascii || c0_ <= kMaxAsciiCharCode) { Advance(); } else { - return SlowScanJsonString(source_, - beg_pos, - position_); + return SlowScanJsonString(source_, + beg_pos, + position_); } } else { - return SlowScanJsonString(source_, - beg_pos, - position_); + return SlowScanJsonString(source_, + beg_pos, + position_); } } while (c0_ != '"'); int length = position_ - beg_pos; Handle result; - if (is_symbol && source_->IsSeqAsciiString()) { - result = isolate()->factory()->LookupAsciiSymbol( - Handle::cast(source_), beg_pos, length); + if (seq_ascii && is_symbol) { + result = isolate()->factory()->LookupAsciiSymbol(seq_source_, + beg_pos, + length); } else { result = isolate()->factory()->NewRawAsciiString(length); char* dest = SeqAsciiString::cast(*result)->GetChars(); @@ -595,74 +594,6 @@ Handle JsonParser::ScanJsonString() { return result; } - -template -void JsonParser::InitializeSource() { } - - -template <> -void JsonParser::InitializeSource() { - characters_ = source_->resource()->data(); -} - - -template <> -void JsonParser::InitializeSource() { - characters_ = source_->resource()->data(); -} - - -template <> -uc32 JsonParser::GetChar(int pos) { - return static_cast(source_->SeqAsciiStringGet(pos)); -} - - -template <> -uc32 JsonParser::GetChar(int pos) { - return static_cast(source_->SeqTwoByteStringGet(pos)); -} - - -template <> -uc32 JsonParser::GetChar(int pos) { - ASSERT(pos >= 0); - ASSERT(pos < source_length_); - return static_cast(characters_[pos]); -} - - -template <> -uc32 JsonParser::GetChar(int pos) { - ASSERT(pos >= 0); - ASSERT(pos < source_length_); - return static_cast(characters_[pos]); -} - - -template <> -const char* JsonParser::GetChars() { - return source_->GetChars(); -} - - -template <> -const uc16* JsonParser::GetChars() { - return source_->GetChars(); -} - - -template <> -const char* JsonParser::GetChars() { - return characters_; -} - - -template <> -const uc16* JsonParser::GetChars() { - return characters_; -} - } } // namespace v8::internal #endif // V8_JSON_PARSER_H_ diff --git a/src/objects-inl.h b/src/objects-inl.h index 6509f136c..c579d373f 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -37,7 +37,6 @@ #include "elements.h" #include "objects.h" -#include "char-predicates-inl.h" #include "contexts.h" #include "conversions-inl.h" #include "heap.h" @@ -4218,6 +4217,7 @@ StringHasher::StringHasher(int length) raw_running_hash_(0), array_index_(0), is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize), + is_first_char_(true), is_valid_(true) { } @@ -4229,18 +4229,26 @@ bool StringHasher::has_trivial_hash() { void StringHasher::AddCharacter(uc32 c) { // Use the Jenkins one-at-a-time hash function to update the hash // for the given character. - raw_running_hash_ = (raw_running_hash_ + c) * 1025; + raw_running_hash_ += c; + raw_running_hash_ += (raw_running_hash_ << 10); raw_running_hash_ ^= (raw_running_hash_ >> 6); + // Incremental array index computation. if (is_array_index_) { - // Incremental array index computation. - unsigned digit = static_cast(c) - '0'; - if (digit > 9 || array_index_ > 429496729U - ((digit + 2) >> 3)) { + if (c < '0' || c > '9') { is_array_index_ = false; } else { - array_index_ = array_index_ * 10 + digit; - // Check for overflows or prefixed zeros (lengths > 0). - if (array_index_ == 0 && length_ > 1) { + int d = c - '0'; + if (is_first_char_) { + is_first_char_ = false; + if (c == '0' && length_ > 1) { + is_array_index_ = false; + return; + } + } + if (array_index_ > 429496729U - ((d + 2) >> 3)) { is_array_index_ = false; + } else { + array_index_ = array_index_ * 10 + d; } } } @@ -4249,7 +4257,8 @@ void StringHasher::AddCharacter(uc32 c) { void StringHasher::AddCharacterNoIndex(uc32 c) { ASSERT(!is_array_index()); - raw_running_hash_ = (raw_running_hash_ + c) * 1025; + raw_running_hash_ += c; + raw_running_hash_ += (raw_running_hash_ << 10); raw_running_hash_ ^= (raw_running_hash_ >> 6); } diff --git a/src/objects.cc b/src/objects.cc index 3e280fd79..b77dd1b58 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -2822,8 +2822,7 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( attributes); } - // Unlike SetLocalProperty, we ignore the prototype chain and - // any accessors in it. + // Check for accessor in prototype chain removed here in clone. if (!result.IsFound()) { // Neither properties nor transitions found. return AddProperty(name, value, attributes, kNonStrictMode); @@ -10224,8 +10223,6 @@ class SubStringAsciiSymbolKey : public HashTableKey { ASSERT(length_ >= 0); ASSERT(from_ + length_ <= string_->length()); StringHasher hasher(length_); - AssertNoAllocation no_alloc; - const char* chars = string_->GetChars() + from_; // Very long strings have a trivial hash that doesn't inspect the // string contents. @@ -10236,14 +10233,16 @@ class SubStringAsciiSymbolKey : public HashTableKey { // Do the iterative array index computation as long as there is a // chance this is an array index. while (i < length_ && hasher.is_array_index()) { - hasher.AddCharacter(static_cast(chars[i])); + hasher.AddCharacter(static_cast( + string_->SeqAsciiStringGet(i + from_))); i++; } // Process the remaining characters without updating the array // index. while (i < length_) { - hasher.AddCharacterNoIndex(static_cast(chars[i])); + hasher.AddCharacterNoIndex(static_cast( + string_->SeqAsciiStringGet(i + from_))); i++; } hash_field_ = hasher.GetHashField(); diff --git a/src/objects.h b/src/objects.h index 74fb01257..7e531b28a 100644 --- a/src/objects.h +++ b/src/objects.h @@ -5766,6 +5766,7 @@ class StringHasher { uint32_t raw_running_hash_; uint32_t array_index_; bool is_array_index_; + bool is_first_char_; bool is_valid_; friend class TwoCharHashTableKey; }; @@ -6217,25 +6218,15 @@ class SeqString: public String { // Layout description. static const int kHeaderSize = String::kSize; - // Shortcuts for templates that know their string-type exactly. - bool IsExternalAsciiString() { - return false; - } - bool IsExternalTwoByteString() { - return false; - } - - private: DISALLOW_IMPLICIT_CONSTRUCTORS(SeqString); }; -// The SeqAsciiString class captures sequential ASCII string objects. -// Each character in the AsciiString is an ASCII character. +// The AsciiString class captures sequential ascii string objects. +// Each character in the AsciiString is an ascii character. class SeqAsciiString: public SeqString { public: - typedef char CharType; static const bool kHasAsciiEncoding = true; // Dispatched behavior. @@ -6250,15 +6241,6 @@ class SeqAsciiString: public SeqString { // Casting static inline SeqAsciiString* cast(Object* obj); - bool IsSeqAsciiString() { - ASSERT(this->Object::IsSeqAsciiString()); - return true; - } - bool IsSeqTwoByteString() { - ASSERT(this->Object::IsSeqAsciiString()); - return false; - } - // Garbage collection support. This method is called by the // garbage collector to compute the actual size of an AsciiString // instance. @@ -6288,12 +6270,10 @@ class SeqAsciiString: public SeqString { }; -// The SeqTwoByteString class captures sequential unicode string objects. +// The TwoByteString class captures sequential unicode string objects. // Each character in the TwoByteString is a two-byte uint16_t. class SeqTwoByteString: public SeqString { public: - typedef uc16 CharType; - static const bool kHasAsciiEncoding = false; // Dispatched behavior. @@ -6310,14 +6290,6 @@ class SeqTwoByteString: public SeqString { // Casting static inline SeqTwoByteString* cast(Object* obj); - bool IsSeqTwoByteString() { - ASSERT(this->Object::IsSeqTwoByteString()); - return true; - } - bool IsSeqAsciiString() { - ASSERT(this->Object::IsSeqTwoByteString()); - return false; - } // Garbage collection support. This method is called by the // garbage collector to compute the actual size of a TwoByteString @@ -6478,14 +6450,6 @@ class ExternalString: public String { STATIC_CHECK(kResourceOffset == Internals::kStringResourceOffset); - // Shortcuts for templates that know their string type exactly. - bool IsSeqAsciiString() { - return false; - } - bool IsSeqTwoByteString() { - return false; - } - private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalString); }; @@ -6495,8 +6459,6 @@ class ExternalString: public String { // ASCII string. class ExternalAsciiString: public ExternalString { public: - typedef char CharType; - static const bool kHasAsciiEncoding = true; typedef v8::String::ExternalAsciiStringResource Resource; @@ -6510,14 +6472,6 @@ class ExternalAsciiString: public ExternalString { // Casting. static inline ExternalAsciiString* cast(Object* obj); - bool IsExternalAsciiString() { - ASSERT(this->Object::IsExternalAsciiString()); - return true; - } - bool IsExternalTwoByteString() { - ASSERT(this->Object::IsExternalAsciiString()); - return false; - } // Garbage collection support. inline void ExternalAsciiStringIterateBody(ObjectVisitor* v); @@ -6538,11 +6492,10 @@ class ExternalAsciiString: public ExternalString { }; -// The ExternalTwoByteString class is an external string backed by a 16-bit -// character sequence. +// The ExternalTwoByteString class is an external string backed by a UTF-16 +// encoded string. class ExternalTwoByteString: public ExternalString { public: - typedef uc16 CharType; static const bool kHasAsciiEncoding = false; typedef v8::String::ExternalStringResource Resource; @@ -6559,14 +6512,6 @@ class ExternalTwoByteString: public ExternalString { // Casting. static inline ExternalTwoByteString* cast(Object* obj); - bool IsExternalTwoByteString() { - ASSERT(this->Object::IsExternalTwoByteString()); - return true; - } - bool IsExternalAsciiString() { - ASSERT(this->Object::IsExternalTwoByteString()); - return false; - } // Garbage collection support. inline void ExternalTwoByteStringIterateBody(ObjectVisitor* v); diff --git a/src/runtime.cc b/src/runtime.cc index 0e1ae4484..1f52a225d 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -9139,22 +9139,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { ASSERT_EQ(1, args.length()); CONVERT_ARG_CHECKED(String, source, 0); - source = FlattenGetString(source); - ASSERT(!source->IsConsString()); - ASSERT(!source->IsSlicedString()); + source = Handle(source->TryFlattenGetString()); + // Optimized fast case where we only have ascii characters. Handle result; - { - StringLock lock_representation(source); - if (source->IsSeqAsciiString()) { - result = JsonParser::Parse(source); - } else if (source->IsExternalTwoByteString()) { - result = JsonParser::Parse(source); - } else if (source->IsSeqTwoByteString()) { - result = JsonParser::Parse(source); - } else { - ASSERT(source->IsExternalAsciiString()); - result = JsonParser::Parse(source); - } + if (source->IsSeqAsciiString()) { + result = JsonParser::Parse(source); + } else { + result = JsonParser::Parse(source); } if (result.is_null()) { // Syntax error or stack overflow in scanner. diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 88b925f26..167c4cd15 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -33,7 +33,6 @@ #include "isolate.h" #include "compilation-cache.h" #include "execution.h" -#include "handles.h" #include "snapshot.h" #include "platform.h" #include "utils.h" @@ -15441,223 +15440,3 @@ THREADED_TEST(ForeignFunctionReceiver) { foreign_context.Dispose(); } - - - -class SimpleTestResource: public String::ExternalStringResource { - public: - explicit SimpleTestResource(const uint16_t* data) : data_(data), length_(0) { - while (data[length_] != 0) length_++; - } - virtual ~SimpleTestResource() { } - virtual const uint16_t* data() const { return data_; } - virtual size_t length() const { return length_; } - private: - const uint16_t* data_; - int length_; -}; - - -THREADED_TEST(StringLock) { - v8::HandleScope scope; - LocalContext env; - - i::Isolate* isolate = i::Isolate::Current(); - i::Heap* heap = isolate->heap(); - - // ASCII text of test strings. - const char* text = "Lorem ipsum dolor sic amet."; - const size_t kTextLength = 27; - CHECK(strlen(text) == kTextLength); - // UC16 version of string. - uint16_t uc16_text[kTextLength + 1]; - for (unsigned i = 0; i <= kTextLength; i++) { - uc16_text[i] = static_cast(text[i]); - } - - // Create some different strings and move them to old-space, - // so that externalization can succeede. - Local s1 = v8_str(text); - Local s2 = v8_str(text + 1); - Local s3 = v8_str(text + 2); - heap->CollectGarbage(i::NEW_SPACE); - heap->CollectGarbage(i::NEW_SPACE); - - SimpleTestResource* r1 = new SimpleTestResource(uc16_text); - SimpleTestResource* r2 = new SimpleTestResource(uc16_text + 1); - SimpleTestResource* r3 = new SimpleTestResource(uc16_text + 2); - - // Check that externalization works. - CHECK(!s1->IsExternal()); - CHECK(s1->MakeExternal(r1)); - CHECK(s1->IsExternal()); - - // Externalize while the string is locked. - - // Use the direct interface to string locking. - i::Handle s2i(v8::Utils::OpenHandle(*s2)); - CHECK(!heap->IsStringLocked(*s2i)); - LockString(s2i); // Use handle version, not Heap::LockString, to allow GC. - CHECK(isolate->heap()->IsStringLocked(*s2i)); - - CHECK(!s2->IsExternal()); - CHECK(!s2->MakeExternal(r2)); - CHECK(!s2->IsExternal()); - - CHECK(heap->IsStringLocked(*s2i)); - heap->UnlockString(*s2i); - CHECK(!heap->IsStringLocked(*s2i)); - - CHECK(!s2->IsExternal()); - CHECK(s2->MakeExternal(r2)); - CHECK(s2->IsExternal()); - - // Use the Handle-based scoped StringLock. - i::Handle s3i(v8::Utils::OpenHandle(*s3)); - { - CHECK(!heap->IsStringLocked(*s3i)); - i::StringLock lock(s3i); - CHECK(heap->IsStringLocked(*s3i)); - - CHECK(!s3->IsExternal()); - CHECK(!s3->MakeExternal(r3)); - CHECK(!s3->IsExternal()); - - CHECK(heap->IsStringLocked(*s3i)); - } - CHECK(!heap->IsStringLocked(*s3i)); - - CHECK(!s3->IsExternal()); - CHECK(s3->MakeExternal(r3)); - CHECK(s3->IsExternal()); -} - - -THREADED_TEST(MultiStringLock) { - v8::HandleScope scope; - LocalContext env; - i::Isolate* isolate = i::Isolate::Current(); - i::Heap* heap = isolate->heap(); - const char* text = "Lorem ipsum dolor sic amet."; - - const int N = 16; // Must be power of 2. - CHECK_GT(strlen(text), static_cast(N)); - - // Create a bunch of different strings. - i::Handle strings[N]; - - for (int i = 0; i < N; i++) { - Local s = v8_str(text + i); - strings[i] = v8::Utils::OpenHandle(*s); - } - - heap->CollectGarbage(i::NEW_SPACE); - heap->CollectGarbage(i::NEW_SPACE); - - // Check that start out are unlocked. - for (int i = 0; i < N; i++) { - CHECK(!heap->IsStringLocked(*strings[i])); - } - - // Lock them, one at a time. - for (int i = 0; i < N; i++) { - LockString(strings[i]); - for (int j = 0; j < N; j++) { - if (j <= i) { - CHECK(heap->IsStringLocked(*strings[j])); - } else { - CHECK(!heap->IsStringLocked(*strings[j])); - } - } - } - - // Unlock them in a slightly different order (not same as locking, - // nor the reverse order). - for (int i = 0; i < N; i++) { - int mix_i = i ^ 3; - heap->UnlockString(*strings[mix_i]); - for (int j = 0; j < N; j++) { - int unmix_j = j ^ 3; - if (unmix_j <= i) { - CHECK(!heap->IsStringLocked(*strings[j])); - } else { - CHECK(heap->IsStringLocked(*strings[j])); - } - } - } -} - - -THREADED_TEST(DuplicateStringLock) { - v8::HandleScope scope; - LocalContext env; - i::Isolate* isolate = i::Isolate::Current(); - i::Heap* heap = isolate->heap(); - const char* text = "Lorem ipsum dolor sic amet."; - - const int N = 16; // Must be power of 2. - CHECK_GT(strlen(text), static_cast(N)); - - // Create a bunch of different strings. - i::Handle strings[N]; - - for (int i = 0; i < N; i++) { - Local s = v8_str(text + i); - strings[i] = v8::Utils::OpenHandle(*s); - } - - heap->CollectGarbage(i::NEW_SPACE); - heap->CollectGarbage(i::NEW_SPACE); - - // Check that strings start out unlocked. - for (int i = 0; i < N; i++) { - CHECK(!heap->IsStringLocked(*strings[i])); - } - - // Lock them, one at a time. - for (int i = 0; i < N; i++) { - LockString(strings[i]); - for (int j = 0; j < N; j++) { - if (j <= i) { - CHECK(heap->IsStringLocked(*strings[j])); - } else { - CHECK(!heap->IsStringLocked(*strings[j])); - } - } - } - - // Lock the first half of them a second time. - for (int i = 0; i < N / 2; i++) { - LockString(strings[i]); - for (int j = 0; j < N; j++) { - CHECK(heap->IsStringLocked(*strings[j])); - } - } - - // Unlock them in a slightly different order (not same as locking, - // nor the reverse order). - for (int i = 0; i < N; i++) { - int mix_i = i ^ 3; - heap->UnlockString(*strings[mix_i]); - for (int j = 0; j < N; j++) { - int unmix_j = j ^ 3; - if (unmix_j <= i && j >= N / 2) { - CHECK(!heap->IsStringLocked(*strings[j])); - } else { - CHECK(heap->IsStringLocked(*strings[j])); - } - } - } - - // Unlock the first half again. - for (int i = 0; i < N / 2; i++) { - heap->UnlockString(*strings[i]); - for (int j = 0; j < N; j++) { - if (j <= i || j >= N/ 2) { - CHECK(!heap->IsStringLocked(*strings[j])); - } else { - CHECK(heap->IsStringLocked(*strings[j])); - } - } - } -} -- 2.34.1