Remove all uses of StringShape variables, since that has proven
to be error-prone and of little benefit in terms of performance. Review URL: http://codereview.chromium.org/45010 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1521 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
f060eb3293
commit
608a99a90c
10
src/api.cc
10
src/api.cc
@ -2034,7 +2034,7 @@ int String::WriteAscii(char* buffer, int start, int length) const {
|
||||
i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
// Flatten the string for efficiency. This applies whether we are
|
||||
// using StringInputBuffer or Get(i) to access the characters.
|
||||
str->TryFlattenIfNotFlat(i::StringShape(*str));
|
||||
str->TryFlattenIfNotFlat();
|
||||
int end = length;
|
||||
if ( (length == -1) || (length > str->length() - start) )
|
||||
end = str->length() - start;
|
||||
@ -2059,7 +2059,7 @@ int String::Write(uint16_t* buffer, int start, int length) const {
|
||||
i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
// Flatten the string for efficiency. This applies whether we are
|
||||
// using StringInputBuffer or Get(i) to access the characters.
|
||||
str->TryFlattenIfNotFlat(i::StringShape(*str));
|
||||
str->TryFlattenIfNotFlat();
|
||||
int end = length;
|
||||
if ( (length == -1) || (length > str->length() - start) )
|
||||
end = str->length() - start;
|
||||
@ -2077,16 +2077,14 @@ int String::Write(uint16_t* buffer, int start, int length) const {
|
||||
bool v8::String::IsExternal() const {
|
||||
EnsureInitialized("v8::String::IsExternal()");
|
||||
i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
i::StringShape shape(*str);
|
||||
return shape.IsExternalTwoByte();
|
||||
return i::StringShape(*str).IsExternalTwoByte();
|
||||
}
|
||||
|
||||
|
||||
bool v8::String::IsExternalAscii() const {
|
||||
EnsureInitialized("v8::String::IsExternalAscii()");
|
||||
i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
i::StringShape shape(*str);
|
||||
return shape.IsExternalAscii();
|
||||
return i::StringShape(*str).IsExternalAscii();
|
||||
}
|
||||
|
||||
|
||||
|
@ -402,8 +402,7 @@ bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
|
||||
"_Log"}
|
||||
};
|
||||
Handle<String> name = node->name();
|
||||
StringShape shape(*name);
|
||||
if (name->length(shape) > 0 && name->Get(shape, 0) == '_') {
|
||||
if (name->length() > 0 && name->Get(0) == '_') {
|
||||
for (unsigned i = 0;
|
||||
i < sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
|
||||
i++) {
|
||||
|
@ -55,8 +55,7 @@ static inline int GetChar(const char* str, int index) {
|
||||
|
||||
|
||||
static inline int GetChar(String* str, int index) {
|
||||
StringShape shape(str);
|
||||
return str->Get(shape, index);
|
||||
return str->Get(index);
|
||||
}
|
||||
|
||||
|
||||
@ -76,11 +75,10 @@ static inline const char* GetCString(const char* str, int index) {
|
||||
|
||||
|
||||
static inline const char* GetCString(String* str, int index) {
|
||||
StringShape shape(str);
|
||||
int length = str->length(shape);
|
||||
int length = str->length();
|
||||
char* result = NewArray<char>(length + 1);
|
||||
for (int i = index; i < length; i++) {
|
||||
uc16 c = str->Get(shape, i);
|
||||
uc16 c = str->Get(i);
|
||||
if (c <= 127) {
|
||||
result[i - index] = static_cast<char>(c);
|
||||
} else {
|
||||
@ -108,8 +106,7 @@ static inline bool IsSpace(const char* str, int index) {
|
||||
|
||||
|
||||
static inline bool IsSpace(String* str, int index) {
|
||||
StringShape shape(str);
|
||||
return Scanner::kIsWhiteSpace.get(str->Get(shape, index));
|
||||
return Scanner::kIsWhiteSpace.get(str->Get(index));
|
||||
}
|
||||
|
||||
|
||||
|
@ -90,11 +90,9 @@ Handle<String> Factory::NewRawTwoByteString(int length,
|
||||
|
||||
|
||||
Handle<String> Factory::NewConsString(Handle<String> first,
|
||||
StringShape first_shape,
|
||||
Handle<String> second,
|
||||
StringShape second_shape) {
|
||||
if (first->length(first_shape) == 0) return second;
|
||||
if (second->length(second_shape) == 0) return first;
|
||||
Handle<String> second) {
|
||||
if (first->length() == 0) return second;
|
||||
if (second->length() == 0) return first;
|
||||
CALL_HEAP_FUNCTION(Heap::AllocateConsString(*first, *second), String);
|
||||
}
|
||||
|
||||
|
@ -98,9 +98,7 @@ class Factory : public AllStatic {
|
||||
|
||||
// Create a new cons string object which consists of a pair of strings.
|
||||
static Handle<String> NewConsString(Handle<String> first,
|
||||
StringShape first_shape,
|
||||
Handle<String> second,
|
||||
StringShape second_shape);
|
||||
Handle<String> second);
|
||||
|
||||
// Create a new sliced string object which represents a substring of a
|
||||
// backing string.
|
||||
|
@ -186,8 +186,8 @@ void TransformToFastProperties(Handle<JSObject> object,
|
||||
|
||||
|
||||
void FlattenString(Handle<String> string) {
|
||||
CALL_HEAP_FUNCTION_VOID(string->TryFlattenIfNotFlat(StringShape(*string)));
|
||||
ASSERT(string->IsFlat(StringShape(*string)));
|
||||
CALL_HEAP_FUNCTION_VOID(string->TryFlattenIfNotFlat());
|
||||
ASSERT(string->IsFlat());
|
||||
}
|
||||
|
||||
|
||||
|
71
src/heap.cc
71
src/heap.cc
@ -230,7 +230,6 @@ void Heap::ReportStatisticsAfterGC() {
|
||||
|
||||
|
||||
void Heap::GarbageCollectionPrologue() {
|
||||
RegExpImpl::NewSpaceCollectionPrologue();
|
||||
gc_count_++;
|
||||
#ifdef DEBUG
|
||||
ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
|
||||
@ -475,7 +474,6 @@ void Heap::MarkCompactPrologue(bool is_compacting) {
|
||||
ClearKeyedLookupCache();
|
||||
|
||||
CompilationCache::MarkCompactPrologue();
|
||||
RegExpImpl::OldSpaceCollectionPrologue();
|
||||
|
||||
Top::MarkCompactPrologue(is_compacting);
|
||||
ThreadManager::MarkCompactPrologue(is_compacting);
|
||||
@ -1392,41 +1390,31 @@ Object* Heap::AllocateSharedFunctionInfo(Object* name) {
|
||||
|
||||
Object* Heap::AllocateConsString(String* first,
|
||||
String* second) {
|
||||
StringShape first_shape(first);
|
||||
StringShape second_shape(second);
|
||||
int first_length = first->length(first_shape);
|
||||
int second_length = second->length(second_shape);
|
||||
int first_length = first->length();
|
||||
int second_length = second->length();
|
||||
int length = first_length + second_length;
|
||||
bool is_ascii = first_shape.IsAsciiRepresentation()
|
||||
&& second_shape.IsAsciiRepresentation();
|
||||
bool is_ascii = StringShape(first).IsAsciiRepresentation()
|
||||
&& StringShape(second).IsAsciiRepresentation();
|
||||
|
||||
// If the resulting string is small make a flat string.
|
||||
if (length < String::kMinNonFlatLength) {
|
||||
ASSERT(first->IsFlat(first_shape));
|
||||
ASSERT(second->IsFlat(second_shape));
|
||||
ASSERT(first->IsFlat());
|
||||
ASSERT(second->IsFlat());
|
||||
if (is_ascii) {
|
||||
Object* result = AllocateRawAsciiString(length);
|
||||
if (result->IsFailure()) return result;
|
||||
// Copy the characters into the new object.
|
||||
char* dest = SeqAsciiString::cast(result)->GetChars();
|
||||
String::WriteToFlat(first, first_shape, dest, 0, first_length);
|
||||
String::WriteToFlat(second,
|
||||
second_shape,
|
||||
dest + first_length,
|
||||
0,
|
||||
second_length);
|
||||
String::WriteToFlat(first, dest, 0, first_length);
|
||||
String::WriteToFlat(second, dest + first_length, 0, second_length);
|
||||
return result;
|
||||
} else {
|
||||
Object* result = AllocateRawTwoByteString(length);
|
||||
if (result->IsFailure()) return result;
|
||||
// Copy the characters into the new object.
|
||||
uc16* dest = SeqTwoByteString::cast(result)->GetChars();
|
||||
String::WriteToFlat(first, first_shape, dest, 0, first_length);
|
||||
String::WriteToFlat(second,
|
||||
second_shape,
|
||||
dest + first_length,
|
||||
0,
|
||||
second_length);
|
||||
String::WriteToFlat(first, dest, 0, first_length);
|
||||
String::WriteToFlat(second, dest + first_length, 0, second_length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1457,25 +1445,24 @@ Object* Heap::AllocateConsString(String* first,
|
||||
Object* Heap::AllocateSlicedString(String* buffer,
|
||||
int start,
|
||||
int end) {
|
||||
StringShape buffer_shape(buffer);
|
||||
int length = end - start;
|
||||
|
||||
// If the resulting string is small make a sub string.
|
||||
if (end - start <= String::kMinNonFlatLength) {
|
||||
return Heap::AllocateSubString(buffer, buffer_shape, start, end);
|
||||
return Heap::AllocateSubString(buffer, start, end);
|
||||
}
|
||||
|
||||
Map* map;
|
||||
if (length <= String::kMaxShortStringSize) {
|
||||
map = buffer_shape.IsAsciiRepresentation() ?
|
||||
map = StringShape(buffer).IsAsciiRepresentation() ?
|
||||
short_sliced_ascii_string_map() :
|
||||
short_sliced_string_map();
|
||||
} else if (length <= String::kMaxMediumStringSize) {
|
||||
map = buffer_shape.IsAsciiRepresentation() ?
|
||||
map = StringShape(buffer).IsAsciiRepresentation() ?
|
||||
medium_sliced_ascii_string_map() :
|
||||
medium_sliced_string_map();
|
||||
} else {
|
||||
map = buffer_shape.IsAsciiRepresentation() ?
|
||||
map = StringShape(buffer).IsAsciiRepresentation() ?
|
||||
long_sliced_ascii_string_map() :
|
||||
long_sliced_string_map();
|
||||
}
|
||||
@ -1493,41 +1480,38 @@ Object* Heap::AllocateSlicedString(String* buffer,
|
||||
|
||||
|
||||
Object* Heap::AllocateSubString(String* buffer,
|
||||
StringShape buffer_shape,
|
||||
int start,
|
||||
int end) {
|
||||
int length = end - start;
|
||||
|
||||
if (length == 1) {
|
||||
return Heap::LookupSingleCharacterStringFromCode(
|
||||
buffer->Get(buffer_shape, start));
|
||||
buffer->Get(start));
|
||||
}
|
||||
|
||||
// Make an attempt to flatten the buffer to reduce access time.
|
||||
if (!buffer->IsFlat(buffer_shape)) {
|
||||
buffer->TryFlatten(buffer_shape);
|
||||
buffer_shape = StringShape(buffer);
|
||||
if (!buffer->IsFlat()) {
|
||||
buffer->TryFlatten();
|
||||
}
|
||||
|
||||
Object* result = buffer_shape.IsAsciiRepresentation()
|
||||
Object* result = StringShape(buffer).IsAsciiRepresentation()
|
||||
? AllocateRawAsciiString(length)
|
||||
: AllocateRawTwoByteString(length);
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
// Copy the characters into the new object.
|
||||
String* string_result = String::cast(result);
|
||||
StringShape result_shape(string_result);
|
||||
StringHasher hasher(length);
|
||||
int i = 0;
|
||||
for (; i < length && hasher.is_array_index(); i++) {
|
||||
uc32 c = buffer->Get(buffer_shape, start + i);
|
||||
uc32 c = buffer->Get(start + i);
|
||||
hasher.AddCharacter(c);
|
||||
string_result->Set(result_shape, i, c);
|
||||
string_result->Set(i, c);
|
||||
}
|
||||
for (; i < length; i++) {
|
||||
uc32 c = buffer->Get(buffer_shape, start + i);
|
||||
uc32 c = buffer->Get(start + i);
|
||||
hasher.AddCharacterNoIndex(c);
|
||||
string_result->Set(result_shape, i, c);
|
||||
string_result->Set(i, c);
|
||||
}
|
||||
string_result->set_length_field(hasher.GetHashField());
|
||||
return result;
|
||||
@ -1590,7 +1574,7 @@ Object* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
|
||||
Object* result = Heap::AllocateRawTwoByteString(1);
|
||||
if (result->IsFailure()) return result;
|
||||
String* answer = String::cast(result);
|
||||
answer->Set(StringShape(answer), 0, code);
|
||||
answer->Set(0, code);
|
||||
return answer;
|
||||
}
|
||||
|
||||
@ -2016,10 +2000,9 @@ Object* Heap::AllocateStringFromUtf8(Vector<const char> string,
|
||||
// Convert and copy the characters into the new object.
|
||||
String* string_result = String::cast(result);
|
||||
decoder->Reset(string.start(), string.length());
|
||||
StringShape result_shape(string_result);
|
||||
for (int i = 0; i < chars; i++) {
|
||||
uc32 r = decoder->GetNext();
|
||||
string_result->Set(result_shape, i, r);
|
||||
string_result->Set(i, r);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -2042,9 +2025,8 @@ Object* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
|
||||
// Copy the characters into the new object, which may be either ASCII or
|
||||
// UTF-16.
|
||||
String* string_result = String::cast(result);
|
||||
StringShape result_shape(string_result);
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
string_result->Set(result_shape, i, string[i]);
|
||||
string_result->Set(i, string[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -2163,14 +2145,13 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
|
||||
reinterpret_cast<HeapObject*>(result)->set_map(map);
|
||||
// The hash value contains the length of the string.
|
||||
String* answer = String::cast(result);
|
||||
StringShape answer_shape(answer);
|
||||
answer->set_length_field(length_field);
|
||||
|
||||
ASSERT_EQ(size, answer->Size());
|
||||
|
||||
// Fill in the characters.
|
||||
for (int i = 0; i < chars; i++) {
|
||||
answer->Set(answer_shape, i, buffer->GetNext());
|
||||
answer->Set(i, buffer->GetNext());
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
@ -532,7 +532,6 @@ class Heap : public AllStatic {
|
||||
// failed.
|
||||
// Please note this does not perform a garbage collection.
|
||||
static Object* AllocateSubString(String* buffer,
|
||||
StringShape buffer_shape,
|
||||
int start,
|
||||
int end);
|
||||
|
||||
|
@ -569,13 +569,12 @@ bool IrregexpInterpreter::Match(Handle<ByteArray> code_array,
|
||||
Handle<String> subject,
|
||||
int* registers,
|
||||
int start_position) {
|
||||
ASSERT(subject->IsFlat(StringShape(*subject)));
|
||||
ASSERT(subject->IsFlat());
|
||||
|
||||
AssertNoAllocation a;
|
||||
const byte* code_base = code_array->GetDataStartAddress();
|
||||
StringShape subject_shape(*subject);
|
||||
uc16 previous_char = '\n';
|
||||
if (subject_shape.IsAsciiRepresentation()) {
|
||||
if (StringShape(*subject).IsAsciiRepresentation()) {
|
||||
Vector<const char> subject_vector = subject->ToAsciiVector();
|
||||
if (start_position != 0) previous_char = subject_vector[start_position - 1];
|
||||
return RawMatch(code_base,
|
||||
|
@ -55,27 +55,6 @@
|
||||
namespace v8 { namespace internal {
|
||||
|
||||
|
||||
String* RegExpImpl::last_ascii_string_ = NULL;
|
||||
String* RegExpImpl::two_byte_cached_string_ = NULL;
|
||||
|
||||
|
||||
void RegExpImpl::NewSpaceCollectionPrologue() {
|
||||
// The two byte string is always in the old space. The Ascii string may be
|
||||
// in either place. If it is in the old space we don't need to do anything.
|
||||
if (Heap::InNewSpace(last_ascii_string_)) {
|
||||
// Invalidate the cache.
|
||||
last_ascii_string_ = NULL;
|
||||
two_byte_cached_string_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RegExpImpl::OldSpaceCollectionPrologue() {
|
||||
last_ascii_string_ = NULL;
|
||||
two_byte_cached_string_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor,
|
||||
Handle<String> pattern,
|
||||
Handle<String> flags,
|
||||
@ -92,55 +71,10 @@ Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor,
|
||||
}
|
||||
|
||||
|
||||
// Converts a source string to a 16 bit flat string or a SlicedString containing
|
||||
// a 16 bit flat string).
|
||||
Handle<String> RegExpImpl::CachedStringToTwoByte(Handle<String> subject) {
|
||||
if (*subject == last_ascii_string_) {
|
||||
ASSERT(two_byte_cached_string_ != NULL);
|
||||
return Handle<String>(String::cast(two_byte_cached_string_));
|
||||
}
|
||||
Handle<String> two_byte_string = StringToTwoByte(subject);
|
||||
last_ascii_string_ = *subject;
|
||||
two_byte_cached_string_ = *two_byte_string;
|
||||
return two_byte_string;
|
||||
}
|
||||
|
||||
|
||||
// Converts a source string to a 16 bit flat string or a SlicedString containing
|
||||
// a 16 bit flat string).
|
||||
Handle<String> RegExpImpl::StringToTwoByte(Handle<String> pattern) {
|
||||
StringShape shape(*pattern);
|
||||
if (!pattern->IsFlat(shape)) {
|
||||
FlattenString(pattern);
|
||||
shape = StringShape(*pattern);
|
||||
}
|
||||
Handle<String> flat_string(shape.IsCons() ?
|
||||
String::cast(ConsString::cast(*pattern)->first()) :
|
||||
*pattern);
|
||||
ASSERT(flat_string->IsString());
|
||||
StringShape flat_shape(*flat_string);
|
||||
ASSERT(!flat_shape.IsCons());
|
||||
ASSERT(flat_shape.IsSequential() ||
|
||||
flat_shape.IsSliced() ||
|
||||
flat_shape.IsExternal());
|
||||
if (!flat_shape.IsAsciiRepresentation()) {
|
||||
return flat_string;
|
||||
}
|
||||
|
||||
int len = flat_string->length(flat_shape);
|
||||
Handle<String> two_byte_string =
|
||||
Factory::NewRawTwoByteString(len, TENURED);
|
||||
uc16* dest = SeqTwoByteString::cast(*two_byte_string)->GetChars();
|
||||
String::WriteToFlat(*flat_string, flat_shape, dest, 0, len);
|
||||
return two_byte_string;
|
||||
}
|
||||
|
||||
|
||||
static JSRegExp::Flags RegExpFlagsFromString(Handle<String> str) {
|
||||
int flags = JSRegExp::NONE;
|
||||
StringShape shape(*str);
|
||||
for (int i = 0; i < str->length(shape); i++) {
|
||||
switch (str->Get(shape, i)) {
|
||||
for (int i = 0; i < str->length(); i++) {
|
||||
switch (str->Get(i)) {
|
||||
case 'i':
|
||||
flags |= JSRegExp::IGNORE_CASE;
|
||||
break;
|
||||
@ -421,7 +355,7 @@ bool RegExpImpl::EnsureCompiledIrregexp(Handle<JSRegExp> re,
|
||||
JSRegExp::Flags flags = re->GetFlags();
|
||||
|
||||
Handle<String> pattern(re->Pattern());
|
||||
if (!pattern->IsFlat(StringShape(*pattern))) {
|
||||
if (!pattern->IsFlat()) {
|
||||
FlattenString(pattern);
|
||||
}
|
||||
|
||||
@ -552,7 +486,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> regexp,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!subject->IsFlat(StringShape(*subject))) {
|
||||
if (!subject->IsFlat()) {
|
||||
FlattenString(subject);
|
||||
}
|
||||
|
||||
@ -590,7 +524,7 @@ Handle<Object> RegExpImpl::IrregexpExecGlobal(Handle<JSRegExp> regexp,
|
||||
int result_length = 0;
|
||||
Handle<Object> matches;
|
||||
|
||||
if (!subject->IsFlat(StringShape(*subject))) {
|
||||
if (!subject->IsFlat()) {
|
||||
FlattenString(subject);
|
||||
}
|
||||
|
||||
@ -659,9 +593,8 @@ Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> regexp,
|
||||
int previous_index,
|
||||
int* offsets_vector,
|
||||
int offsets_vector_length) {
|
||||
StringShape shape(*subject);
|
||||
ASSERT(subject->IsFlat(shape));
|
||||
bool is_ascii = shape.IsAsciiRepresentation();
|
||||
ASSERT(subject->IsFlat());
|
||||
bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
|
||||
bool rc;
|
||||
|
||||
Handle<String> original_subject = subject;
|
||||
|
@ -108,15 +108,6 @@ class RegExpImpl {
|
||||
Handle<String> subject,
|
||||
Handle<JSArray> lastMatchInfo);
|
||||
|
||||
static void NewSpaceCollectionPrologue();
|
||||
static void OldSpaceCollectionPrologue();
|
||||
|
||||
// Converts a source string to a 16 bit flat string. The string
|
||||
// will be either sequential or it will be a SlicedString backed
|
||||
// by a flat string.
|
||||
static Handle<String> StringToTwoByte(Handle<String> pattern);
|
||||
static Handle<String> CachedStringToTwoByte(Handle<String> pattern);
|
||||
|
||||
// Offsets in the lastMatchInfo array.
|
||||
static const int kLastCaptureCount = 0;
|
||||
static const int kLastSubject = 1;
|
||||
|
16
src/log.cc
16
src/log.cc
@ -362,29 +362,27 @@ void LogMessageBuilder::Append(const char c) {
|
||||
// Append a heap string.
|
||||
void LogMessageBuilder::Append(String* str) {
|
||||
AssertNoAllocation no_heap_allocation; // Ensure string stay valid.
|
||||
StringShape shape(str);
|
||||
int length = str->length(shape);
|
||||
int length = str->length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
Append(static_cast<char>(str->Get(shape, i)));
|
||||
Append(static_cast<char>(str->Get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
|
||||
AssertNoAllocation no_heap_allocation; // Ensure string stay valid.
|
||||
StringShape shape(str);
|
||||
int len = str->length(shape);
|
||||
int len = str->length();
|
||||
if (len > 0x1000)
|
||||
len = 0x1000;
|
||||
if (show_impl_info) {
|
||||
Append(shape.IsAsciiRepresentation() ? 'a' : '2');
|
||||
if (shape.IsExternal())
|
||||
Append(StringShape(str).IsAsciiRepresentation() ? 'a' : '2');
|
||||
if (StringShape(str).IsExternal())
|
||||
Append('e');
|
||||
if (shape.IsSymbol())
|
||||
if (StringShape(str).IsSymbol())
|
||||
Append('#');
|
||||
Append(":%i:", str->length());
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
uc32 c = str->Get(shape, i);
|
||||
uc32 c = str->Get(i);
|
||||
if (c > 0xff) {
|
||||
Append("\\u%04x", c);
|
||||
} else if (c < 32 || c > 126) {
|
||||
|
@ -491,20 +491,19 @@ void JSValue::JSValueVerify() {
|
||||
|
||||
|
||||
void String::StringPrint() {
|
||||
StringShape shape(this);
|
||||
if (shape.IsSymbol()) {
|
||||
if (StringShape(this).IsSymbol()) {
|
||||
PrintF("#");
|
||||
} else if (shape.IsCons()) {
|
||||
} else if (StringShape(this).IsCons()) {
|
||||
PrintF("c\"");
|
||||
} else {
|
||||
PrintF("\"");
|
||||
}
|
||||
|
||||
for (int i = 0; i < length(); i++) {
|
||||
PrintF("%c", Get(shape, i));
|
||||
PrintF("%c", Get(i));
|
||||
}
|
||||
|
||||
if (!shape.IsSymbol()) PrintF("\"");
|
||||
if (!StringShape(this).IsSymbol()) PrintF("\"");
|
||||
}
|
||||
|
||||
|
||||
|
@ -143,15 +143,15 @@ bool Object::IsSeqString() {
|
||||
|
||||
bool Object::IsSeqAsciiString() {
|
||||
if (!IsString()) return false;
|
||||
StringShape shape(String::cast(this));
|
||||
return shape.IsSequential() && shape.IsAsciiRepresentation();
|
||||
return StringShape(String::cast(this)).IsSequential() &&
|
||||
StringShape(String::cast(this)).IsAsciiRepresentation();
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsSeqTwoByteString() {
|
||||
if (!IsString()) return false;
|
||||
StringShape shape(String::cast(this));
|
||||
return shape.IsSequential() && shape.IsTwoByteRepresentation();
|
||||
return StringShape(String::cast(this)).IsSequential() &&
|
||||
StringShape(String::cast(this)).IsTwoByteRepresentation();
|
||||
}
|
||||
|
||||
|
||||
@ -163,15 +163,15 @@ bool Object::IsExternalString() {
|
||||
|
||||
bool Object::IsExternalAsciiString() {
|
||||
if (!IsString()) return false;
|
||||
StringShape shape(String::cast(this));
|
||||
return shape.IsExternal() && shape.IsAsciiRepresentation();
|
||||
return StringShape(String::cast(this)).IsExternal() &&
|
||||
StringShape(String::cast(this)).IsAsciiRepresentation();
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsExternalTwoByteString() {
|
||||
if (!IsString()) return false;
|
||||
StringShape shape(String::cast(this));
|
||||
return shape.IsExternal() && shape.IsTwoByteRepresentation();
|
||||
return StringShape(String::cast(this)).IsExternal() &&
|
||||
StringShape(String::cast(this)).IsTwoByteRepresentation();
|
||||
}
|
||||
|
||||
|
||||
@ -1243,15 +1243,13 @@ void DescriptorArray::fast_swap(FixedArray* array, int first, int second) {
|
||||
int DescriptorArray::Search(String* name) {
|
||||
SLOW_ASSERT(IsSortedNoDuplicates());
|
||||
|
||||
StringShape shape(name);
|
||||
|
||||
// Check for empty descriptor array.
|
||||
int nof = number_of_descriptors();
|
||||
if (nof == 0) return kNotFound;
|
||||
|
||||
// Fast case: do linear search for small arrays.
|
||||
const int kMaxElementsForLinearSearch = 8;
|
||||
if (shape.IsSymbol() && nof < kMaxElementsForLinearSearch) {
|
||||
if (StringShape(name).IsSymbol() && nof < kMaxElementsForLinearSearch) {
|
||||
return LinearSearch(name, nof);
|
||||
}
|
||||
|
||||
@ -1392,27 +1390,21 @@ INT_ACCESSORS(Array, length, kLengthOffset)
|
||||
|
||||
bool String::Equals(String* other) {
|
||||
if (other == this) return true;
|
||||
StringShape this_shape(this);
|
||||
StringShape other_shape(other);
|
||||
if (this_shape.IsSymbol() && other_shape.IsSymbol()) return false;
|
||||
return SlowEquals(this_shape, other, other_shape);
|
||||
if (StringShape(this).IsSymbol() && StringShape(other).IsSymbol()) {
|
||||
return false;
|
||||
}
|
||||
return SlowEquals(other);
|
||||
}
|
||||
|
||||
|
||||
int String::length(StringShape shape) {
|
||||
ASSERT(shape.type() == StringShape(this).type());
|
||||
int String::length() {
|
||||
uint32_t len = READ_INT_FIELD(this, kLengthOffset);
|
||||
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
return len >> (shape.size_tag() + kLongLengthShift);
|
||||
}
|
||||
|
||||
|
||||
int String::length() {
|
||||
return length(StringShape(this));
|
||||
return len >> (StringShape(this).size_tag() + kLongLengthShift);
|
||||
}
|
||||
|
||||
|
||||
@ -1421,10 +1413,9 @@ void String::set_length(int value) {
|
||||
ASSERT(kMediumStringTag + kLongLengthShift == kMediumLengthShift);
|
||||
ASSERT(kLongStringTag == 0);
|
||||
|
||||
StringShape shape(this);
|
||||
WRITE_INT_FIELD(this,
|
||||
kLengthOffset,
|
||||
value << (shape.size_tag() + kLongLengthShift));
|
||||
value << (StringShape(this).size_tag() + kLongLengthShift));
|
||||
}
|
||||
|
||||
|
||||
@ -1438,21 +1429,19 @@ void String::set_length_field(uint32_t value) {
|
||||
}
|
||||
|
||||
|
||||
Object* String::TryFlattenIfNotFlat(StringShape shape) {
|
||||
ASSERT(shape.type() == StringShape(this).type());
|
||||
Object* String::TryFlattenIfNotFlat() {
|
||||
// We don't need to flatten strings that are already flat. Since this code
|
||||
// is inlined, it can be helpful in the flat case to not call out to Flatten.
|
||||
if (!IsFlat(shape)) {
|
||||
return TryFlatten(shape);
|
||||
if (!IsFlat()) {
|
||||
return TryFlatten();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
uint16_t String::Get(StringShape shape, int index) {
|
||||
ASSERT(shape.type() == StringShape(this).type());
|
||||
ASSERT(index >= 0 && index < length(shape));
|
||||
switch (shape.full_representation_tag()) {
|
||||
uint16_t String::Get(int index) {
|
||||
ASSERT(index >= 0 && index < length());
|
||||
switch (StringShape(this).full_representation_tag()) {
|
||||
case kSeqStringTag | kAsciiStringTag:
|
||||
return SeqAsciiString::cast(this)->SeqAsciiStringGet(index);
|
||||
case kSeqStringTag | kTwoByteStringTag:
|
||||
@ -1476,29 +1465,26 @@ uint16_t String::Get(StringShape shape, int index) {
|
||||
}
|
||||
|
||||
|
||||
void String::Set(StringShape shape, int index, uint16_t value) {
|
||||
ASSERT(shape.type() == StringShape(this).type());
|
||||
ASSERT(shape.type() == StringShape(this).type());
|
||||
ASSERT(index >= 0 && index < length(shape));
|
||||
ASSERT(shape.IsSequential());
|
||||
void String::Set(int index, uint16_t value) {
|
||||
ASSERT(index >= 0 && index < length());
|
||||
ASSERT(StringShape(this).IsSequential());
|
||||
|
||||
return shape.IsAsciiRepresentation()
|
||||
return StringShape(this).IsAsciiRepresentation()
|
||||
? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value)
|
||||
: SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value);
|
||||
}
|
||||
|
||||
|
||||
bool String::IsFlat(StringShape shape) {
|
||||
ASSERT(shape.type() == StringShape(this).type());
|
||||
switch (shape.representation_tag()) {
|
||||
bool String::IsFlat() {
|
||||
switch (StringShape(this).representation_tag()) {
|
||||
case kConsStringTag: {
|
||||
String* second = ConsString::cast(this)->second();
|
||||
// Only flattened strings have second part empty.
|
||||
return second->length() == 0;
|
||||
}
|
||||
case kSlicedStringTag: {
|
||||
StringShape slice_shape = StringShape(SlicedString::cast(this)->buffer());
|
||||
StringRepresentationTag tag = slice_shape.representation_tag();
|
||||
StringRepresentationTag tag =
|
||||
StringShape(SlicedString::cast(this)->buffer()).representation_tag();
|
||||
return tag == kSeqStringTag || tag == kExternalStringTag;
|
||||
}
|
||||
default:
|
||||
@ -1552,7 +1538,7 @@ void SeqTwoByteString::SeqTwoByteStringSet(int index, uint16_t value) {
|
||||
}
|
||||
|
||||
|
||||
int SeqTwoByteString::SeqTwoByteStringSize(StringShape shape) {
|
||||
int SeqTwoByteString::SeqTwoByteStringSize(InstanceType instance_type) {
|
||||
uint32_t length = READ_INT_FIELD(this, kLengthOffset);
|
||||
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
@ -1561,13 +1547,13 @@ int SeqTwoByteString::SeqTwoByteStringSize(StringShape shape) {
|
||||
|
||||
// Use the map (and not 'this') to compute the size tag, since
|
||||
// TwoByteStringSize is called during GC when maps are encoded.
|
||||
length >>= shape.size_tag() + kLongLengthShift;
|
||||
length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
|
||||
|
||||
return SizeFor(length);
|
||||
}
|
||||
|
||||
|
||||
int SeqAsciiString::SeqAsciiStringSize(StringShape shape) {
|
||||
int SeqAsciiString::SeqAsciiStringSize(InstanceType instance_type) {
|
||||
uint32_t length = READ_INT_FIELD(this, kLengthOffset);
|
||||
|
||||
ASSERT(kShortStringTag + kLongLengthShift == kShortLengthShift);
|
||||
@ -1576,7 +1562,7 @@ int SeqAsciiString::SeqAsciiStringSize(StringShape shape) {
|
||||
|
||||
// Use the map (and not 'this') to compute the size tag, since
|
||||
// AsciiStringSize is called during GC when maps are encoded.
|
||||
length >>= shape.size_tag() + kLongLengthShift;
|
||||
length >>= StringShape(instance_type).size_tag() + kLongLengthShift;
|
||||
|
||||
return SizeFor(length);
|
||||
}
|
||||
|
234
src/objects.cc
234
src/objects.cc
@ -575,10 +575,9 @@ Failure* Failure::RetryAfterGC(int requested_bytes, AllocationSpace space) {
|
||||
// We don't use the BBC's overcorrect "an historic occasion" though if
|
||||
// you speak a dialect you may well say "an 'istoric occasion".
|
||||
static bool AnWord(String* str) {
|
||||
StringShape shape(str);
|
||||
if (str->length(shape) == 0) return false; // A nothing.
|
||||
int c0 = str->Get(shape, 0);
|
||||
int c1 = str->length(shape) > 1 ? str->Get(shape, 1) : 0;
|
||||
if (str->length() == 0) return false; // A nothing.
|
||||
int c0 = str->Get(0);
|
||||
int c1 = str->length() > 1 ? str->Get(1) : 0;
|
||||
if (c0 == 'U') {
|
||||
if (c1 > 'Z') {
|
||||
return true; // An Umpire, but a UTF8String, a U.
|
||||
@ -594,7 +593,7 @@ static bool AnWord(String* str) {
|
||||
}
|
||||
|
||||
|
||||
Object* String::TryFlatten(StringShape shape) {
|
||||
Object* String::TryFlatten() {
|
||||
#ifdef DEBUG
|
||||
// Do not attempt to flatten in debug mode when allocation is not
|
||||
// allowed. This is to avoid an assertion failure when allocating.
|
||||
@ -603,7 +602,7 @@ Object* String::TryFlatten(StringShape shape) {
|
||||
if (!Heap::IsAllocationAllowed()) return this;
|
||||
#endif
|
||||
|
||||
switch (shape.representation_tag()) {
|
||||
switch (StringShape(this).representation_tag()) {
|
||||
case kSlicedStringTag: {
|
||||
SlicedString* ss = SlicedString::cast(this);
|
||||
// The SlicedString constructor should ensure that there are no
|
||||
@ -611,7 +610,7 @@ Object* String::TryFlatten(StringShape shape) {
|
||||
// SlicedStrings.
|
||||
String* buf = ss->buffer();
|
||||
ASSERT(!buf->IsSlicedString());
|
||||
Object* ok = buf->TryFlatten(StringShape(buf));
|
||||
Object* ok = buf->TryFlatten();
|
||||
if (ok->IsFailure()) return ok;
|
||||
// Under certain circumstances (TryFlattenIfNotFlat fails in
|
||||
// String::Slice) we can have a cons string under a slice.
|
||||
@ -630,21 +629,19 @@ Object* String::TryFlatten(StringShape shape) {
|
||||
// cons string is in old space. It can never get GCed until there is
|
||||
// an old space GC.
|
||||
PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED : TENURED;
|
||||
int len = length(shape);
|
||||
int len = length();
|
||||
Object* object;
|
||||
String* result;
|
||||
if (shape.IsAsciiRepresentation()) {
|
||||
if (StringShape(this).IsAsciiRepresentation()) {
|
||||
object = Heap::AllocateRawAsciiString(len, tenure);
|
||||
if (object->IsFailure()) return object;
|
||||
result = String::cast(object);
|
||||
String* first = cs->first();
|
||||
StringShape first_shape(first);
|
||||
int first_length = first->length(first_shape);
|
||||
int first_length = first->length();
|
||||
char* dest = SeqAsciiString::cast(result)->GetChars();
|
||||
WriteToFlat(first, first_shape, dest, 0, first_length);
|
||||
WriteToFlat(first, dest, 0, first_length);
|
||||
String* second = cs->second();
|
||||
WriteToFlat(second,
|
||||
StringShape(second),
|
||||
dest + first_length,
|
||||
0,
|
||||
len - first_length);
|
||||
@ -654,12 +651,10 @@ Object* String::TryFlatten(StringShape shape) {
|
||||
result = String::cast(object);
|
||||
uc16* dest = SeqTwoByteString::cast(result)->GetChars();
|
||||
String* first = cs->first();
|
||||
StringShape first_shape(first);
|
||||
int first_length = first->length(first_shape);
|
||||
WriteToFlat(first, first_shape, dest, 0, first_length);
|
||||
int first_length = first->length();
|
||||
WriteToFlat(first, dest, 0, first_length);
|
||||
String* second = cs->second();
|
||||
WriteToFlat(second,
|
||||
StringShape(second),
|
||||
dest + first_length,
|
||||
0,
|
||||
len - first_length);
|
||||
@ -761,8 +756,7 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
|
||||
|
||||
|
||||
void String::StringShortPrint(StringStream* accumulator) {
|
||||
StringShape shape(this);
|
||||
int len = length(shape);
|
||||
int len = length();
|
||||
if (len > kMaxMediumStringSize) {
|
||||
accumulator->Add("<Very long string[%u]>", len);
|
||||
return;
|
||||
@ -790,7 +784,7 @@ void String::StringShortPrint(StringStream* accumulator) {
|
||||
}
|
||||
buf.Reset(this);
|
||||
if (ascii) {
|
||||
accumulator->Add("<String[%u]: ", length(shape));
|
||||
accumulator->Add("<String[%u]: ", length());
|
||||
for (int i = 0; i < len; i++) {
|
||||
accumulator->Put(buf.GetNext());
|
||||
}
|
||||
@ -798,7 +792,7 @@ void String::StringShortPrint(StringStream* accumulator) {
|
||||
} else {
|
||||
// Backslash indicates that the string contains control
|
||||
// characters and that backslashes are therefore escaped.
|
||||
accumulator->Add("<String[%u]\\: ", length(shape));
|
||||
accumulator->Add("<String[%u]\\: ", length());
|
||||
for (int i = 0; i < len; i++) {
|
||||
int c = buf.GetNext();
|
||||
if (c == '\n') {
|
||||
@ -979,12 +973,12 @@ int HeapObject::SlowSizeFromMap(Map* map) {
|
||||
|
||||
if (instance_type < FIRST_NONSTRING_TYPE
|
||||
&& (StringShape(instance_type).IsSequential())) {
|
||||
StringShape shape(instance_type);
|
||||
if (shape.IsAsciiRepresentation()) {
|
||||
return reinterpret_cast<SeqAsciiString*>(this)->SeqAsciiStringSize(shape);
|
||||
if (StringShape(instance_type).IsAsciiRepresentation()) {
|
||||
SeqAsciiString* seq_ascii_this = reinterpret_cast<SeqAsciiString*>(this);
|
||||
return seq_ascii_this->SeqAsciiStringSize(instance_type);
|
||||
} else {
|
||||
SeqTwoByteString* self = reinterpret_cast<SeqTwoByteString*>(this);
|
||||
return self->SeqTwoByteStringSize(shape);
|
||||
return self->SeqTwoByteStringSize(instance_type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2559,7 +2553,7 @@ Object* JSObject::DefineGetterSetter(String* name,
|
||||
}
|
||||
|
||||
// Try to flatten before operating on the string.
|
||||
name->TryFlattenIfNotFlat(StringShape(name));
|
||||
name->TryFlattenIfNotFlat();
|
||||
|
||||
// Check if there is an API defined callback object which prohibits
|
||||
// callback overwriting in this object or it's prototype chain.
|
||||
@ -3274,13 +3268,12 @@ bool String::LooksValid() {
|
||||
|
||||
|
||||
int String::Utf8Length() {
|
||||
StringShape shape(this);
|
||||
if (shape.IsAsciiRepresentation()) return length(shape);
|
||||
if (StringShape(this).IsAsciiRepresentation()) return length();
|
||||
// Attempt to flatten before accessing the string. It probably
|
||||
// doesn't make Utf8Length faster, but it is very likely that
|
||||
// the string will be accessed later (for example by WriteUtf8)
|
||||
// so it's still a good idea.
|
||||
TryFlattenIfNotFlat(shape); // shape is now no longer valid.
|
||||
TryFlattenIfNotFlat();
|
||||
Access<StringInputBuffer> buffer(&string_input_buffer);
|
||||
buffer->Reset(0, this);
|
||||
int result = 0;
|
||||
@ -3291,26 +3284,23 @@ int String::Utf8Length() {
|
||||
|
||||
|
||||
Vector<const char> String::ToAsciiVector() {
|
||||
StringShape shape(this);
|
||||
ASSERT(shape.IsAsciiRepresentation());
|
||||
ASSERT(IsFlat(shape));
|
||||
ASSERT(StringShape(this).IsAsciiRepresentation());
|
||||
ASSERT(IsFlat());
|
||||
|
||||
int offset = 0;
|
||||
int length = this->length(shape);
|
||||
StringRepresentationTag string_tag = shape.representation_tag();
|
||||
int length = this->length();
|
||||
StringRepresentationTag string_tag = StringShape(this).representation_tag();
|
||||
String* string = this;
|
||||
if (string_tag == kSlicedStringTag) {
|
||||
SlicedString* sliced = SlicedString::cast(string);
|
||||
offset += sliced->start();
|
||||
string = sliced->buffer();
|
||||
shape = StringShape(string);
|
||||
string_tag = shape.representation_tag();
|
||||
string_tag = StringShape(string).representation_tag();
|
||||
} else if (string_tag == kConsStringTag) {
|
||||
ConsString* cons = ConsString::cast(string);
|
||||
ASSERT(cons->second()->length(StringShape(cons->second())) == 0);
|
||||
ASSERT(cons->second()->length() == 0);
|
||||
string = cons->first();
|
||||
shape = StringShape(string);
|
||||
string_tag = shape.representation_tag();
|
||||
string_tag = StringShape(string).representation_tag();
|
||||
}
|
||||
if (string_tag == kSeqStringTag) {
|
||||
SeqAsciiString* seq = SeqAsciiString::cast(string);
|
||||
@ -3325,26 +3315,23 @@ Vector<const char> String::ToAsciiVector() {
|
||||
|
||||
|
||||
Vector<const uc16> String::ToUC16Vector() {
|
||||
StringShape shape(this);
|
||||
ASSERT(shape.IsTwoByteRepresentation());
|
||||
ASSERT(IsFlat(shape));
|
||||
ASSERT(StringShape(this).IsTwoByteRepresentation());
|
||||
ASSERT(IsFlat());
|
||||
|
||||
int offset = 0;
|
||||
int length = this->length(shape);
|
||||
StringRepresentationTag string_tag = shape.representation_tag();
|
||||
int length = this->length();
|
||||
StringRepresentationTag string_tag = StringShape(this).representation_tag();
|
||||
String* string = this;
|
||||
if (string_tag == kSlicedStringTag) {
|
||||
SlicedString* sliced = SlicedString::cast(string);
|
||||
offset += sliced->start();
|
||||
string = String::cast(sliced->buffer());
|
||||
shape = StringShape(string);
|
||||
string_tag = shape.representation_tag();
|
||||
string_tag = StringShape(string).representation_tag();
|
||||
} else if (string_tag == kConsStringTag) {
|
||||
ConsString* cons = ConsString::cast(string);
|
||||
ASSERT(cons->second()->length(StringShape(cons->second())) == 0);
|
||||
ASSERT(cons->second()->length() == 0);
|
||||
string = cons->first();
|
||||
shape = StringShape(string);
|
||||
string_tag = shape.representation_tag();
|
||||
string_tag = StringShape(string).representation_tag();
|
||||
}
|
||||
if (string_tag == kSeqStringTag) {
|
||||
SeqTwoByteString* seq = SeqTwoByteString::cast(string);
|
||||
@ -3424,9 +3411,8 @@ const uc16* String::GetTwoByteData() {
|
||||
|
||||
|
||||
const uc16* String::GetTwoByteData(unsigned start) {
|
||||
StringShape shape(this);
|
||||
ASSERT(!shape.IsAsciiRepresentation());
|
||||
switch (shape.representation_tag()) {
|
||||
ASSERT(!StringShape(this).IsAsciiRepresentation());
|
||||
switch (StringShape(this).representation_tag()) {
|
||||
case kSeqStringTag:
|
||||
return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
|
||||
case kExternalStringTag:
|
||||
@ -3438,7 +3424,7 @@ const uc16* String::GetTwoByteData(unsigned start) {
|
||||
if (StringShape(buffer).IsCons()) {
|
||||
ConsString* cs = ConsString::cast(buffer);
|
||||
// Flattened string.
|
||||
ASSERT(cs->second()->length(StringShape(cs->second())) == 0);
|
||||
ASSERT(cs->second()->length() == 0);
|
||||
buffer = cs->first();
|
||||
}
|
||||
return buffer->GetTwoByteData(start + sliced_string->start());
|
||||
@ -3541,8 +3527,7 @@ const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
|
||||
|
||||
while (true) {
|
||||
String* left = current->first();
|
||||
StringShape left_shape(left);
|
||||
unsigned left_length = (unsigned)left->length(left_shape);
|
||||
unsigned left_length = (unsigned)left->length();
|
||||
if (left_length > offset &&
|
||||
(max_chars <= left_length - offset ||
|
||||
(rbb->capacity <= left_length - offset &&
|
||||
@ -3554,7 +3539,7 @@ const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
|
||||
// the point where we switch to the -IntoBuffer routines (below) in order
|
||||
// to maximize the chances of delegating a big chunk of work to the
|
||||
// efficient *AsciiStringReadBlock routines.
|
||||
if (left_shape.IsCons()) {
|
||||
if (StringShape(left).IsCons()) {
|
||||
current = ConsString::cast(left);
|
||||
continue;
|
||||
} else {
|
||||
@ -3719,10 +3704,9 @@ const unibrow::byte* String::ReadBlock(String* input,
|
||||
rbb->remaining = 0;
|
||||
return NULL;
|
||||
}
|
||||
StringShape shape(input);
|
||||
switch (shape.representation_tag()) {
|
||||
switch (StringShape(input).representation_tag()) {
|
||||
case kSeqStringTag:
|
||||
if (shape.IsAsciiRepresentation()) {
|
||||
if (StringShape(input).IsAsciiRepresentation()) {
|
||||
SeqAsciiString* str = SeqAsciiString::cast(input);
|
||||
return str->SeqAsciiStringReadBlock(&rbb->remaining,
|
||||
offset_ptr,
|
||||
@ -3743,7 +3727,7 @@ const unibrow::byte* String::ReadBlock(String* input,
|
||||
offset_ptr,
|
||||
max_chars);
|
||||
case kExternalStringTag:
|
||||
if (shape.IsAsciiRepresentation()) {
|
||||
if (StringShape(input).IsAsciiRepresentation()) {
|
||||
return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
|
||||
&rbb->remaining,
|
||||
offset_ptr,
|
||||
@ -3795,9 +3779,8 @@ FlatStringReader::~FlatStringReader() {
|
||||
void FlatStringReader::RefreshState() {
|
||||
if (str_ == NULL) return;
|
||||
Handle<String> str(str_);
|
||||
StringShape shape(*str);
|
||||
ASSERT(str->IsFlat(shape));
|
||||
is_ascii_ = shape.IsAsciiRepresentation();
|
||||
ASSERT(str->IsFlat());
|
||||
is_ascii_ = StringShape(*str).IsAsciiRepresentation();
|
||||
if (is_ascii_) {
|
||||
start_ = str->ToAsciiVector().start();
|
||||
} else {
|
||||
@ -3833,13 +3816,12 @@ void String::ReadBlockIntoBuffer(String* input,
|
||||
ReadBlockBuffer* rbb,
|
||||
unsigned* offset_ptr,
|
||||
unsigned max_chars) {
|
||||
StringShape shape(input);
|
||||
ASSERT(*offset_ptr <= (unsigned)input->length(shape));
|
||||
ASSERT(*offset_ptr <= (unsigned)input->length());
|
||||
if (max_chars == 0) return;
|
||||
|
||||
switch (shape.representation_tag()) {
|
||||
switch (StringShape(input).representation_tag()) {
|
||||
case kSeqStringTag:
|
||||
if (shape.IsAsciiRepresentation()) {
|
||||
if (StringShape(input).IsAsciiRepresentation()) {
|
||||
SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
|
||||
offset_ptr,
|
||||
max_chars);
|
||||
@ -3861,7 +3843,7 @@ void String::ReadBlockIntoBuffer(String* input,
|
||||
max_chars);
|
||||
return;
|
||||
case kExternalStringTag:
|
||||
if (shape.IsAsciiRepresentation()) {
|
||||
if (StringShape(input).IsAsciiRepresentation()) {
|
||||
ExternalAsciiString::cast(input)->
|
||||
ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
|
||||
} else {
|
||||
@ -3885,12 +3867,11 @@ const unibrow::byte* String::ReadBlock(String* input,
|
||||
unsigned capacity,
|
||||
unsigned* remaining,
|
||||
unsigned* offset_ptr) {
|
||||
StringShape shape(input);
|
||||
ASSERT(*offset_ptr <= (unsigned)input->length(shape));
|
||||
unsigned chars = input->length(shape) - *offset_ptr;
|
||||
ASSERT(*offset_ptr <= (unsigned)input->length());
|
||||
unsigned chars = input->length() - *offset_ptr;
|
||||
ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
|
||||
const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
|
||||
ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape)));
|
||||
ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
|
||||
*remaining = rbb.remaining;
|
||||
return answer;
|
||||
}
|
||||
@ -3901,14 +3882,13 @@ const unibrow::byte* String::ReadBlock(String** raw_input,
|
||||
unsigned capacity,
|
||||
unsigned* remaining,
|
||||
unsigned* offset_ptr) {
|
||||
StringShape shape(*raw_input);
|
||||
Handle<String> input(raw_input);
|
||||
ASSERT(*offset_ptr <= (unsigned)input->length(shape));
|
||||
unsigned chars = input->length(shape) - *offset_ptr;
|
||||
ASSERT(*offset_ptr <= (unsigned)input->length());
|
||||
unsigned chars = input->length() - *offset_ptr;
|
||||
if (chars > capacity) chars = capacity;
|
||||
ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
|
||||
ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
|
||||
ASSERT(rbb.remaining <= static_cast<unsigned>(input->length(shape)));
|
||||
ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
|
||||
*remaining = rbb.remaining;
|
||||
return rbb.util_buffer;
|
||||
}
|
||||
@ -3928,13 +3908,12 @@ void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
|
||||
|
||||
while (true) {
|
||||
String* left = current->first();
|
||||
StringShape left_shape(left);
|
||||
unsigned left_length = (unsigned)left->length(left_shape);
|
||||
unsigned left_length = (unsigned)left->length();
|
||||
if (left_length > offset &&
|
||||
max_chars <= left_length - offset) {
|
||||
// Left hand side only - iterate unless we have reached the bottom of
|
||||
// the cons tree.
|
||||
if (left_shape.IsCons()) {
|
||||
if (StringShape(left).IsCons()) {
|
||||
current = ConsString::cast(left);
|
||||
continue;
|
||||
} else {
|
||||
@ -4002,27 +3981,23 @@ uint16_t ConsString::ConsStringGet(int index) {
|
||||
// Check for a flattened cons string
|
||||
if (second()->length() == 0) {
|
||||
String* left = first();
|
||||
return left->Get(StringShape(left), index);
|
||||
return left->Get(index);
|
||||
}
|
||||
|
||||
String* string = String::cast(this);
|
||||
StringShape shape(string);
|
||||
|
||||
while (true) {
|
||||
if (shape.IsCons()) {
|
||||
if (StringShape(string).IsCons()) {
|
||||
ConsString* cons_string = ConsString::cast(string);
|
||||
String* left = cons_string->first();
|
||||
StringShape left_shape(left);
|
||||
if (left->length(left_shape) > index) {
|
||||
if (left->length() > index) {
|
||||
string = left;
|
||||
shape = left_shape;
|
||||
} else {
|
||||
index -= left->length(left_shape);
|
||||
index -= left->length();
|
||||
string = cons_string->second();
|
||||
shape = StringShape(string);
|
||||
}
|
||||
} else {
|
||||
return string->Get(shape, index);
|
||||
return string->Get(index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4033,17 +4008,15 @@ uint16_t ConsString::ConsStringGet(int index) {
|
||||
|
||||
template <typename sinkchar>
|
||||
void String::WriteToFlat(String* src,
|
||||
StringShape src_shape,
|
||||
sinkchar* sink,
|
||||
int f,
|
||||
int t) {
|
||||
String* source = src;
|
||||
StringShape shape = src_shape;
|
||||
int from = f;
|
||||
int to = t;
|
||||
while (true) {
|
||||
ASSERT(0 <= from && from <= to && to <= source->length(shape));
|
||||
switch (shape.full_representation_tag()) {
|
||||
ASSERT(0 <= from && from <= to && to <= source->length());
|
||||
switch (StringShape(source).full_representation_tag()) {
|
||||
case kAsciiStringTag | kExternalStringTag: {
|
||||
CopyChars(sink,
|
||||
ExternalAsciiString::cast(source)->resource()->data() + from,
|
||||
@ -4077,19 +4050,17 @@ void String::WriteToFlat(String* src,
|
||||
from += start;
|
||||
to += start;
|
||||
source = String::cast(sliced_string->buffer());
|
||||
shape = StringShape(source);
|
||||
break;
|
||||
}
|
||||
case kAsciiStringTag | kConsStringTag:
|
||||
case kTwoByteStringTag | kConsStringTag: {
|
||||
ConsString* cons_string = ConsString::cast(source);
|
||||
String* first = cons_string->first();
|
||||
StringShape first_shape(first);
|
||||
int boundary = first->length(first_shape);
|
||||
int boundary = first->length();
|
||||
if (to - boundary >= boundary - from) {
|
||||
// Right hand side is longer. Recurse over left.
|
||||
if (from < boundary) {
|
||||
WriteToFlat(first, first_shape, sink, from, boundary);
|
||||
WriteToFlat(first, sink, from, boundary);
|
||||
sink += boundary - from;
|
||||
from = 0;
|
||||
} else {
|
||||
@ -4097,20 +4068,17 @@ void String::WriteToFlat(String* src,
|
||||
}
|
||||
to -= boundary;
|
||||
source = cons_string->second();
|
||||
shape = StringShape(source);
|
||||
} else {
|
||||
// Left hand side is longer. Recurse over right.
|
||||
if (to > boundary) {
|
||||
String* second = cons_string->second();
|
||||
WriteToFlat(second,
|
||||
StringShape(second),
|
||||
sink + boundary - from,
|
||||
0,
|
||||
to - boundary);
|
||||
to = boundary;
|
||||
}
|
||||
source = first;
|
||||
shape = first_shape;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -4128,7 +4096,7 @@ uint16_t SlicedString::SlicedStringGet(int index) {
|
||||
ASSERT(index >= 0 && index < this->length());
|
||||
// Delegate to the buffer string.
|
||||
String* underlying = buffer();
|
||||
return underlying->Get(StringShape(underlying), start() + index);
|
||||
return underlying->Get(start() + index);
|
||||
}
|
||||
|
||||
|
||||
@ -4192,9 +4160,8 @@ static StringInputBuffer string_compare_buffer_b;
|
||||
|
||||
template <typename IteratorA>
|
||||
static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
|
||||
StringShape b_shape(b);
|
||||
if (b->IsFlat(b_shape)) {
|
||||
if (b_shape.IsAsciiRepresentation()) {
|
||||
if (b->IsFlat()) {
|
||||
if (StringShape(b).IsAsciiRepresentation()) {
|
||||
VectorIterator<char> ib(b->ToAsciiVector());
|
||||
return CompareStringContents(ia, &ib);
|
||||
} else {
|
||||
@ -4211,12 +4178,10 @@ static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
|
||||
static StringInputBuffer string_compare_buffer_a;
|
||||
|
||||
|
||||
bool String::SlowEquals(StringShape this_shape,
|
||||
String* other,
|
||||
StringShape other_shape) {
|
||||
bool String::SlowEquals(String* other) {
|
||||
// Fast check: negative check with lengths.
|
||||
int len = length(this_shape);
|
||||
if (len != other->length(other_shape)) return false;
|
||||
int len = length();
|
||||
if (len != other->length()) return false;
|
||||
if (len == 0) return true;
|
||||
|
||||
// Fast check: if hash code is computed for both strings
|
||||
@ -4225,18 +4190,18 @@ bool String::SlowEquals(StringShape this_shape,
|
||||
if (Hash() != other->Hash()) return false;
|
||||
}
|
||||
|
||||
if (this_shape.IsSequentialAscii() && other_shape.IsSequentialAscii()) {
|
||||
if (StringShape(this).IsSequentialAscii() && StringShape(other).IsSequentialAscii()) {
|
||||
const char* str1 = SeqAsciiString::cast(this)->GetChars();
|
||||
const char* str2 = SeqAsciiString::cast(other)->GetChars();
|
||||
return CompareRawStringContents(Vector<const char>(str1, len),
|
||||
Vector<const char>(str2, len));
|
||||
}
|
||||
|
||||
if (this->IsFlat(this_shape)) {
|
||||
if (this_shape.IsAsciiRepresentation()) {
|
||||
if (this->IsFlat()) {
|
||||
if (StringShape(this).IsAsciiRepresentation()) {
|
||||
Vector<const char> vec1 = this->ToAsciiVector();
|
||||
if (other->IsFlat(other_shape)) {
|
||||
if (other_shape.IsAsciiRepresentation()) {
|
||||
if (other->IsFlat()) {
|
||||
if (StringShape(other).IsAsciiRepresentation()) {
|
||||
Vector<const char> vec2 = other->ToAsciiVector();
|
||||
return CompareRawStringContents(vec1, vec2);
|
||||
} else {
|
||||
@ -4251,8 +4216,8 @@ bool String::SlowEquals(StringShape this_shape,
|
||||
}
|
||||
} else {
|
||||
Vector<const uc16> vec1 = this->ToUC16Vector();
|
||||
if (other->IsFlat(other_shape)) {
|
||||
if (other_shape.IsAsciiRepresentation()) {
|
||||
if (other->IsFlat()) {
|
||||
if (StringShape(other).IsAsciiRepresentation()) {
|
||||
VectorIterator<uc16> buf1(vec1);
|
||||
VectorIterator<char> ib(other->ToAsciiVector());
|
||||
return CompareStringContents(&buf1, &ib);
|
||||
@ -4302,14 +4267,13 @@ bool String::MarkAsUndetectable() {
|
||||
|
||||
|
||||
bool String::IsEqualTo(Vector<const char> str) {
|
||||
StringShape this_shape(this);
|
||||
int slen = length(this_shape);
|
||||
int slen = length();
|
||||
Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
|
||||
decoder->Reset(str.start(), str.length());
|
||||
int i;
|
||||
for (i = 0; i < slen && decoder->has_more(); i++) {
|
||||
uc32 r = decoder->GetNext();
|
||||
if (Get(this_shape, i) != r) return false;
|
||||
if (Get(i) != r) return false;
|
||||
}
|
||||
return i == slen && !decoder->has_more();
|
||||
}
|
||||
@ -4363,8 +4327,7 @@ bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
|
||||
|
||||
|
||||
bool String::SlowAsArrayIndex(uint32_t* index) {
|
||||
StringShape shape(this);
|
||||
if (length(shape) <= kMaxCachedArrayIndexLength) {
|
||||
if (length() <= kMaxCachedArrayIndexLength) {
|
||||
Hash(); // force computation of hash code
|
||||
uint32_t field = length_field();
|
||||
if ((field & kIsArrayIndexMask) == 0) return false;
|
||||
@ -4372,7 +4335,7 @@ bool String::SlowAsArrayIndex(uint32_t* index) {
|
||||
return true;
|
||||
} else {
|
||||
StringInputBuffer buffer(this);
|
||||
return ComputeArrayIndex(&buffer, index, length(shape));
|
||||
return ComputeArrayIndex(&buffer, index, length());
|
||||
}
|
||||
}
|
||||
|
||||
@ -4433,9 +4396,8 @@ uint32_t String::ComputeLengthAndHashField(unibrow::CharacterStream* buffer,
|
||||
|
||||
|
||||
Object* String::Slice(int start, int end) {
|
||||
StringShape shape(this);
|
||||
if (start == 0 && end == length(shape)) return this;
|
||||
if (shape.representation_tag() == kSlicedStringTag) {
|
||||
if (start == 0 && end == length()) return this;
|
||||
if (StringShape(this).representation_tag() == kSlicedStringTag) {
|
||||
// Translate slices of a SlicedString into slices of the
|
||||
// underlying string buffer.
|
||||
SlicedString* str = SlicedString::cast(this);
|
||||
@ -4459,14 +4421,13 @@ Object* String::Slice(int start, int end) {
|
||||
// if Heap::AllocateSlicedString actually returned a SlicedString. It will
|
||||
// return flat strings for small slices for efficiency reasons.
|
||||
String* answer = String::cast(result);
|
||||
StringShape answer_shape(answer);
|
||||
if (answer_shape.IsSliced() &&
|
||||
shape.representation_tag() == kConsStringTag) {
|
||||
TryFlatten(shape);
|
||||
if (StringShape(answer).IsSliced() &&
|
||||
StringShape(this).representation_tag() == kConsStringTag) {
|
||||
TryFlatten();
|
||||
// If the flatten succeeded we might as well make the sliced string point
|
||||
// to the flat string rather than the cons string.
|
||||
String* second = ConsString::cast(this)->second();
|
||||
if (second->length(StringShape(second)) == 0) {
|
||||
if (second->length() == 0) {
|
||||
SlicedString::cast(answer)->set_buffer(ConsString::cast(this)->first());
|
||||
}
|
||||
}
|
||||
@ -4475,10 +4436,9 @@ Object* String::Slice(int start, int end) {
|
||||
|
||||
|
||||
void String::PrintOn(FILE* file) {
|
||||
StringShape shape(this);
|
||||
int length = this->length(shape);
|
||||
int length = this->length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
fprintf(file, "%c", Get(shape, i));
|
||||
fprintf(file, "%c", Get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -6034,13 +5994,12 @@ int JSObject::GetLocalElementKeys(FixedArray* storage,
|
||||
Object* val = JSValue::cast(this)->value();
|
||||
if (val->IsString()) {
|
||||
String* str = String::cast(val);
|
||||
StringShape shape(str);
|
||||
if (storage) {
|
||||
for (int i = 0; i < str->length(shape); i++) {
|
||||
for (int i = 0; i < str->length(); i++) {
|
||||
storage->set(counter + i, Smi::FromInt(i), SKIP_WRITE_BARRIER);
|
||||
}
|
||||
}
|
||||
counter += str->length(shape);
|
||||
counter += str->length();
|
||||
}
|
||||
}
|
||||
ASSERT(!storage || storage->length() == counter);
|
||||
@ -6288,10 +6247,9 @@ class SymbolKey : public HashTableKey {
|
||||
Object* GetObject() {
|
||||
// If the string is a cons string, attempt to flatten it so that
|
||||
// symbols will most often be flat strings.
|
||||
StringShape shape(string_);
|
||||
if (shape.IsCons()) {
|
||||
if (StringShape(string_).IsCons()) {
|
||||
ConsString* cons_string = ConsString::cast(string_);
|
||||
cons_string->TryFlatten(shape);
|
||||
cons_string->TryFlatten();
|
||||
if (cons_string->second() == Heap::empty_string()) {
|
||||
string_ = cons_string->first();
|
||||
}
|
||||
|
@ -3139,13 +3139,9 @@ class StringHasher {
|
||||
// to be passed by value and is immutable, but be aware that flattening a
|
||||
// string can potentially alter its shape. Also be aware that a GC caused by
|
||||
// something else can alter the shape of a string due to ConsString
|
||||
// shortcutting.
|
||||
//
|
||||
// Most of the methods designed to interrogate a string as to its exact nature
|
||||
// have been made into methods on StringShape in order to encourage the use of
|
||||
// StringShape. The String class has both a length() and a length(StringShape)
|
||||
// operation. The former is simpler to type, but the latter is faster if you
|
||||
// need the StringShape for some other operation immediately before or after.
|
||||
// shortcutting. Keeping these restrictions in mind has proven to be error-
|
||||
// prone and so we no longer put StringShapes in variables unless there is a
|
||||
// concrete performance benefit at that particular point in the code.
|
||||
class StringShape BASE_EMBEDDED {
|
||||
public:
|
||||
inline explicit StringShape(String* s);
|
||||
@ -3194,9 +3190,6 @@ class StringShape BASE_EMBEDDED {
|
||||
class String: public HeapObject {
|
||||
public:
|
||||
// Get and set the length of the string.
|
||||
// Fast version.
|
||||
inline int length(StringShape shape);
|
||||
// Easy version.
|
||||
inline int length();
|
||||
inline void set_length(int value);
|
||||
|
||||
@ -3208,22 +3201,22 @@ class String: public HeapObject {
|
||||
inline void set_length_field(uint32_t value);
|
||||
|
||||
// Get and set individual two byte chars in the string.
|
||||
inline void Set(StringShape shape, int index, uint16_t value);
|
||||
inline void Set(int index, uint16_t value);
|
||||
// Get individual two byte char in the string. Repeated calls
|
||||
// to this method are not efficient unless the string is flat.
|
||||
inline uint16_t Get(StringShape shape, int index);
|
||||
inline uint16_t Get(int index);
|
||||
|
||||
// Try to flatten the top level ConsString that is hiding behind this
|
||||
// string. This is a no-op unless the string is a ConsString or a
|
||||
// SlicedString. Flatten mutates the ConsString and might return a
|
||||
// failure.
|
||||
Object* TryFlatten(StringShape shape);
|
||||
Object* TryFlatten();
|
||||
|
||||
// Try to flatten the string. Checks first inline to see if it is necessary.
|
||||
// Do not handle allocation failures. After calling TryFlattenIfNotFlat, the
|
||||
// string could still be a ConsString, in which case a failure is returned.
|
||||
// Use FlattenString from Handles.cc to be sure to flatten.
|
||||
inline Object* TryFlattenIfNotFlat(StringShape shape);
|
||||
inline Object* TryFlattenIfNotFlat();
|
||||
|
||||
Vector<const char> ToAsciiVector();
|
||||
Vector<const uc16> ToUC16Vector();
|
||||
@ -3302,7 +3295,7 @@ class String: public HeapObject {
|
||||
void StringPrint();
|
||||
void StringVerify();
|
||||
#endif
|
||||
inline bool IsFlat(StringShape shape);
|
||||
inline bool IsFlat();
|
||||
|
||||
// Layout description.
|
||||
static const int kLengthOffset = HeapObject::kHeaderSize;
|
||||
@ -3364,7 +3357,6 @@ class String: public HeapObject {
|
||||
// Helper function for flattening strings.
|
||||
template <typename sinkchar>
|
||||
static void WriteToFlat(String* source,
|
||||
StringShape shape,
|
||||
sinkchar* sink,
|
||||
int from,
|
||||
int to);
|
||||
@ -3405,9 +3397,7 @@ class String: public HeapObject {
|
||||
private:
|
||||
// Slow case of String::Equals. This implementation works on any strings
|
||||
// but it is most efficient on strings that are almost flat.
|
||||
bool SlowEquals(StringShape this_shape,
|
||||
String* other,
|
||||
StringShape other_shape);
|
||||
bool SlowEquals(String* other);
|
||||
|
||||
// Slow case of AsArrayIndex.
|
||||
bool SlowAsArrayIndex(uint32_t* index);
|
||||
@ -3454,7 +3444,7 @@ class SeqAsciiString: public SeqString {
|
||||
// Garbage collection support. This method is called by the
|
||||
// garbage collector to compute the actual size of an AsciiString
|
||||
// instance.
|
||||
inline int SeqAsciiStringSize(StringShape shape);
|
||||
inline int SeqAsciiStringSize(InstanceType instance_type);
|
||||
|
||||
// Computes the size for an AsciiString instance of a given length.
|
||||
static int SizeFor(int length) {
|
||||
@ -3499,7 +3489,7 @@ class SeqTwoByteString: public SeqString {
|
||||
// Garbage collection support. This method is called by the
|
||||
// garbage collector to compute the actual size of a TwoByteString
|
||||
// instance.
|
||||
inline int SeqTwoByteStringSize(StringShape shape);
|
||||
inline int SeqTwoByteStringSize(InstanceType instance_type);
|
||||
|
||||
// Computes the size for a TwoByteString instance of a given length.
|
||||
static int SizeFor(int length) {
|
||||
|
@ -1097,11 +1097,10 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
|
||||
ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
|
||||
|
||||
HistogramTimerScope timer(&Counters::parse);
|
||||
StringShape shape(*source);
|
||||
Counters::total_parse_size.Increment(source->length(shape));
|
||||
Counters::total_parse_size.Increment(source->length());
|
||||
|
||||
// Initialize parser state.
|
||||
source->TryFlattenIfNotFlat(shape);
|
||||
source->TryFlattenIfNotFlat();
|
||||
scanner_.Init(source, stream, 0);
|
||||
ASSERT(target_stack_ == NULL);
|
||||
|
||||
@ -1150,9 +1149,8 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source,
|
||||
bool is_expression) {
|
||||
ZoneScope zone_scope(DONT_DELETE_ON_EXIT);
|
||||
HistogramTimerScope timer(&Counters::parse_lazy);
|
||||
source->TryFlattenIfNotFlat(StringShape(*source));
|
||||
StringShape shape(*source);
|
||||
Counters::total_parse_size.Increment(source->length(shape));
|
||||
source->TryFlattenIfNotFlat();
|
||||
Counters::total_parse_size.Increment(source->length());
|
||||
SafeStringInputBuffer buffer(source.location());
|
||||
|
||||
// Initialize parser state.
|
||||
|
@ -517,10 +517,9 @@ void PrettyPrinter::PrintLiteral(Handle<Object> value, bool quote) {
|
||||
Object* object = *value;
|
||||
if (object->IsString()) {
|
||||
String* string = String::cast(object);
|
||||
StringShape shape(string);
|
||||
if (quote) Print("\"");
|
||||
for (int i = 0; i < string->length(shape); i++) {
|
||||
Print("%c", string->Get(shape, i));
|
||||
for (int i = 0; i < string->length(); i++) {
|
||||
Print("%c", string->Get(i));
|
||||
}
|
||||
if (quote) Print("\"");
|
||||
} else if (object == Heap::null_value()) {
|
||||
|
@ -985,16 +985,14 @@ RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match(
|
||||
int* offsets_vector,
|
||||
int offsets_vector_length,
|
||||
int previous_index) {
|
||||
StringShape shape(*subject);
|
||||
|
||||
// Character offsets into string.
|
||||
int start_offset = previous_index;
|
||||
int end_offset = subject->length(shape);
|
||||
int end_offset = subject->length();
|
||||
|
||||
if (shape.IsCons()) {
|
||||
if (StringShape(*subject).IsCons()) {
|
||||
subject =
|
||||
Handle<String>(String::cast(ConsString::cast(*subject)->first()));
|
||||
} else if (shape.IsSliced()) {
|
||||
} else if (StringShape(*subject).IsSliced()) {
|
||||
SlicedString* slice = SlicedString::cast(*subject);
|
||||
start_offset += slice->start();
|
||||
end_offset += slice->start();
|
||||
@ -1002,13 +1000,12 @@ RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match(
|
||||
}
|
||||
|
||||
// String is now either Sequential or External
|
||||
StringShape flatshape(*subject);
|
||||
bool is_ascii = flatshape.IsAsciiRepresentation();
|
||||
bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
|
||||
int char_size_shift = is_ascii ? 0 : 1;
|
||||
|
||||
RegExpMacroAssemblerIA32::Result res;
|
||||
|
||||
if (flatshape.IsExternal()) {
|
||||
if (StringShape(*subject).IsExternal()) {
|
||||
const byte* address;
|
||||
if (is_ascii) {
|
||||
ExternalAsciiString* ext = ExternalAsciiString::cast(*subject);
|
||||
|
289
src/runtime.cc
289
src/runtime.cc
@ -1077,12 +1077,11 @@ static Object* CharCodeAt(String* subject, Object* index) {
|
||||
// Flatten the string. If someone wants to get a char at an index
|
||||
// in a cons string, it is likely that more indices will be
|
||||
// accessed.
|
||||
subject->TryFlattenIfNotFlat(StringShape(subject));
|
||||
StringShape shape(subject);
|
||||
if (i >= static_cast<uint32_t>(subject->length(shape))) {
|
||||
subject->TryFlattenIfNotFlat();
|
||||
if (i >= static_cast<uint32_t>(subject->length())) {
|
||||
return Heap::nan_value();
|
||||
}
|
||||
return Smi::FromInt(subject->Get(shape, i));
|
||||
return Smi::FromInt(subject->Get(i));
|
||||
}
|
||||
|
||||
|
||||
@ -1114,7 +1113,6 @@ static const int kStringBuilderConcatHelperPositionBits = 19;
|
||||
|
||||
template <typename schar>
|
||||
static inline void StringBuilderConcatHelper(String*,
|
||||
StringShape,
|
||||
schar*,
|
||||
FixedArray*,
|
||||
int);
|
||||
@ -1170,11 +1168,10 @@ class ReplacementStringBuilder {
|
||||
|
||||
|
||||
void AddString(Handle<String> string) {
|
||||
StringShape shape(*string);
|
||||
int length = string->length(shape);
|
||||
int length = string->length();
|
||||
ASSERT(length > 0);
|
||||
AddElement(*string);
|
||||
if (!shape.IsAsciiRepresentation()) {
|
||||
if (!StringShape(*string).IsAsciiRepresentation()) {
|
||||
is_ascii_ = false;
|
||||
}
|
||||
IncrementCharacterCount(length);
|
||||
@ -1193,7 +1190,6 @@ class ReplacementStringBuilder {
|
||||
SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
|
||||
char* char_buffer = seq->GetChars();
|
||||
StringBuilderConcatHelper(*subject_,
|
||||
StringShape(*subject_),
|
||||
char_buffer,
|
||||
*parts_,
|
||||
part_count_);
|
||||
@ -1204,7 +1200,6 @@ class ReplacementStringBuilder {
|
||||
SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
|
||||
uc16* char_buffer = seq->GetChars();
|
||||
StringBuilderConcatHelper(*subject_,
|
||||
StringShape(*subject_),
|
||||
char_buffer,
|
||||
*parts_,
|
||||
part_count_);
|
||||
@ -1432,16 +1427,15 @@ class CompiledReplacement {
|
||||
void CompiledReplacement::Compile(Handle<String> replacement,
|
||||
int capture_count,
|
||||
int subject_length) {
|
||||
StringShape shape(*replacement);
|
||||
ASSERT(replacement->IsFlat(shape));
|
||||
if (shape.IsAsciiRepresentation()) {
|
||||
ASSERT(replacement->IsFlat());
|
||||
if (StringShape(*replacement).IsAsciiRepresentation()) {
|
||||
AssertNoAllocation no_alloc;
|
||||
ParseReplacementPattern(&parts_,
|
||||
replacement->ToAsciiVector(),
|
||||
capture_count,
|
||||
subject_length);
|
||||
} else {
|
||||
ASSERT(shape.IsTwoByteRepresentation());
|
||||
ASSERT(StringShape(*replacement).IsTwoByteRepresentation());
|
||||
AssertNoAllocation no_alloc;
|
||||
|
||||
ParseReplacementPattern(&parts_,
|
||||
@ -1514,8 +1508,8 @@ static Object* StringReplaceRegExpWithString(String* subject,
|
||||
JSRegExp* regexp,
|
||||
String* replacement,
|
||||
JSArray* last_match_info) {
|
||||
ASSERT(subject->IsFlat(StringShape(subject)));
|
||||
ASSERT(replacement->IsFlat(StringShape(replacement)));
|
||||
ASSERT(subject->IsFlat());
|
||||
ASSERT(replacement->IsFlat());
|
||||
|
||||
HandleScope handles;
|
||||
|
||||
@ -1619,9 +1613,8 @@ static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
|
||||
ASSERT(args.length() == 4);
|
||||
|
||||
CONVERT_CHECKED(String, subject, args[0]);
|
||||
StringShape subject_shape(subject);
|
||||
if (!subject->IsFlat(subject_shape)) {
|
||||
Object* flat_subject = subject->TryFlatten(subject_shape);
|
||||
if (!subject->IsFlat()) {
|
||||
Object* flat_subject = subject->TryFlatten();
|
||||
if (flat_subject->IsFailure()) {
|
||||
return flat_subject;
|
||||
}
|
||||
@ -1629,9 +1622,8 @@ static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
|
||||
}
|
||||
|
||||
CONVERT_CHECKED(String, replacement, args[2]);
|
||||
StringShape replacement_shape(replacement);
|
||||
if (!replacement->IsFlat(replacement_shape)) {
|
||||
Object* flat_replacement = replacement->TryFlatten(replacement_shape);
|
||||
if (!replacement->IsFlat()) {
|
||||
Object* flat_replacement = replacement->TryFlatten();
|
||||
if (flat_replacement->IsFailure()) {
|
||||
return flat_replacement;
|
||||
}
|
||||
@ -2002,27 +1994,24 @@ int Runtime::StringMatch(Handle<String> sub,
|
||||
Handle<String> pat,
|
||||
int start_index) {
|
||||
ASSERT(0 <= start_index);
|
||||
StringShape sub_shape(*sub);
|
||||
ASSERT(start_index <= sub->length(sub_shape));
|
||||
ASSERT(start_index <= sub->length());
|
||||
|
||||
int pattern_length = pat->length();
|
||||
if (pattern_length == 0) return start_index;
|
||||
|
||||
int subject_length = sub->length(sub_shape);
|
||||
int subject_length = sub->length();
|
||||
if (start_index + pattern_length > subject_length) return -1;
|
||||
|
||||
if (!sub->IsFlat(sub_shape)) {
|
||||
if (!sub->IsFlat()) {
|
||||
FlattenString(sub);
|
||||
sub_shape = StringShape(*sub);
|
||||
}
|
||||
StringShape pat_shape(*pat);
|
||||
// Searching for one specific character is common. For one
|
||||
// character patterns linear search is necessary, so any smart
|
||||
// algorithm is unnecessary overhead.
|
||||
if (pattern_length == 1) {
|
||||
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
|
||||
if (sub_shape.IsAsciiRepresentation()) {
|
||||
uc16 pchar = pat->Get(pat_shape, 0);
|
||||
if (StringShape(*sub).IsAsciiRepresentation()) {
|
||||
uc16 pchar = pat->Get(0);
|
||||
if (pchar > String::kMaxAsciiCharCode) {
|
||||
return -1;
|
||||
}
|
||||
@ -2037,28 +2026,24 @@ int Runtime::StringMatch(Handle<String> sub,
|
||||
return reinterpret_cast<const char*>(pos) - ascii_vector.start()
|
||||
+ start_index;
|
||||
}
|
||||
return SingleCharIndexOf(sub->ToUC16Vector(),
|
||||
pat->Get(pat_shape, 0),
|
||||
start_index);
|
||||
return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index);
|
||||
}
|
||||
|
||||
if (!pat->IsFlat(pat_shape)) {
|
||||
if (!pat->IsFlat()) {
|
||||
FlattenString(pat);
|
||||
pat_shape = StringShape(*pat);
|
||||
sub_shape = StringShape(*sub);
|
||||
}
|
||||
|
||||
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
|
||||
// dispatch on type of strings
|
||||
if (pat_shape.IsAsciiRepresentation()) {
|
||||
if (StringShape(*pat).IsAsciiRepresentation()) {
|
||||
Vector<const char> pat_vector = pat->ToAsciiVector();
|
||||
if (sub_shape.IsAsciiRepresentation()) {
|
||||
if (StringShape(*sub).IsAsciiRepresentation()) {
|
||||
return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
|
||||
}
|
||||
return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
|
||||
}
|
||||
Vector<const uc16> pat_vector = pat->ToUC16Vector();
|
||||
if (sub_shape.IsAsciiRepresentation()) {
|
||||
if (StringShape(*sub).IsAsciiRepresentation()) {
|
||||
return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
|
||||
}
|
||||
return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
|
||||
@ -2090,17 +2075,14 @@ static Object* Runtime_StringLastIndexOf(Arguments args) {
|
||||
CONVERT_CHECKED(String, pat, args[1]);
|
||||
Object* index = args[2];
|
||||
|
||||
sub->TryFlattenIfNotFlat(StringShape(sub));
|
||||
pat->TryFlattenIfNotFlat(StringShape(pat));
|
||||
|
||||
StringShape sub_shape(sub);
|
||||
StringShape pat_shape(pat);
|
||||
sub->TryFlattenIfNotFlat();
|
||||
pat->TryFlattenIfNotFlat();
|
||||
|
||||
uint32_t start_index;
|
||||
if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
|
||||
|
||||
uint32_t pattern_length = pat->length(pat_shape);
|
||||
uint32_t sub_length = sub->length(sub_shape);
|
||||
uint32_t pattern_length = pat->length();
|
||||
uint32_t sub_length = sub->length();
|
||||
|
||||
if (start_index + pattern_length > sub_length) {
|
||||
start_index = sub_length - pattern_length;
|
||||
@ -2109,7 +2091,7 @@ static Object* Runtime_StringLastIndexOf(Arguments args) {
|
||||
for (int i = start_index; i >= 0; i--) {
|
||||
bool found = true;
|
||||
for (uint32_t j = 0; j < pattern_length; j++) {
|
||||
if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) {
|
||||
if (sub->Get(i + j) != pat->Get(j)) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
@ -2129,10 +2111,8 @@ static Object* Runtime_StringLocaleCompare(Arguments args) {
|
||||
CONVERT_CHECKED(String, str2, args[1]);
|
||||
|
||||
if (str1 == str2) return Smi::FromInt(0); // Equal.
|
||||
StringShape shape1(str1);
|
||||
StringShape shape2(str2);
|
||||
int str1_length = str1->length(shape1);
|
||||
int str2_length = str2->length(shape2);
|
||||
int str1_length = str1->length();
|
||||
int str2_length = str2->length();
|
||||
|
||||
// Decide trivial cases without flattening.
|
||||
if (str1_length == 0) {
|
||||
@ -2147,11 +2127,11 @@ static Object* Runtime_StringLocaleCompare(Arguments args) {
|
||||
// No need to flatten if we are going to find the answer on the first
|
||||
// character. At this point we know there is at least one character
|
||||
// in each string, due to the trivial case handling above.
|
||||
int d = str1->Get(shape1, 0) - str2->Get(shape2, 0);
|
||||
int d = str1->Get(0) - str2->Get(0);
|
||||
if (d != 0) return Smi::FromInt(d);
|
||||
|
||||
str1->TryFlattenIfNotFlat(shape1); // Shapes are no longer valid now!
|
||||
str2->TryFlattenIfNotFlat(shape2);
|
||||
str1->TryFlattenIfNotFlat();
|
||||
str2->TryFlattenIfNotFlat();
|
||||
|
||||
static StringInputBuffer buf1;
|
||||
static StringInputBuffer buf2;
|
||||
@ -2286,11 +2266,10 @@ static Object* Runtime_NumberToPrecision(Arguments args) {
|
||||
// Returns a single character string where first character equals
|
||||
// string->Get(index).
|
||||
static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
|
||||
StringShape shape(*string);
|
||||
if (index < static_cast<uint32_t>(string->length(shape))) {
|
||||
string->TryFlattenIfNotFlat(shape); // Invalidates shape!
|
||||
if (index < static_cast<uint32_t>(string->length())) {
|
||||
string->TryFlattenIfNotFlat();
|
||||
return LookupSingleCharacterStringFromCode(
|
||||
string->Get(StringShape(*string), index));
|
||||
string->Get(index));
|
||||
}
|
||||
return Execution::CharAt(string, index);
|
||||
}
|
||||
@ -2481,7 +2460,7 @@ Object* Runtime::SetObjectProperty(Handle<Object> object,
|
||||
result = SetElement(js_object, index, value);
|
||||
} else {
|
||||
Handle<String> key_string = Handle<String>::cast(key);
|
||||
key_string->TryFlattenIfNotFlat(StringShape(*key_string));
|
||||
key_string->TryFlattenIfNotFlat();
|
||||
result = SetProperty(js_object, key_string, value, attr);
|
||||
}
|
||||
if (result.is_null()) return Failure::Exception();
|
||||
@ -2775,7 +2754,7 @@ static Object* Runtime_StringToNumber(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_CHECKED(String, subject, args[0]);
|
||||
subject->TryFlattenIfNotFlat(StringShape(subject));
|
||||
subject->TryFlattenIfNotFlat();
|
||||
return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
|
||||
}
|
||||
|
||||
@ -2805,11 +2784,10 @@ static Object* Runtime_StringFromCharCodeArray(Arguments args) {
|
||||
|
||||
if (object->IsFailure()) return object;
|
||||
String* result = String::cast(object);
|
||||
StringShape result_shape(result);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object* element = codes->GetElement(i);
|
||||
CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
|
||||
result->Set(result_shape, i, chr & 0xffff);
|
||||
result->Set(i, chr & 0xffff);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -2858,7 +2836,7 @@ static Object* Runtime_URIEscape(Arguments args) {
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_CHECKED(String, source, args[0]);
|
||||
|
||||
source->TryFlattenIfNotFlat(StringShape(source));
|
||||
source->TryFlattenIfNotFlat();
|
||||
|
||||
int escaped_length = 0;
|
||||
int length = source->length();
|
||||
@ -2888,7 +2866,6 @@ static Object* Runtime_URIEscape(Arguments args) {
|
||||
Object* o = Heap::AllocateRawAsciiString(escaped_length);
|
||||
if (o->IsFailure()) return o;
|
||||
String* destination = String::cast(o);
|
||||
StringShape dshape(destination);
|
||||
int dest_position = 0;
|
||||
|
||||
Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
|
||||
@ -2896,20 +2873,20 @@ static Object* Runtime_URIEscape(Arguments args) {
|
||||
while (buffer->has_more()) {
|
||||
uint16_t chr = buffer->GetNext();
|
||||
if (chr >= 256) {
|
||||
destination->Set(dshape, dest_position, '%');
|
||||
destination->Set(dshape, dest_position+1, 'u');
|
||||
destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]);
|
||||
destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]);
|
||||
destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]);
|
||||
destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]);
|
||||
destination->Set(dest_position, '%');
|
||||
destination->Set(dest_position+1, 'u');
|
||||
destination->Set(dest_position+2, hex_chars[chr >> 12]);
|
||||
destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
|
||||
destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
|
||||
destination->Set(dest_position+5, hex_chars[chr & 0xf]);
|
||||
dest_position += 6;
|
||||
} else if (IsNotEscaped(chr)) {
|
||||
destination->Set(dshape, dest_position, chr);
|
||||
destination->Set(dest_position, chr);
|
||||
dest_position++;
|
||||
} else {
|
||||
destination->Set(dshape, dest_position, '%');
|
||||
destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]);
|
||||
destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]);
|
||||
destination->Set(dest_position, '%');
|
||||
destination->Set(dest_position+1, hex_chars[chr >> 4]);
|
||||
destination->Set(dest_position+2, hex_chars[chr & 0xf]);
|
||||
dest_position += 3;
|
||||
}
|
||||
}
|
||||
@ -2938,26 +2915,25 @@ static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
|
||||
|
||||
|
||||
static inline int Unescape(String* source,
|
||||
StringShape shape,
|
||||
int i,
|
||||
int length,
|
||||
int* step) {
|
||||
uint16_t character = source->Get(shape, i);
|
||||
uint16_t character = source->Get(i);
|
||||
int32_t hi = 0;
|
||||
int32_t lo = 0;
|
||||
if (character == '%' &&
|
||||
i <= length - 6 &&
|
||||
source->Get(shape, i + 1) == 'u' &&
|
||||
(hi = TwoDigitHex(source->Get(shape, i + 2),
|
||||
source->Get(shape, i + 3))) != -1 &&
|
||||
(lo = TwoDigitHex(source->Get(shape, i + 4),
|
||||
source->Get(shape, i + 5))) != -1) {
|
||||
source->Get(i + 1) == 'u' &&
|
||||
(hi = TwoDigitHex(source->Get(i + 2),
|
||||
source->Get(i + 3))) != -1 &&
|
||||
(lo = TwoDigitHex(source->Get(i + 4),
|
||||
source->Get(i + 5))) != -1) {
|
||||
*step = 6;
|
||||
return (hi << 8) + lo;
|
||||
} else if (character == '%' &&
|
||||
i <= length - 3 &&
|
||||
(lo = TwoDigitHex(source->Get(shape, i + 1),
|
||||
source->Get(shape, i + 2))) != -1) {
|
||||
(lo = TwoDigitHex(source->Get(i + 1),
|
||||
source->Get(i + 2))) != -1) {
|
||||
*step = 3;
|
||||
return lo;
|
||||
} else {
|
||||
@ -2972,22 +2948,17 @@ static Object* Runtime_URIUnescape(Arguments args) {
|
||||
ASSERT(args.length() == 1);
|
||||
CONVERT_CHECKED(String, source, args[0]);
|
||||
|
||||
source->TryFlattenIfNotFlat(StringShape(source));
|
||||
StringShape source_shape(source);
|
||||
source->TryFlattenIfNotFlat();
|
||||
|
||||
bool ascii = true;
|
||||
int length = source->length(source_shape);
|
||||
int length = source->length();
|
||||
|
||||
int unescaped_length = 0;
|
||||
for (int i = 0; i < length; unescaped_length++) {
|
||||
int step;
|
||||
if (Unescape(source,
|
||||
source_shape,
|
||||
i,
|
||||
length,
|
||||
&step) >
|
||||
String::kMaxAsciiCharCode)
|
||||
if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
|
||||
ascii = false;
|
||||
}
|
||||
i += step;
|
||||
}
|
||||
|
||||
@ -3000,14 +2971,11 @@ static Object* Runtime_URIUnescape(Arguments args) {
|
||||
Heap::AllocateRawTwoByteString(unescaped_length);
|
||||
if (o->IsFailure()) return o;
|
||||
String* destination = String::cast(o);
|
||||
StringShape destination_shape(destination);
|
||||
|
||||
int dest_position = 0;
|
||||
for (int i = 0; i < length; dest_position++) {
|
||||
int step;
|
||||
destination->Set(destination_shape,
|
||||
dest_position,
|
||||
Unescape(source, source_shape, i, length, &step));
|
||||
destination->Set(dest_position, Unescape(source, i, length, &step));
|
||||
i += step;
|
||||
}
|
||||
return destination;
|
||||
@ -3021,33 +2989,31 @@ static Object* Runtime_StringParseInt(Arguments args) {
|
||||
CONVERT_DOUBLE_CHECKED(n, args[1]);
|
||||
int radix = FastD2I(n);
|
||||
|
||||
s->TryFlattenIfNotFlat(StringShape(s));
|
||||
s->TryFlattenIfNotFlat();
|
||||
|
||||
StringShape shape(s);
|
||||
|
||||
int len = s->length(shape);
|
||||
int len = s->length();
|
||||
int i;
|
||||
|
||||
// Skip leading white space.
|
||||
for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ;
|
||||
for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
|
||||
if (i == len) return Heap::nan_value();
|
||||
|
||||
// Compute the sign (default to +).
|
||||
int sign = 1;
|
||||
if (s->Get(shape, i) == '-') {
|
||||
if (s->Get(i) == '-') {
|
||||
sign = -1;
|
||||
i++;
|
||||
} else if (s->Get(shape, i) == '+') {
|
||||
} else if (s->Get(i) == '+') {
|
||||
i++;
|
||||
}
|
||||
|
||||
// Compute the radix if 0.
|
||||
if (radix == 0) {
|
||||
radix = 10;
|
||||
if (i < len && s->Get(shape, i) == '0') {
|
||||
if (i < len && s->Get(i) == '0') {
|
||||
radix = 8;
|
||||
if (i + 1 < len) {
|
||||
int c = s->Get(shape, i + 1);
|
||||
int c = s->Get(i + 1);
|
||||
if (c == 'x' || c == 'X') {
|
||||
radix = 16;
|
||||
i += 2;
|
||||
@ -3056,8 +3022,8 @@ static Object* Runtime_StringParseInt(Arguments args) {
|
||||
}
|
||||
} else if (radix == 16) {
|
||||
// Allow 0x or 0X prefix if radix is 16.
|
||||
if (i + 1 < len && s->Get(shape, i) == '0') {
|
||||
int c = s->Get(shape, i + 1);
|
||||
if (i + 1 < len && s->Get(i) == '0') {
|
||||
int c = s->Get(i + 1);
|
||||
if (c == 'x' || c == 'X') i += 2;
|
||||
}
|
||||
}
|
||||
@ -3089,40 +3055,26 @@ static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
|
||||
|
||||
|
||||
template <class Converter>
|
||||
static Object* ConvertCase(Arguments args,
|
||||
unibrow::Mapping<Converter, 128>* mapping) {
|
||||
NoHandleAllocation ha;
|
||||
|
||||
CONVERT_CHECKED(String, s, args[0]);
|
||||
s->TryFlattenIfNotFlat(StringShape(s));
|
||||
StringShape shape(s);
|
||||
|
||||
int raw_string_length = s->length(shape);
|
||||
// Assume that the string is not empty; we need this assumption later
|
||||
if (raw_string_length == 0) return s;
|
||||
int length = raw_string_length;
|
||||
|
||||
|
||||
// We try this twice, once with the assumption that the result is
|
||||
// no longer than the input and, if that assumption breaks, again
|
||||
// with the exact length. This is implemented using a goto back
|
||||
// to this label if we discover that the assumption doesn't hold.
|
||||
// I apologize sincerely for this and will give a vaffel-is to
|
||||
// the first person who can implement it in a nicer way.
|
||||
try_convert:
|
||||
|
||||
static Object* ConvertCaseHelper(String* s,
|
||||
int length,
|
||||
int input_string_length,
|
||||
unibrow::Mapping<Converter, 128>* mapping) {
|
||||
// We try this twice, once with the assumption that the result is no longer
|
||||
// than the input and, if that assumption breaks, again with the exact
|
||||
// length. This may not be pretty, but it is nicer than what was here before
|
||||
// and I hereby claim my vaffel-is.
|
||||
//
|
||||
// Allocate the resulting string.
|
||||
//
|
||||
// NOTE: This assumes that the upper/lower case of an ascii
|
||||
// character is also ascii. This is currently the case, but it
|
||||
// might break in the future if we implement more context and locale
|
||||
// dependent upper/lower conversions.
|
||||
Object* o = shape.IsAsciiRepresentation()
|
||||
Object* o = StringShape(s).IsAsciiRepresentation()
|
||||
? Heap::AllocateRawAsciiString(length)
|
||||
: Heap::AllocateRawTwoByteString(length);
|
||||
if (o->IsFailure()) return o;
|
||||
String* result = String::cast(o);
|
||||
StringShape result_shape(result);
|
||||
bool has_changed_character = false;
|
||||
|
||||
// Convert all characters to upper case, assuming that they will fit
|
||||
@ -3130,24 +3082,23 @@ static Object* ConvertCase(Arguments args,
|
||||
Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
|
||||
buffer->Reset(s);
|
||||
unibrow::uchar chars[Converter::kMaxWidth];
|
||||
int i = 0;
|
||||
// We can assume that the string is not empty
|
||||
uc32 current = buffer->GetNext();
|
||||
while (i < length) {
|
||||
for (int i = 0; i < length; ) {
|
||||
bool has_next = buffer->has_more();
|
||||
uc32 next = has_next ? buffer->GetNext() : 0;
|
||||
int char_length = mapping->get(current, next, chars);
|
||||
if (char_length == 0) {
|
||||
// The case conversion of this character is the character itself.
|
||||
result->Set(result_shape, i, current);
|
||||
result->Set(i, current);
|
||||
i++;
|
||||
} else if (char_length == 1) {
|
||||
// Common case: converting the letter resulted in one character.
|
||||
ASSERT(static_cast<uc32>(chars[0]) != current);
|
||||
result->Set(result_shape, i, chars[0]);
|
||||
result->Set(i, chars[0]);
|
||||
has_changed_character = true;
|
||||
i++;
|
||||
} else if (length == raw_string_length) {
|
||||
} else if (length == input_string_length) {
|
||||
// We've assumed that the result would be as long as the
|
||||
// input but here is a character that converts to several
|
||||
// characters. No matter, we calculate the exact length
|
||||
@ -3174,12 +3125,16 @@ static Object* ConvertCase(Arguments args,
|
||||
int char_length = mapping->get(current, 0, chars);
|
||||
if (char_length == 0) char_length = 1;
|
||||
current_length += char_length;
|
||||
if (current_length > Smi::kMaxValue) {
|
||||
Top::context()->mark_out_of_memory();
|
||||
return Failure::OutOfMemoryException();
|
||||
}
|
||||
}
|
||||
length = current_length;
|
||||
goto try_convert;
|
||||
// Try again with the real length.
|
||||
return Smi::FromInt(current_length);
|
||||
} else {
|
||||
for (int j = 0; j < char_length; j++) {
|
||||
result->Set(result_shape, i, chars[j]);
|
||||
result->Set(i, chars[j]);
|
||||
i++;
|
||||
}
|
||||
has_changed_character = true;
|
||||
@ -3198,6 +3153,28 @@ static Object* ConvertCase(Arguments args,
|
||||
}
|
||||
|
||||
|
||||
template <class Converter>
|
||||
static Object* ConvertCase(Arguments args,
|
||||
unibrow::Mapping<Converter, 128>* mapping) {
|
||||
NoHandleAllocation ha;
|
||||
|
||||
CONVERT_CHECKED(String, s, args[0]);
|
||||
s->TryFlattenIfNotFlat();
|
||||
|
||||
int input_string_length = s->length();
|
||||
// Assume that the string is not empty; we need this assumption later
|
||||
if (input_string_length == 0) return s;
|
||||
int length = input_string_length;
|
||||
|
||||
Object* answer = ConvertCaseHelper(s, length, length, mapping);
|
||||
if (answer->IsSmi()) {
|
||||
// Retry with correct length.
|
||||
answer = ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
|
||||
}
|
||||
return answer; // This may be a failure.
|
||||
}
|
||||
|
||||
|
||||
static Object* Runtime_StringToLowerCase(Arguments args) {
|
||||
return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
|
||||
}
|
||||
@ -3384,7 +3361,6 @@ static Object* Runtime_StringAdd(Arguments args) {
|
||||
|
||||
template<typename sinkchar>
|
||||
static inline void StringBuilderConcatHelper(String* special,
|
||||
StringShape special_shape,
|
||||
sinkchar* sink,
|
||||
FixedArray* fixed_array,
|
||||
int array_length) {
|
||||
@ -3396,16 +3372,14 @@ static inline void StringBuilderConcatHelper(String* special,
|
||||
int pos = StringBuilderSubstringPosition::decode(encoded_slice);
|
||||
int len = StringBuilderSubstringLength::decode(encoded_slice);
|
||||
String::WriteToFlat(special,
|
||||
special_shape,
|
||||
sink + position,
|
||||
pos,
|
||||
pos + len);
|
||||
position += len;
|
||||
} else {
|
||||
String* string = String::cast(element);
|
||||
StringShape shape(string);
|
||||
int element_length = string->length(shape);
|
||||
String::WriteToFlat(string, shape, sink + position, 0, element_length);
|
||||
int element_length = string->length();
|
||||
String::WriteToFlat(string, sink + position, 0, element_length);
|
||||
position += element_length;
|
||||
}
|
||||
}
|
||||
@ -3417,8 +3391,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
|
||||
ASSERT(args.length() == 2);
|
||||
CONVERT_CHECKED(JSArray, array, args[0]);
|
||||
CONVERT_CHECKED(String, special, args[1]);
|
||||
StringShape special_shape(special);
|
||||
int special_length = special->length(special_shape);
|
||||
int special_length = special->length();
|
||||
Object* smi_array_length = array->length();
|
||||
if (!smi_array_length->IsSmi()) {
|
||||
Top::context()->mark_out_of_memory();
|
||||
@ -3440,7 +3413,7 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
|
||||
if (first->IsString()) return first;
|
||||
}
|
||||
|
||||
bool ascii = special_shape.IsAsciiRepresentation();
|
||||
bool ascii = StringShape(special).IsAsciiRepresentation();
|
||||
int position = 0;
|
||||
for (int i = 0; i < array_length; i++) {
|
||||
Object* elt = fixed_array->get(i);
|
||||
@ -3454,14 +3427,13 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
|
||||
position += len;
|
||||
} else if (elt->IsString()) {
|
||||
String* element = String::cast(elt);
|
||||
StringShape element_shape(element);
|
||||
int element_length = element->length(element_shape);
|
||||
int element_length = element->length();
|
||||
if (!Smi::IsValid(element_length + position)) {
|
||||
Top::context()->mark_out_of_memory();
|
||||
return Failure::OutOfMemoryException();
|
||||
}
|
||||
position += element_length;
|
||||
if (ascii && !element_shape.IsAsciiRepresentation()) {
|
||||
if (ascii && !StringShape(element).IsAsciiRepresentation()) {
|
||||
ascii = false;
|
||||
}
|
||||
} else {
|
||||
@ -3477,7 +3449,6 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
|
||||
if (object->IsFailure()) return object;
|
||||
SeqAsciiString* answer = SeqAsciiString::cast(object);
|
||||
StringBuilderConcatHelper(special,
|
||||
special_shape,
|
||||
answer->GetChars(),
|
||||
fixed_array,
|
||||
array_length);
|
||||
@ -3487,7 +3458,6 @@ static Object* Runtime_StringBuilderConcat(Arguments args) {
|
||||
if (object->IsFailure()) return object;
|
||||
SeqTwoByteString* answer = SeqTwoByteString::cast(object);
|
||||
StringBuilderConcatHelper(special,
|
||||
special_shape,
|
||||
answer->GetChars(),
|
||||
fixed_array,
|
||||
array_length);
|
||||
@ -3682,24 +3652,21 @@ static Object* Runtime_StringCompare(Arguments args) {
|
||||
CONVERT_CHECKED(String, x, args[0]);
|
||||
CONVERT_CHECKED(String, y, args[1]);
|
||||
|
||||
StringShape x_shape(x);
|
||||
StringShape y_shape(y);
|
||||
|
||||
// A few fast case tests before we flatten.
|
||||
if (x == y) return Smi::FromInt(EQUAL);
|
||||
if (y->length(y_shape) == 0) {
|
||||
if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL);
|
||||
if (y->length() == 0) {
|
||||
if (x->length() == 0) return Smi::FromInt(EQUAL);
|
||||
return Smi::FromInt(GREATER);
|
||||
} else if (x->length(x_shape) == 0) {
|
||||
} else if (x->length() == 0) {
|
||||
return Smi::FromInt(LESS);
|
||||
}
|
||||
|
||||
int d = x->Get(x_shape, 0) - y->Get(y_shape, 0);
|
||||
int d = x->Get(0) - y->Get(0);
|
||||
if (d < 0) return Smi::FromInt(LESS);
|
||||
else if (d > 0) return Smi::FromInt(GREATER);
|
||||
|
||||
x->TryFlattenIfNotFlat(x_shape); // Shapes are no longer valid!
|
||||
y->TryFlattenIfNotFlat(y_shape);
|
||||
x->TryFlattenIfNotFlat();
|
||||
y->TryFlattenIfNotFlat();
|
||||
|
||||
static StringInputBuffer bufx;
|
||||
static StringInputBuffer bufy;
|
||||
|
@ -254,10 +254,9 @@ TEST(GarbageCollection) {
|
||||
|
||||
static void VerifyStringAllocation(const char* string) {
|
||||
String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string)));
|
||||
StringShape shape(s);
|
||||
CHECK_EQ(static_cast<int>(strlen(string)), s->length(shape));
|
||||
for (int index = 0; index < s->length(shape); index++) {
|
||||
CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(shape, index)); }
|
||||
CHECK_EQ(static_cast<int>(strlen(string)), s->length());
|
||||
for (int index = 0; index < s->length(); index++) {
|
||||
CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index)); }
|
||||
}
|
||||
|
||||
|
||||
|
@ -643,8 +643,7 @@ TEST(MacroAssembler) {
|
||||
|
||||
Handle<String> f1 =
|
||||
Factory::NewStringFromAscii(CStrVector("foobar"));
|
||||
Handle<String> f1_16 = RegExpImpl::StringToTwoByte(f1);
|
||||
CHECK(IrregexpInterpreter::Match(array, f1_16, captures, 0));
|
||||
CHECK(IrregexpInterpreter::Match(array, f1, captures, 0));
|
||||
CHECK_EQ(0, captures[0]);
|
||||
CHECK_EQ(3, captures[1]);
|
||||
CHECK_EQ(1, captures[2]);
|
||||
@ -653,8 +652,7 @@ TEST(MacroAssembler) {
|
||||
|
||||
Handle<String> f2 =
|
||||
Factory::NewStringFromAscii(CStrVector("barfoo"));
|
||||
Handle<String> f2_16 = RegExpImpl::StringToTwoByte(f2);
|
||||
CHECK(!IrregexpInterpreter::Match(array, f2_16, captures, 0));
|
||||
CHECK(!IrregexpInterpreter::Match(array, f2, captures, 0));
|
||||
CHECK_EQ(42, captures[0]);
|
||||
}
|
||||
|
||||
|
@ -62,8 +62,7 @@ static void InitializeBuildingBlocks(
|
||||
building_blocks[i] =
|
||||
Factory::NewStringFromTwoByte(Vector<const uc16>(buf, len));
|
||||
for (int j = 0; j < len; j++) {
|
||||
StringShape shape(*building_blocks[i]);
|
||||
CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
|
||||
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -75,8 +74,7 @@ static void InitializeBuildingBlocks(
|
||||
building_blocks[i] =
|
||||
Factory::NewStringFromAscii(Vector<const char>(buf, len));
|
||||
for (int j = 0; j < len; j++) {
|
||||
StringShape shape(*building_blocks[i]);
|
||||
CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
|
||||
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -101,8 +99,7 @@ static void InitializeBuildingBlocks(
|
||||
Resource* resource = new Resource(Vector<const uc16>(buf, len));
|
||||
building_blocks[i] = Factory::NewExternalStringFromTwoByte(resource);
|
||||
for (int j = 0; j < len; j++) {
|
||||
StringShape shape(*building_blocks[i]);
|
||||
CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
|
||||
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -114,8 +111,7 @@ static void InitializeBuildingBlocks(
|
||||
building_blocks[i] =
|
||||
Factory::NewStringFromAscii(Vector<const char>(buf, len));
|
||||
for (int j = 0; j < len; j++) {
|
||||
StringShape shape(*building_blocks[i]);
|
||||
CHECK_EQ(buf[j], building_blocks[i]->Get(shape, j));
|
||||
CHECK_EQ(buf[j], building_blocks[i]->Get(j));
|
||||
}
|
||||
DeleteArray<char>(buf);
|
||||
break;
|
||||
@ -132,9 +128,7 @@ static Handle<String> ConstructLeft(
|
||||
for (int i = 0; i < depth; i++) {
|
||||
answer = Factory::NewConsString(
|
||||
answer,
|
||||
StringShape(*answer),
|
||||
building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
|
||||
StringShape(*building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]));
|
||||
building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
@ -147,9 +141,7 @@ static Handle<String> ConstructRight(
|
||||
for (int i = depth - 1; i >= 0; i--) {
|
||||
answer = Factory::NewConsString(
|
||||
building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
|
||||
StringShape(*building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]),
|
||||
answer,
|
||||
StringShape(*answer));
|
||||
answer);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
@ -166,19 +158,13 @@ static Handle<String> ConstructBalancedHelper(
|
||||
if (to - from == 2) {
|
||||
return Factory::NewConsString(
|
||||
building_blocks[from % NUMBER_OF_BUILDING_BLOCKS],
|
||||
StringShape(*building_blocks[from % NUMBER_OF_BUILDING_BLOCKS]),
|
||||
building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS],
|
||||
StringShape(*building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]));
|
||||
building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]);
|
||||
}
|
||||
Handle<String> part1 =
|
||||
ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
|
||||
Handle<String> part2 =
|
||||
ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
|
||||
return Factory::NewConsString(
|
||||
part1,
|
||||
StringShape(*part1),
|
||||
part2,
|
||||
StringShape(*part2));
|
||||
return Factory::NewConsString(part1, part2);
|
||||
}
|
||||
|
||||
|
||||
@ -216,8 +202,8 @@ static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
|
||||
CHECK_EQ(c, buffer2.GetNext());
|
||||
i++;
|
||||
}
|
||||
s1->Get(StringShape(*s1), s1->length() - 1);
|
||||
s2->Get(StringShape(*s2), s2->length() - 1);
|
||||
s1->Get(s1->length() - 1);
|
||||
s2->Get(s2->length() - 1);
|
||||
}
|
||||
|
||||
|
||||
@ -299,19 +285,13 @@ static Handle<String> ConstructSliceTree(
|
||||
Handle<String> rhs = building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS];
|
||||
if (gen() % 2 == 0)
|
||||
rhs = SliceOf(rhs);
|
||||
return Factory::NewConsString(lhs,
|
||||
StringShape(*lhs),
|
||||
rhs,
|
||||
StringShape(*rhs));
|
||||
return Factory::NewConsString(lhs, rhs);
|
||||
}
|
||||
Handle<String> part1 =
|
||||
ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
|
||||
Handle<String> part2 =
|
||||
ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
|
||||
Handle<String> branch = Factory::NewConsString(part1,
|
||||
StringShape(*part1),
|
||||
part2,
|
||||
StringShape(*part2));
|
||||
Handle<String> branch = Factory::NewConsString(part1, part2);
|
||||
if (gen() % 2 == 0)
|
||||
return branch;
|
||||
return(SliceOf(branch));
|
||||
@ -351,15 +331,9 @@ TEST(DeepAscii) {
|
||||
Factory::NewStringFromAscii(Vector<const char>(foo, DEEP_ASCII_DEPTH));
|
||||
Handle<String> foo_string = Factory::NewStringFromAscii(CStrVector("foo"));
|
||||
for (int i = 0; i < DEEP_ASCII_DEPTH; i += 10) {
|
||||
string = Factory::NewConsString(string,
|
||||
StringShape(*string),
|
||||
foo_string,
|
||||
StringShape(*foo_string));
|
||||
string = Factory::NewConsString(string, foo_string);
|
||||
}
|
||||
Handle<String> flat_string = Factory::NewConsString(string,
|
||||
StringShape(*string),
|
||||
foo_string,
|
||||
StringShape(*foo_string));
|
||||
Handle<String> flat_string = Factory::NewConsString(string, foo_string);
|
||||
FlattenString(flat_string);
|
||||
|
||||
for (int i = 0; i < 500; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user