Author: [email protected]
Date: Fri May  1 04:16:29 2009
New Revision: 1830

Modified:
    branches/bleeding_edge/src/heap.cc
    branches/bleeding_edge/src/ia32/regexp-macro-assembler-ia32.cc
    branches/bleeding_edge/src/interpreter-irregexp.cc
    branches/bleeding_edge/src/jsregexp.cc
    branches/bleeding_edge/src/log.cc
    branches/bleeding_edge/src/objects-inl.h
    branches/bleeding_edge/src/objects.cc
    branches/bleeding_edge/src/objects.h
    branches/bleeding_edge/src/runtime.cc
    branches/bleeding_edge/test/cctest/test-api.cc

Log:
When strings can change from an ASCII representation to a
UC16 representation we need to be careful about flat strings.
Flat strings can be sliced or cons strings that have a flat
string under them, so when we ask a flat cons or a slice whether
it is ASCII or not we should ask the underlying string about
its representation.  This should fix
http://code.google.com/p/chromium/issues/detail?id=10971
Review URL: http://codereview.chromium.org/100249

Modified: branches/bleeding_edge/src/heap.cc
==============================================================================
--- branches/bleeding_edge/src/heap.cc  (original)
+++ branches/bleeding_edge/src/heap.cc  Fri May  1 04:16:29 2009
@@ -1423,8 +1423,8 @@
    int first_length = first->length();
    int second_length = second->length();
    int length = first_length + second_length;
-  bool is_ascii = StringShape(first).IsAsciiRepresentation()
-      && StringShape(second).IsAsciiRepresentation();
+  bool is_ascii = first->IsAsciiRepresentation()
+      && second->IsAsciiRepresentation();

    // If the resulting string is small make a flat string.
    if (length < String::kMinNonFlatLength) {
@@ -1484,15 +1484,15 @@

    Map* map;
    if (length <= String::kMaxShortStringSize) {
-    map = StringShape(buffer).IsAsciiRepresentation() ?
+    map = buffer->IsAsciiRepresentation() ?
        short_sliced_ascii_string_map() :
        short_sliced_string_map();
    } else if (length <= String::kMaxMediumStringSize) {
-    map = StringShape(buffer).IsAsciiRepresentation() ?
+    map = buffer->IsAsciiRepresentation() ?
        medium_sliced_ascii_string_map() :
        medium_sliced_string_map();
    } else {
-    map = StringShape(buffer).IsAsciiRepresentation() ?
+    map = buffer->IsAsciiRepresentation() ?
        long_sliced_ascii_string_map() :
        long_sliced_string_map();
    }
@@ -1524,7 +1524,7 @@
      buffer->TryFlatten();
    }

-  Object* result = StringShape(buffer).IsAsciiRepresentation()
+  Object* result = buffer->IsAsciiRepresentation()
        ? AllocateRawAsciiString(length)
        : AllocateRawTwoByteString(length);
    if (result->IsFailure()) return result;

Modified: branches/bleeding_edge/src/ia32/regexp-macro-assembler-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/regexp-macro-assembler-ia32.cc       
(original)
+++ branches/bleeding_edge/src/ia32/regexp-macro-assembler-ia32.cc      Fri May 
  
1 04:16:29 2009
@@ -974,7 +974,7 @@
    int start_offset = previous_index;
    int end_offset = subject_ptr->length();

-  bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
+  bool is_ascii = subject->IsAsciiRepresentation();

    if (StringShape(subject_ptr).IsCons()) {
      subject_ptr = ConsString::cast(subject_ptr)->first();
@@ -985,7 +985,7 @@
      subject_ptr = slice->buffer();
    }
    // Ensure that an underlying string has the same ascii-ness.
-  ASSERT(StringShape(subject_ptr).IsAsciiRepresentation() == is_ascii);
+  ASSERT(subject_ptr->IsAsciiRepresentation() == is_ascii);
    ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString());
    // String is now either Sequential or External
    int char_size_shift = is_ascii ? 0 : 1;
@@ -1112,7 +1112,7 @@
    ASSERT(subject->IsExternalString() || subject->IsSeqString());
    ASSERT(start_index >= 0);
    ASSERT(start_index <= subject->length());
