Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 98a7237dead7f0d44923c5c74b4cd483023f15f6..572d46d38f0954e3f095db6efc42eec914ecad59 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -1206,73 +1206,11 @@ Handle<String> String::SlowFlatten(Handle<ConsString> cons, |
} |
cons->set_first(*result); |
cons->set_second(isolate->heap()->empty_string()); |
+ ASSERT(result->IsFlat()); |
return result; |
} |
-MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) { |
-#ifdef DEBUG |
- // Do not attempt to flatten in debug mode when allocation is not |
- // allowed. This is to avoid an assertion failure when allocating. |
- // Flattening strings is the only case where we always allow |
- // allocation because no GC is performed if the allocation fails. |
- if (!AllowHeapAllocation::IsAllowed()) return this; |
-#endif |
- |
- Heap* heap = GetHeap(); |
- switch (StringShape(this).representation_tag()) { |
- case kConsStringTag: { |
- ConsString* cs = ConsString::cast(this); |
- if (cs->second()->length() == 0) { |
- return cs->first(); |
- } |
- // There's little point in putting the flat string in new space if the |
- // cons string is in old space. It can never get GCed until there is |
- // an old space GC. |
- PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED; |
- int len = length(); |
- Object* object; |
- String* result; |
- if (IsOneByteRepresentation()) { |
- { MaybeObject* maybe_object = |
- heap->AllocateRawOneByteString(len, tenure); |
- if (!maybe_object->ToObject(&object)) return maybe_object; |
- } |
- result = String::cast(object); |
- String* first = cs->first(); |
- int first_length = first->length(); |
- uint8_t* dest = SeqOneByteString::cast(result)->GetChars(); |
- WriteToFlat(first, dest, 0, first_length); |
- String* second = cs->second(); |
- WriteToFlat(second, |
- dest + first_length, |
- 0, |
- len - first_length); |
- } else { |
- { MaybeObject* maybe_object = |
- heap->AllocateRawTwoByteString(len, tenure); |
- if (!maybe_object->ToObject(&object)) return maybe_object; |
- } |
- result = String::cast(object); |
- uc16* dest = SeqTwoByteString::cast(result)->GetChars(); |
- String* first = cs->first(); |
- int first_length = first->length(); |
- WriteToFlat(first, dest, 0, first_length); |
- String* second = cs->second(); |
- WriteToFlat(second, |
- dest + first_length, |
- 0, |
- len - first_length); |
- } |
- cs->set_first(result); |
- cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER); |
- return result; |
- } |
- default: |
- return this; |
- } |
-} |
- |
bool String::MakeExternal(v8::String::ExternalStringResource* resource) { |
// Externalizing twice leaks the external resource, so it's |
@@ -6040,18 +5978,6 @@ int Map::NextFreePropertyIndex() { |
} |
-AccessorDescriptor* Map::FindAccessor(Name* name) { |
- DescriptorArray* descs = instance_descriptors(); |
- int number_of_own_descriptors = NumberOfOwnDescriptors(); |
- for (int i = 0; i < number_of_own_descriptors; i++) { |
- if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) { |
- return descs->GetCallbacks(i); |
- } |
- } |
- return NULL; |
-} |
- |
- |
void JSReceiver::LocalLookup( |
Name* name, LookupResult* result, bool search_hidden_prototypes) { |
ASSERT(name->IsName()); |
@@ -6557,8 +6483,8 @@ bool JSObject::DefineFastAccessor(Handle<JSObject> object, |
if (result.IsFound()) { |
Handle<Map> target(result.GetTransitionTarget()); |
int descriptor_number = target->LastAdded(); |
- ASSERT(target->instance_descriptors()->GetKey(descriptor_number) |
- ->Equals(*name)); |
+ ASSERT(Name::Equals(name, |
+ handle(target->instance_descriptors()->GetKey(descriptor_number)))); |
return TryAccessorTransition(object, target, descriptor_number, |
component, accessor, attributes); |
} |
@@ -8378,7 +8304,7 @@ String::FlatContent String::GetFlatContent() { |
} else { |
start = ExternalAsciiString::cast(string)->GetChars(); |
} |
- return FlatContent(Vector<const uint8_t>(start + offset, length)); |
+ return FlatContent(start + offset, length); |
} else { |
ASSERT(shape.encoding_tag() == kTwoByteStringTag); |
const uc16* start; |
@@ -8387,7 +8313,7 @@ String::FlatContent String::GetFlatContent() { |
} else { |
start = ExternalTwoByteString::cast(string)->GetChars(); |
} |
- return FlatContent(Vector<const uc16>(start + offset, length)); |
+ return FlatContent(start + offset, length); |
} |
} |
@@ -9027,6 +8953,7 @@ class StringComparator { |
bool String::SlowEquals(String* other) { |
+ DisallowHeapAllocation no_gc; |
// Fast check: negative check with lengths. |
int len = length(); |
if (len != other->length()) return false; |
@@ -9056,14 +8983,10 @@ bool String::SlowEquals(String* other) { |
// before we try to flatten the strings. |
if (this->Get(0) != other->Get(0)) return false; |
- String* lhs = this->TryFlattenGetString(); |
- String* rhs = other->TryFlattenGetString(); |
- |
// TODO(dcarney): Compare all types of flat strings with a Visitor. |
- if (StringShape(lhs).IsSequentialAscii() && |
- StringShape(rhs).IsSequentialAscii()) { |
- const uint8_t* str1 = SeqOneByteString::cast(lhs)->GetChars(); |
- const uint8_t* str2 = SeqOneByteString::cast(rhs)->GetChars(); |
+ if (IsSeqOneByteString() && other->IsSeqOneByteString()) { |
+ const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars(); |
+ const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars(); |
return CompareRawStringContents(str1, str2, len); |
} |
@@ -9071,7 +8994,57 @@ bool String::SlowEquals(String* other) { |
StringComparator comparator(isolate->objects_string_compare_iterator_a(), |
isolate->objects_string_compare_iterator_b()); |
- return comparator.Equals(static_cast<unsigned>(len), lhs, rhs); |
+ return comparator.Equals(static_cast<unsigned>(len), this, other); |
+} |
+ |
+ |
+bool String::SlowEquals(Handle<String> one, Handle<String> two) { |
+ // Fast check: negative check with lengths. |
+ int one_length = one->length(); |
+ if (one_length != two->length()) return false; |
+ if (one_length == 0) return true; |
+ |
+ // Fast check: if hash code is computed for both strings |
+ // a fast negative check can be performed. |
+ if (one->HasHashCode() && two->HasHashCode()) { |
+#ifdef ENABLE_SLOW_ASSERTS |
+ if (FLAG_enable_slow_asserts) { |
+ if (one->Hash() != two->Hash()) { |
+ bool found_difference = false; |
+ for (int i = 0; i < one_length; i++) { |
+ if (one->Get(i) != two->Get(i)) { |
+ found_difference = true; |
+ break; |
+ } |
+ } |
+ ASSERT(found_difference); |
+ } |
+ } |
+#endif |
+ if (one->Hash() != two->Hash()) return false; |
+ } |
+ |
+ // We know the strings are both non-empty. Compare the first chars |
+ // before we try to flatten the strings. |
+ if (one->Get(0) != two->Get(0)) return false; |
+ |
+ one = String::Flatten(one); |
+ two = String::Flatten(two); |
+ |
+ DisallowHeapAllocation no_gc; |
+ String::FlatContent flat1 = one->GetFlatContent(); |
+ String::FlatContent flat2 = two->GetFlatContent(); |
+ |
+ if (flat1.IsAscii() && flat2.IsAscii()) { |
+ return CompareRawStringContents(flat1.ToOneByteVector().start(), |
+ flat2.ToOneByteVector().start(), |
+ one_length); |
+ } else { |
+ for (int i = 0; i < one_length; i++) { |
+ if (flat1.Get(i) != flat2.Get(i)) return false; |
+ } |
+ return true; |
+ } |
} |