if (isolate->string_tracker()->IsFreshUnusedString(obj)) {
return false;
}
- if (isolate->heap()->IsStringLocked(*obj)) {
- return false;
- }
if (isolate->heap()->IsInGCPostProcessing()) {
return false;
}
return CompileLazyHelper(&info, flag);
}
-
-void LockString(Handle<String> string) {
- CALL_HEAP_FUNCTION_VOID(string->GetHeap()->isolate(),
- string->GetHeap()->LockString(*string));
-}
-
-
-StringLock::StringLock(Handle<String> string) : string_(string) {
- LockString(string);
-}
-
-
-StringLock::~StringLock() {
- string_->GetHeap()->UnlockString(*string_);
-}
-
} } // namespace v8::internal
// ----------------------------------------------------------------------------
// 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<JSObject> object,
PropertyNormalizationMode mode,
void FlattenString(Handle<String> str);
// Flattens a string and returns the underlying external or sequential
-// string. Never returns a null handle.
+// string.
Handle<String> FlattenGetString(Handle<String> str);
Handle<Object> SetProperty(Handle<JSReceiver> object,
#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> string);
-
-// Scoped lock on a string.
-class StringLock {
- public:
- explicit StringLock(Handle<String> string);
- ~StringLock();
- private:
- Handle<String> string_;
-};
-
} } // namespace v8::internal
#endif // V8_HANDLES_H_
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 =
}
-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<FixedArray>(&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)]);
}
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) \
// 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);
namespace v8 {
namespace internal {
-// A simple JSON parser.
-template <typename StringType>
+// A simple json parser.
+template <bool seq_ascii>
class JsonParser BASE_EMBEDDED {
public:
static Handle<Object> Parse(Handle<String> source) {
- return JsonParser(Handle<StringType>::cast(source)).ParseJson();
+ return JsonParser().ParseJson(source);
}
static const int kEndOfString = -1;
private:
- typedef typename StringType::CharType SourceChar;
-
- explicit JsonParser(Handle<StringType> 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<Object> 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<Object> ParseJson(Handle<String> 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_);
}
}
// 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<uc32>(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();
}
}
// 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 <typename SinkStringType>
+ template <typename StringType, typename SinkChar>
Handle<String> SlowScanJsonString(Handle<String> prefix, int start, int end);
// A JSON number (production JSONNumber) is a subset of the valid JavaScript
static const int kInitialSpecialStringLength = 1024;
- Isolate* isolate_;
- Handle<StringType> source_;
- // Used for external strings, to avoid going through the resource on
- // every access.
- const SourceChar* characters_;
+
+ private:
+ Handle<String> source_;
int source_length_;
- int position_;
+ Handle<SeqAsciiString> seq_source_;
+
+ Isolate* isolate_;
uc32 c0_;
+ int position_;
};
-template <typename StringType>
-Handle<Object> JsonParser<StringType>::ParseJson() {
- // Initial position is right before the string.
- ASSERT(position_ == -1);
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJson(Handle<String> 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<SeqAsciiString>::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<Object> result = ParseJsonValue();
if (result.is_null() || c0_ != kEndOfString) {
// Parse failed. Current character is the unexpected token.
+
const char* message;
Factory* factory = isolate()->factory();
Handle<JSArray> array;
break;
}
- MessageLocation location(factory->NewScript(source_),
+ MessageLocation location(factory->NewScript(source),
position_,
position_ + 1);
Handle<Object> result = factory->NewSyntaxError(message, array);
// Parse any JSON value.
-template <typename StringType>
-Handle<Object> JsonParser<StringType>::ParseJsonValue() {
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJsonValue() {
switch (c0_) {
case '"':
return ParseJsonString();
// Parse a JSON object. Position must be right at '{'.
-template <typename StringType>
-Handle<Object> JsonParser<StringType>::ParseJsonObject() {
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJsonObject() {
Handle<JSFunction> object_constructor(
isolate()->global_context()->object_function());
Handle<JSObject> json_object =
isolate()->factory()->NewJSObject(object_constructor);
- ASSERT_EQ('{', c0_);
+ ASSERT_EQ(c0_, '{');
AdvanceSkipWhitespace();
if (c0_ != '}') {
}
// Parse a JSON array. Position must be right at '['.
-template <typename StringType>
-Handle<Object> JsonParser<StringType>::ParseJsonArray() {
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJsonArray() {
ZoneScope zone_scope(isolate(), DELETE_ON_EXIT);
ZoneList<Handle<Object> > elements(4);
ASSERT_EQ(c0_, '[');
}
-template <typename StringType>
-Handle<Object> JsonParser<StringType>::ParseJsonNumber() {
+template <bool seq_ascii>
+Handle<Object> JsonParser<seq_ascii>::ParseJsonNumber() {
bool negative = false;
int beg_pos = position_;
if (c0_ == '-') {
}
int length = position_ - beg_pos;
double number;
-
- Vector<const SourceChar> 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<const char> 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<char> buffer = Vector<char>::New(length);
+ String::WriteToFlat(*source_, buffer.start(), beg_pos, position_);
+ Vector<const char> result =
+ Vector<const char>(reinterpret_cast<const char*>(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);
}
// 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 <typename StringType>
-template <typename SinkStringType>
-Handle<String> JsonParser<StringType>::SlowScanJsonString(
+template <bool seq_ascii>
+template <typename StringType, typename SinkChar>
+Handle<String> JsonParser<seq_ascii>::SlowScanJsonString(
Handle<String> 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<SinkStringType> seq_str =
- NewRawString<SinkStringType>(isolate()->factory(),
- length);
+ Handle<StringType> seq_str = NewRawString<StringType>(isolate()->factory(),
+ length);
// Copy prefix into seq_str.
SinkChar* dest = seq_str->GetChars();
String::WriteToFlat(*prefix, dest, start, end);
if (c0_ < 0x20) return Handle<String>::null();
if (count >= length) {
// We need to create a longer sequential string for the result.
- return SlowScanJsonString<SinkStringType>(seq_str, 0, count);
+ return SlowScanJsonString<StringType, SinkChar>(seq_str, 0, count);
}
if (c0_ != '\\') {
// If the sink can contain UC16 characters, or source_ contains only
// 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<SeqTwoByteString>(seq_str, 0, count);
+ // StringType is SeqAsciiString and we just read a non-ASCII char.
+ return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str, 0, count);
}
} else {
- Advance(); // Advance past the '\'.
+ Advance(); // Advance past the \.
switch (c0_) {
case '"':
case '\\':
// StringType is SeqAsciiString and we just read a non-ASCII char.
position_ -= 6; // Rewind position_ to \ in \uxxxx.
Advance();
- return SlowScanJsonString<SeqTwoByteString>(seq_str,
- 0,
- count);
+ return SlowScanJsonString<SeqTwoByteString, uc16>(seq_str,
+ 0,
+ count);
}
}
default:
// Shrink seq_string length to count.
if (isolate()->heap()->InNewSpace(*seq_str)) {
isolate()->heap()->new_space()->
- template ShrinkStringAtAllocationBoundary<SinkStringType>(
+ template ShrinkStringAtAllocationBoundary<StringType>(
*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);
}
-template <typename StringType>
+template <bool seq_ascii>
template <bool is_symbol>
-Handle<String> JsonParser<StringType>::ScanJsonString() {
+Handle<String> JsonParser<seq_ascii>::ScanJsonString() {
ASSERT_EQ('"', c0_);
Advance();
if (c0_ == '"') {
// Check for control character (0x00-0x1f) or unterminated string (<0).
if (c0_ < 0x20) return Handle<String>::null();
if (c0_ != '\\') {
- if (c0_ <= kMaxAsciiCharCode) {
+ if (seq_ascii || c0_ <= kMaxAsciiCharCode) {
Advance();
} else {
- return SlowScanJsonString<SeqTwoByteString>(source_,
- beg_pos,
- position_);
+ return SlowScanJsonString<SeqTwoByteString, uc16>(source_,
+ beg_pos,
+ position_);
}
} else {
- return SlowScanJsonString<SeqAsciiString>(source_,
- beg_pos,
- position_);
+ return SlowScanJsonString<SeqAsciiString, char>(source_,
+ beg_pos,
+ position_);
}
} while (c0_ != '"');
int length = position_ - beg_pos;
Handle<String> result;
- if (is_symbol && source_->IsSeqAsciiString()) {
- result = isolate()->factory()->LookupAsciiSymbol(
- Handle<SeqAsciiString>::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();
return result;
}
-
-template <typename StringType>
-void JsonParser<StringType>::InitializeSource() { }
-
-
-template <>
-void JsonParser<ExternalAsciiString>::InitializeSource() {
- characters_ = source_->resource()->data();
-}
-
-
-template <>
-void JsonParser<ExternalTwoByteString>::InitializeSource() {
- characters_ = source_->resource()->data();
-}
-
-
-template <>
-uc32 JsonParser<SeqAsciiString>::GetChar(int pos) {
- return static_cast<uc32>(source_->SeqAsciiStringGet(pos));
-}
-
-
-template <>
-uc32 JsonParser<SeqTwoByteString>::GetChar(int pos) {
- return static_cast<uc32>(source_->SeqTwoByteStringGet(pos));
-}
-
-
-template <>
-uc32 JsonParser<ExternalAsciiString>::GetChar(int pos) {
- ASSERT(pos >= 0);
- ASSERT(pos < source_length_);
- return static_cast<uc32>(characters_[pos]);
-}
-
-
-template <>
-uc32 JsonParser<ExternalTwoByteString>::GetChar(int pos) {
- ASSERT(pos >= 0);
- ASSERT(pos < source_length_);
- return static_cast<uc32>(characters_[pos]);
-}
-
-
-template <>
-const char* JsonParser<SeqAsciiString>::GetChars() {
- return source_->GetChars();
-}
-
-
-template <>
-const uc16* JsonParser<SeqTwoByteString>::GetChars() {
- return source_->GetChars();
-}
-
-
-template <>
-const char* JsonParser<ExternalAsciiString>::GetChars() {
- return characters_;
-}
-
-
-template <>
-const uc16* JsonParser<ExternalTwoByteString>::GetChars() {
- return characters_;
-}
-
} } // namespace v8::internal
#endif // V8_JSON_PARSER_H_
#include "elements.h"
#include "objects.h"
-#include "char-predicates-inl.h"
#include "contexts.h"
#include "conversions-inl.h"
#include "heap.h"
raw_running_hash_(0),
array_index_(0),
is_array_index_(0 < length_ && length_ <= String::kMaxArrayIndexSize),
+ is_first_char_(true),
is_valid_(true) { }
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<unsigned>(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;
}
}
}
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);
}
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);
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.
// 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<uc32>(chars[i]));
+ hasher.AddCharacter(static_cast<uc32>(
+ string_->SeqAsciiStringGet(i + from_)));
i++;
}
// Process the remaining characters without updating the array
// index.
while (i < length_) {
- hasher.AddCharacterNoIndex(static_cast<uc32>(chars[i]));
+ hasher.AddCharacterNoIndex(static_cast<uc32>(
+ string_->SeqAsciiStringGet(i + from_)));
i++;
}
hash_field_ = hasher.GetHashField();
uint32_t raw_running_hash_;
uint32_t array_index_;
bool is_array_index_;
+ bool is_first_char_;
bool is_valid_;
friend class TwoCharHashTableKey;
};
// 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.
// 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.
};
-// 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.
// 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
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);
};
// ASCII string.
class ExternalAsciiString: public ExternalString {
public:
- typedef char CharType;
-
static const bool kHasAsciiEncoding = true;
typedef v8::String::ExternalAsciiStringResource Resource;
// 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);
};
-// 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;
// 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);
ASSERT_EQ(1, args.length());
CONVERT_ARG_CHECKED(String, source, 0);
- source = FlattenGetString(source);
- ASSERT(!source->IsConsString());
- ASSERT(!source->IsSlicedString());
+ source = Handle<String>(source->TryFlattenGetString());
+ // Optimized fast case where we only have ascii characters.
Handle<Object> result;
- {
- StringLock lock_representation(source);
- if (source->IsSeqAsciiString()) {
- result = JsonParser<SeqAsciiString>::Parse(source);
- } else if (source->IsExternalTwoByteString()) {
- result = JsonParser<ExternalTwoByteString>::Parse(source);
- } else if (source->IsSeqTwoByteString()) {
- result = JsonParser<SeqTwoByteString>::Parse(source);
- } else {
- ASSERT(source->IsExternalAsciiString());
- result = JsonParser<ExternalAsciiString>::Parse(source);
- }
+ if (source->IsSeqAsciiString()) {
+ result = JsonParser<true>::Parse(source);
+ } else {
+ result = JsonParser<false>::Parse(source);
}
if (result.is_null()) {
// Syntax error or stack overflow in scanner.
#include "isolate.h"
#include "compilation-cache.h"
#include "execution.h"
-#include "handles.h"
#include "snapshot.h"
#include "platform.h"
#include "utils.h"
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<uint16_t>(text[i]);
- }
-
- // Create some different strings and move them to old-space,
- // so that externalization can succeede.
- Local<String> s1 = v8_str(text);
- Local<String> s2 = v8_str(text + 1);
- Local<String> 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<i::String> 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<i::String> 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<size_t>(N));
-
- // Create a bunch of different strings.
- i::Handle<i::String> strings[N];
-
- for (int i = 0; i < N; i++) {
- Local<String> 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<size_t>(N));
-
- // Create a bunch of different strings.
- i::Handle<i::String> strings[N];
-
- for (int i = 0; i < N; i++) {
- Local<String> 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]));
- }
- }
- }
-}