-  if (StringShape(subject).IsAsciiRepresentation()) {
+  if (subject->IsAsciiRepresentation()) {
      const byte* address;
      if (StringShape(subject).IsExternal()) {
        const char* data =  
ExternalAsciiString::cast(subject)->resource()->data();
@@ -1152,7 +1152,7 @@

    Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
    // Current string.
-  bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
+  bool is_ascii = subject->IsAsciiRepresentation();

    ASSERT(re_code->instruction_start() <= *return_address);
    ASSERT(*return_address <=
@@ -1171,7 +1171,7 @@
    }

    // String might have changed.
-  if (StringShape(*subject).IsAsciiRepresentation() != is_ascii) {
+  if (subject->IsAsciiRepresentation() != is_ascii) {
      // If we changed between an ASCII and an UC16 string, the specialized
      // code cannot be used, and we need to restart regexp matching from
      // scratch (including, potentially, compiling a new version of the  
code).

Modified: branches/bleeding_edge/src/interpreter-irregexp.cc
==============================================================================
--- branches/bleeding_edge/src/interpreter-irregexp.cc  (original)
+++ branches/bleeding_edge/src/interpreter-irregexp.cc  Fri May  1 04:16:29  
2009
@@ -574,7 +574,7 @@
    AssertNoAllocation a;
    const byte* code_base = code_array->GetDataStartAddress();
    uc16 previous_char = '\n';
-  if (StringShape(*subject).IsAsciiRepresentation()) {
+  if (subject->IsAsciiRepresentation()) {
      Vector<const char> subject_vector = subject->ToAsciiVector();
      if (start_position != 0) previous_char = subject_vector[start_position  
- 1];
      return RawMatch(code_base,

Modified: branches/bleeding_edge/src/jsregexp.cc
==============================================================================
--- branches/bleeding_edge/src/jsregexp.cc      (original)
+++ branches/bleeding_edge/src/jsregexp.cc      Fri May  1 04:16:29 2009
@@ -440,7 +440,7 @@
  #ifdef V8_ARCH_IA32
      RegExpMacroAssemblerIA32::Result res;
      do {
-      bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
+      bool is_ascii = subject->IsAsciiRepresentation();
        if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
          return Handle<Object>::null();
        }
@@ -463,7 +463,7 @@
      rc = (res == RegExpMacroAssemblerIA32::SUCCESS);
  #endif
    } else {
-    bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
+    bool is_ascii = subject->IsAsciiRepresentation();
      if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
        return Handle<Object>::null();
      }

Modified: branches/bleeding_edge/src/log.cc
==============================================================================
--- branches/bleeding_edge/src/log.cc   (original)
+++ branches/bleeding_edge/src/log.cc   Fri May  1 04:16:29 2009
@@ -366,7 +366,7 @@
    if (len > 0x1000)
      len = 0x1000;
    if (show_impl_info) {
-    Append(StringShape(str).IsAsciiRepresentation() ? 'a' : '2');
+    Append(str->IsAsciiRepresentation() ? 'a' : '2');
      if (StringShape(str).IsExternal())
        Append('e');
      if (StringShape(str).IsSymbol())

Modified: branches/bleeding_edge/src/objects-inl.h
==============================================================================
--- branches/bleeding_edge/src/objects-inl.h    (original)
+++ branches/bleeding_edge/src/objects-inl.h    Fri May  1 04:16:29 2009
@@ -144,14 +144,14 @@
  bool Object::IsSeqAsciiString() {
    if (!IsString()) return false;
    return StringShape(String::cast(this)).IsSequential() &&
-         StringShape(String::cast(this)).IsAsciiRepresentation();
+         String::cast(this)->IsAsciiRepresentation();
  }


  bool Object::IsSeqTwoByteString() {
    if (!IsString()) return false;
    return StringShape(String::cast(this)).IsSequential() &&
-         StringShape(String::cast(this)).IsTwoByteRepresentation();
+         String::cast(this)->IsTwoByteRepresentation();
  }


@@ -164,14 +164,14 @@
  bool Object::IsExternalAsciiString() {
    if (!IsString()) return false;
    return StringShape(String::cast(this)).IsExternal() &&
-         StringShape(String::cast(this)).IsAsciiRepresentation();
+         String::cast(this)->IsAsciiRepresentation();
  }


  bool Object::IsExternalTwoByteString() {
    if (!IsString()) return false;
    return StringShape(String::cast(this)).IsExternal() &&
-         StringShape(String::cast(this)).IsTwoByteRepresentation();
+         String::cast(this)->IsTwoByteRepresentation();
  }


@@ -211,13 +211,28 @@
  }


-bool StringShape::IsAsciiRepresentation() {
-  return (type_ & kStringEncodingMask) == kAsciiStringTag;
+bool String::IsAsciiRepresentation() {
+  uint32_t type = map()->instance_type();
+  if ((type & kStringRepresentationMask) == kSlicedStringTag) {
+    return SlicedString::cast(this)->buffer()->IsAsciiRepresentation();
+  }
+  if ((type & kStringRepresentationMask) == kConsStringTag &&
+      ConsString::cast(this)->second()->length() == 0) {
+    return ConsString::cast(this)->first()->IsAsciiRepresentation();
+  }
+  return (type & kStringEncodingMask) == kAsciiStringTag;
  }


-bool StringShape::IsTwoByteRepresentation() {
-  return (type_ & kStringEncodingMask) == kTwoByteStringTag;
+bool String::IsTwoByteRepresentation() {
+  uint32_t type = map()->instance_type();
+  if ((type & kStringRepresentationMask) == kSlicedStringTag) {
+    return SlicedString::cast(this)->buffer()->IsTwoByteRepresentation();
+  } else if ((type & kStringRepresentationMask) == kConsStringTag &&
+             ConsString::cast(this)->second()->length() == 0) {
+    return ConsString::cast(this)->first()->IsTwoByteRepresentation();
+  }
+  return (type & kStringEncodingMask) == kTwoByteStringTag;
  }


@@ -1476,7 +1491,7 @@
    ASSERT(index >= 0 && index < length());
    ASSERT(StringShape(this).IsSequential());

-  return StringShape(this).IsAsciiRepresentation()
+  return this->IsAsciiRepresentation()
        ? SeqAsciiString::cast(this)->SeqAsciiStringSet(index, value)
        : SeqTwoByteString::cast(this)->SeqTwoByteStringSet(index, value);
  }
@@ -1576,11 +1591,6 @@


  String* ConsString::first() {
-  ASSERT(String::cast(READ_FIELD(this, kSecondOffset))->length() != 0 ||
-      StringShape(
-          String::cast(
-              READ_FIELD(this, kFirstOffset))).IsAsciiRepresentation()
-          == StringShape(this).IsAsciiRepresentation());
    return String::cast(READ_FIELD(this, kFirstOffset));
  }

@@ -1613,10 +1623,6 @@


  String* SlicedString::buffer() {
-  ASSERT(
-      StringShape(
-          String::cast(READ_FIELD(this,  
kBufferOffset))).IsAsciiRepresentation()
-      == StringShape(this).IsAsciiRepresentation());
    return String::cast(READ_FIELD(this, kBufferOffset));
  }


Modified: branches/bleeding_edge/src/objects.cc
==============================================================================
--- branches/bleeding_edge/src/objects.cc       (original)
+++ branches/bleeding_edge/src/objects.cc       Fri May  1 04:16:29 2009
@@ -602,8 +602,6 @@
        if (StringShape(String::cast(ok)).IsCons()) {
          ss->set_buffer(ConsString::cast(ok)->first());
        }
-      ASSERT(StringShape(this).IsAsciiRepresentation() ==
-          StringShape(ss->buffer()).IsAsciiRepresentation());
        return this;
      }
      case kConsStringTag: {
@@ -618,7 +616,7 @@
        int len = length();
        Object* object;
        String* result;
-      if (StringShape(this).IsAsciiRepresentation()) {
+      if (IsAsciiRepresentation()) {
          object = Heap::AllocateRawAsciiString(len, tenure);
          if (object->IsFailure()) return object;
          result = String::cast(object);
@@ -956,10 +954,11 @@
    // Avoid calling functions such as FixedArray::cast during GC, which
    // read map pointer of this object again.
    InstanceType instance_type = map->instance_type();
+  uint32_t type = static_cast<uint32_t>(instance_type);

    if (instance_type < FIRST_NONSTRING_TYPE
        && (StringShape(instance_type).IsSequential())) {
-    if (StringShape(instance_type).IsAsciiRepresentation()) {
+    if ((type & kStringEncodingMask) == kAsciiStringTag) {
        SeqAsciiString* seq_ascii_this =  
reinterpret_cast<SeqAsciiString*>(this);
        return seq_ascii_this->SeqAsciiStringSize(instance_type);
      } else {
@@ -3235,7 +3234,7 @@


  int String::Utf8Length() {
-  if (StringShape(this).IsAsciiRepresentation()) return length();
+  if (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)
@@ -3251,7 +3250,7 @@


  Vector<const char> String::ToAsciiVector() {
-  ASSERT(StringShape(this).IsAsciiRepresentation());
+  ASSERT(IsAsciiRepresentation());
    ASSERT(IsFlat());

    int offset = 0;
@@ -3282,7 +3281,7 @@


  Vector<const uc16> String::ToUC16Vector() {
-  ASSERT(StringShape(this).IsTwoByteRepresentation());
+  ASSERT(IsTwoByteRepresentation());
    ASSERT(IsFlat());

    int offset = 0;
@@ -3385,7 +3384,7 @@


  const uc16* String::GetTwoByteData(unsigned start) {
-  ASSERT(!StringShape(this).IsAsciiRepresentation());
+  ASSERT(!IsAsciiRepresentation());
    switch (StringShape(this).representation_tag()) {
      case kSeqStringTag:
        return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
@@ -3680,7 +3679,7 @@
    }
    switch (StringShape(input).representation_tag()) {
      case kSeqStringTag:
-      if (StringShape(input).IsAsciiRepresentation()) {
+      if (input->IsAsciiRepresentation()) {
          SeqAsciiString* str = SeqAsciiString::cast(input);
          return str->SeqAsciiStringReadBlock(&rbb->remaining,
                                              offset_ptr,
@@ -3701,7 +3700,7 @@
                                                                offset_ptr,
                                                                max_chars);
      case kExternalStringTag:
-      if (StringShape(input).IsAsciiRepresentation()) {
+      if (input->IsAsciiRepresentation()) {
          return  
ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
              &rbb->remaining,
              offset_ptr,
@@ -3754,7 +3753,7 @@
    if (str_ == NULL) return;
    Handle<String> str(str_);
    ASSERT(str->IsFlat());
-  is_ascii_ = StringShape(*str).IsAsciiRepresentation();
+  is_ascii_ = str->IsAsciiRepresentation();
    if (is_ascii_) {
      start_ = str->ToAsciiVector().start();
    } else {
@@ -3795,7 +3794,7 @@

    switch (StringShape(input).representation_tag()) {
      case kSeqStringTag:
-      if (StringShape(input).IsAsciiRepresentation()) {
+      if (input->IsAsciiRepresentation()) {
          SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
                                                                    
offset_ptr,
                                                                    
max_chars);
@@ -3817,7 +3816,7 @@
                                                                    
max_chars);
        return;
      case kExternalStringTag:
-      if (StringShape(input).IsAsciiRepresentation()) {
+      if (input->IsAsciiRepresentation()) {
           ExternalAsciiString::cast(input)->
               ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr,  
max_chars);
         } else {
@@ -4147,7 +4146,7 @@
  template <typename IteratorA>
  static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) {
    if (b->IsFlat()) {
-    if (StringShape(b).IsAsciiRepresentation()) {
+    if (b->IsAsciiRepresentation()) {
        VectorIterator<char> ib(b->ToAsciiVector());
        return CompareStringContents(ia, &ib);
      } else {
@@ -4187,10 +4186,10 @@
    }

    if (this->IsFlat()) {
-    if (StringShape(this).IsAsciiRepresentation()) {
+    if (IsAsciiRepresentation()) {
        Vector<const char> vec1 = this->ToAsciiVector();
        if (other->IsFlat()) {
-        if (StringShape(other).IsAsciiRepresentation()) {
+        if (other->IsAsciiRepresentation()) {
            Vector<const char> vec2 = other->ToAsciiVector();
            return CompareRawStringContents(vec1, vec2);
          } else {
@@ -4209,7 +4208,7 @@
        Vector<const uc16> vec1 = this->ToUC16Vector();
        if (CheckVectorForBug9746(vec1)) return false;
        if (other->IsFlat()) {
-        if (StringShape(other).IsAsciiRepresentation()) {
+        if (other->IsAsciiRepresentation()) {
            VectorIterator<uc16> buf1(vec1);
            VectorIterator<char> ib(other->ToAsciiVector());
            return CompareStringContents(&buf1, &ib);

Modified: branches/bleeding_edge/src/objects.h
==============================================================================
--- branches/bleeding_edge/src/objects.h        (original)
+++ branches/bleeding_edge/src/objects.h        Fri May  1 04:16:29 2009
@@ -3207,8 +3207,6 @@
    inline explicit StringShape(String* s);
    inline explicit StringShape(Map* s);
    inline explicit StringShape(InstanceType t);
-  inline bool IsAsciiRepresentation();
-  inline bool IsTwoByteRepresentation();
    inline bool IsSequential();
    inline bool IsExternal();
    inline bool IsCons();
@@ -3259,6 +3257,9 @@
    // use the length() and set_length methods.
    inline uint32_t length_field();
    inline void set_length_field(uint32_t value);
+
+  inline bool IsAsciiRepresentation();
+  inline bool IsTwoByteRepresentation();

    // Get and set individual two byte chars in the string.
    inline void Set(int index, uint16_t value);

Modified: branches/bleeding_edge/src/runtime.cc
==============================================================================
--- branches/bleeding_edge/src/runtime.cc       (original)
+++ branches/bleeding_edge/src/runtime.cc       Fri May  1 04:16:29 2009
@@ -1282,7 +1282,7 @@
          parts_(Factory::NewFixedArray(estimated_part_count)),
          part_count_(0),
          character_count_(0),
-        is_ascii_(StringShape(*subject).IsAsciiRepresentation()) {
+        is_ascii_(subject->IsAsciiRepresentation()) {
      // Require a non-zero initial size. Ensures that doubling the size to
      // extend the array will work.
      ASSERT(estimated_part_count > 0);
@@ -1326,7 +1326,7 @@
      int length = string->length();
      ASSERT(length > 0);
      AddElement(*string);
-    if (!StringShape(*string).IsAsciiRepresentation()) {
+    if (!string->IsAsciiRepresentation()) {
        is_ascii_ = false;
      }
      IncrementCharacterCount(length);
@@ -1583,14 +1583,14 @@
                                    int capture_count,
                                    int subject_length) {
    ASSERT(replacement->IsFlat());
-  if (StringShape(*replacement).IsAsciiRepresentation()) {
+  if (replacement->IsAsciiRepresentation()) {
      AssertNoAllocation no_alloc;
      ParseReplacementPattern(&parts_,
                              replacement->ToAsciiVector(),
                              capture_count,
                              subject_length);
    } else {
-    ASSERT(StringShape(*replacement).IsTwoByteRepresentation());
+    ASSERT(replacement->IsTwoByteRepresentation());
      AssertNoAllocation no_alloc;

      ParseReplacementPattern(&parts_,
@@ -2165,7 +2165,7 @@
    // algorithm is unnecessary overhead.
    if (pattern_length == 1) {
      AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
-    if (StringShape(*sub).IsAsciiRepresentation()) {
+    if (sub->IsAsciiRepresentation()) {
        uc16 pchar = pat->Get(0);
        if (pchar > String::kMaxAsciiCharCode) {
          return -1;
@@ -2190,15 +2190,15 @@

    AssertNoAllocation no_heap_allocation;  // ensure vectors stay valid
    // dispatch on type of strings
-  if (StringShape(*pat).IsAsciiRepresentation()) {
+  if (pat->IsAsciiRepresentation()) {
      Vector<const char> pat_vector = pat->ToAsciiVector();
-    if (StringShape(*sub).IsAsciiRepresentation()) {
+    if (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 (StringShape(*sub).IsAsciiRepresentation()) {
+  if (sub->IsAsciiRepresentation()) {
      return StringMatchStrategy(sub->ToAsciiVector(), pat_vector,  
start_index);
    }
    return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
@@ -3329,7 +3329,7 @@
    // 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 = StringShape(s).IsAsciiRepresentation()
+  Object* o = s->IsAsciiRepresentation()
        ? Heap::AllocateRawAsciiString(length)
        : Heap::AllocateRawTwoByteString(length);
    if (o->IsFailure()) return o;
@@ -3680,7 +3680,7 @@
      if (first->IsString()) return first;
    }

-  bool ascii = StringShape(special).IsAsciiRepresentation();
+  bool ascii = special->IsAsciiRepresentation();
    int position = 0;
    for (int i = 0; i < array_length; i++) {
      Object* elt = fixed_array->get(i);
@@ -3700,7 +3700,7 @@
          return Failure::OutOfMemoryException();
        }
        position += element_length;
-      if (ascii && !StringShape(element).IsAsciiRepresentation()) {
+      if (ascii && !element->IsAsciiRepresentation()) {
          ascii = false;
        }
      } else {
@@ -4757,10 +4757,10 @@
    FixedArray* output_array = output->elements();
    RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
    bool result;
-  if (StringShape(*str).IsAsciiRepresentation()) {
+  if (str->IsAsciiRepresentation()) {
      result = DateParser::Parse(str->ToAsciiVector(), output_array);
    } else {
-    ASSERT(StringShape(*str).IsTwoByteRepresentation());
+    ASSERT(str->IsTwoByteRepresentation());
      result = DateParser::Parse(str->ToUC16Vector(), output_array);
    }

@@ -6574,9 +6574,9 @@
    if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
      return true;
    }
-  if (StringShape(String::cast(str)).IsAsciiRepresentation()) {
+  if (String::cast(str)->IsAsciiRepresentation()) {
      return ExternalAsciiString::cast(str)->resource() != NULL;
-  } else if (StringShape(String::cast(str)).IsTwoByteRepresentation()) {
+  } else if (String::cast(str)->IsTwoByteRepresentation()) {
      return ExternalTwoByteString::cast(str)->resource() != NULL;
    } else {
      return true;

Modified: branches/bleeding_edge/test/cctest/test-api.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-api.cc      (original)
+++ branches/bleeding_edge/test/cctest/test-api.cc      Fri May  1 04:16:29 2009
@@ -420,7 +420,7 @@
   public:
    static int dispose_count;

-  explicit TestAsciiResource(char* data)
+  explicit TestAsciiResource(const char* data)
        : data_(data),
          length_(strlen(data)) { }

@@ -437,7 +437,7 @@
      return length_;
    }
   private:
-  char* data_;
+  const char* data_;
    size_t length_;
  };

@@ -6153,6 +6153,117 @@
  }


+class AsciiVectorResource : public v8::String::ExternalAsciiStringResource  
{
+ public:
+  explicit AsciiVectorResource(i::Vector<const char> vector)
+      : data_(vector) {}
+  virtual ~AsciiVectorResource() {}
+  virtual size_t length() const { return data_.length(); }
+  virtual const char* data() const { return data_.start(); }
+ private:
+  i::Vector<const char> data_;
+};
+
+
+class UC16VectorResource : public v8::String::ExternalStringResource {
+ public:
+  explicit UC16VectorResource(i::Vector<const i::uc16> vector)
+      : data_(vector) {}
+  virtual ~UC16VectorResource() {}
+  virtual size_t length() const { return data_.length(); }
+  virtual const i::uc16* data() const { return data_.start(); }
+ private:
+  i::Vector<const i::uc16> data_;
+};
+
+
+static void MorphAString(i::String* string,
+                         AsciiVectorResource* ascii_resource,
+                         UC16VectorResource* uc16_resource) {
+  CHECK(i::StringShape(string).IsExternal());
+  if (string->IsAsciiRepresentation()) {
+    // Check old map is not symbol or long.
+    CHECK(string->map() == i::Heap::short_external_ascii_string_map() ||
+          string->map() == i::Heap::medium_external_ascii_string_map());
+    // Morph external string to be TwoByte string.
+    if (string->length() <= i::String::kMaxShortStringSize) {
+      string->set_map(i::Heap::short_external_string_map());
+    } else {
+      string->set_map(i::Heap::medium_external_string_map());
+    }
+    i::ExternalTwoByteString* morphed =
+         i::ExternalTwoByteString::cast(string);
+    morphed->set_resource(uc16_resource);
+  } else {
+    // Check old map is not symbol or long.
+    CHECK(string->map() == i::Heap::short_external_string_map() ||
+          string->map() == i::Heap::medium_external_string_map());
+    // Morph external string to be ASCII string.
+    if (string->length() <= i::String::kMaxShortStringSize) {
+      string->set_map(i::Heap::short_external_ascii_string_map());
+    } else {
+      string->set_map(i::Heap::medium_external_ascii_string_map());
+    }
+    i::ExternalAsciiString* morphed =
+         i::ExternalAsciiString::cast(string);
+    morphed->set_resource(ascii_resource);
+  }
+}
+
+
+// Test that we can still flatten a string if the components it is built up
+// from have been turned into 16 bit strings in the mean time.
+THREADED_TEST(MorphCompositeStringTest) {
+  const char* c_string = "Now is the time for all good men"
+                         " to come to the aid of the party";
+  uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
+  {
+    v8::HandleScope scope;
+    LocalContext env;
+    AsciiVectorResource ascii_resource(
+        i::Vector<const char>(c_string, strlen(c_string)));
+    UC16VectorResource uc16_resource(
+        i::Vector<const uint16_t>(two_byte_string, strlen(c_string)));
+
+    Local<String> lhs(v8::Utils::ToLocal(
+        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
+    Local<String> rhs(v8::Utils::ToLocal(
+        i::Factory::NewExternalStringFromAscii(&ascii_resource)));
+
+    env->Global()->Set(v8_str("lhs"), lhs);
+    env->Global()->Set(v8_str("rhs"), rhs);
+
+    CompileRun(
+        "var cons = lhs + rhs;"
+        "var slice = lhs.substring(1, lhs.length - 1);"
+        "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 -  
1);");
+
+    MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource,  
&uc16_resource);
+    MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource,  
&uc16_resource);
+
+    // Now do some stuff to make sure the strings are flattened, etc.
+    CompileRun(
+        "/[^a-z]/.test(cons);"
+        "/[^a-z]/.test(slice);"
+        "/[^a-z]/.test(slice_on_cons);");
+    const char* expected_cons =
+        "Now is the time for all good men to come to the aid of the party"
+        "Now is the time for all good men to come to the aid of the party";
+    const char* expected_slice =
+        "ow is the time for all good men to come to the aid of the part";
+    const char* expected_slice_on_cons =
+        "ow is the time for all good men to come to the aid of the party"
+        "Now is the time for all good men to come to the aid of the part";
+    CHECK_EQ(String::New(expected_cons),
+             env->Global()->Get(v8_str("cons")));
+    CHECK_EQ(String::New(expected_slice),
+             env->Global()->Get(v8_str("slice")));
+    CHECK_EQ(String::New(expected_slice_on_cons),
+             env->Global()->Get(v8_str("slice_on_cons")));
+  }
+}
+
+
  class RegExpStringModificationTest {
   public:
    RegExpStringModificationTest()
@@ -6197,26 +6308,6 @@
    }
   private:

-  class AsciiVectorResource : public  
v8::String::ExternalAsciiStringResource {
-   public:
-    explicit AsciiVectorResource(i::Vector<const char> vector)
-        : data_(vector) {}
-    virtual ~AsciiVectorResource() {}
-    virtual size_t length() const { return data_.length(); }
-    virtual const char* data() const { return data_.start(); }
-   private:
-    i::Vector<const char> data_;
-  };
-  class UC16VectorResource : public v8::String::ExternalStringResource {
-   public:
-    explicit UC16VectorResource(i::Vector<const i::uc16> vector)
-        : data_(vector) {}
-    virtual ~UC16VectorResource() {}
-    virtual size_t length() const { return data_.length(); }
-    virtual const i::uc16* data() const { return data_.start(); }
-   private:
-    i::Vector<const i::uc16> data_;
-  };
    // Number of string modifications required.
    static const int kRequiredModifications = 5;
    static const int kMaxModifications = 100;
@@ -6240,25 +6331,7 @@
          v8::Locker lock;
          // Swap string between ascii and two-byte representation.
          i::String* string = *input_;
-        CHECK(i::StringShape(string).IsExternal());
-        if (i::StringShape(string).IsAsciiRepresentation()) {
-          // Morph external string to be TwoByte string.
-          i::ExternalAsciiString* ext_string =
-              i::ExternalAsciiString::cast(string);
-          i::ExternalTwoByteString* morphed =
-              reinterpret_cast<i::ExternalTwoByteString*>(ext_string);
-          morphed->map()->set_instance_type(i::SHORT_EXTERNAL_STRING_TYPE);
-          morphed->set_resource(&uc16_resource_);
-        } else {
-          // Morph external string to be ASCII string.
-          i::ExternalTwoByteString* ext_string =
-              i::ExternalTwoByteString::cast(string);
-          i::ExternalAsciiString* morphed =
-              reinterpret_cast<i::ExternalAsciiString*>(ext_string);
-          morphed->map()->set_instance_type(
-              i::SHORT_EXTERNAL_ASCII_STRING_TYPE);
-          morphed->set_resource(&ascii_resource_);
-        }
+        MorphAString(string, &ascii_resource_, &uc16_resource_);
          morphs_++;
        }
        i::OS::Sleep(1);

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to