Upgrade V8 to 2.2.0.3
authorRyan Dahl <ry@tinyclouds.org>
Mon, 5 Apr 2010 01:07:32 +0000 (18:07 -0700)
committerRyan Dahl <ry@tinyclouds.org>
Mon, 5 Apr 2010 01:07:32 +0000 (18:07 -0700)
25 files changed:
deps/v8/ChangeLog
deps/v8/include/v8.h
deps/v8/src/SConscript
deps/v8/src/api.cc
deps/v8/src/builtins.cc
deps/v8/src/date.js
deps/v8/src/frame-element.h
deps/v8/src/heap.cc
deps/v8/src/objects-inl.h
deps/v8/src/objects.cc
deps/v8/src/objects.h
deps/v8/src/regexp.js
deps/v8/src/register-allocator.h
deps/v8/src/runtime.cc
deps/v8/src/runtime.h
deps/v8/src/string.js
deps/v8/src/type-info.cc [moved from deps/v8/src/type-info-inl.h with 95% similarity]
deps/v8/src/type-info.h
deps/v8/src/v8-counters.h
deps/v8/src/version.cc
deps/v8/test/cctest/test-strings.cc
deps/v8/tools/gyp/v8.gyp
deps/v8/tools/visual_studio/v8_base.vcproj
deps/v8/tools/visual_studio/v8_base_arm.vcproj
deps/v8/tools/visual_studio/v8_base_x64.vcproj

index 0de3308..a15cce8 100644 (file)
@@ -1,3 +1,10 @@
+2010-03-29: Version 2.2.0
+
+        Fixed a few minor bugs.
+
+        Performance improvements for string operations.
+
+
 2010-03-26: Version 2.1.10
 
         Fixed scons build issues.
index f64b386..90c4383 100644 (file)
@@ -855,12 +855,15 @@ class V8EXPORT String : public Primitive {
    * \param start The starting position within the string at which
    * copying begins.
    * \param length The number of bytes to copy from the string.
-   * \return The number of characters copied to the buffer
+   * \param nchars The number of characters written.
+   * \return The number of bytes copied to the buffer
    * excluding the NULL terminator.
    */
   int Write(uint16_t* buffer, int start = 0, int length = -1) const;  // UTF-16
   int WriteAscii(char* buffer, int start = 0, int length = -1) const;  // ASCII
-  int WriteUtf8(char* buffer, int length = -1) const; // UTF-8
+  int WriteUtf8(char* buffer,
+                int length = -1,
+                int* nchars = NULL) const; // UTF-8
 
   /**
    * A zero length string.
index a1d4796..1f1c1c1 100755 (executable)
@@ -102,6 +102,7 @@ SOURCES = {
     stub-cache.cc
     token.cc
     top.cc
+    type-info.cc
     unicode.cc
     utils.cc
     v8-counters.cc
index 2100480..3ba22d6 100644 (file)
@@ -2639,7 +2639,7 @@ int String::Utf8Length() const {
 }
 
 
-int String::WriteUtf8(char* buffer, int capacity) const {
+int String::WriteUtf8(char* buffer, int capacity, int *ncharsRef) const {
   if (IsDeadCheck("v8::String::WriteUtf8()")) return 0;
   LOG_API("String::WriteUtf8");
   ENTER_V8;
@@ -2653,10 +2653,12 @@ int String::WriteUtf8(char* buffer, int capacity) const {
   int fast_end = capacity - (unibrow::Utf8::kMaxEncodedSize - 1);
   int i;
   int pos = 0;
+  int nchars = 0;
   for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) {
     i::uc32 c = write_input_buffer.GetNext();
     int written = unibrow::Utf8::Encode(buffer + pos, c);
     pos += written;
+    nchars++;
   }
   if (i < len) {
     // For the last characters we need to check the length for each one
@@ -2670,12 +2672,14 @@ int String::WriteUtf8(char* buffer, int capacity) const {
         for (int j = 0; j < written; j++)
           buffer[pos + j] = intermediate[j];
         pos += written;
+        nchars++;
       } else {
         // We've reached the end of the buffer
         break;
       }
     }
   }
+  if (ncharsRef) *ncharsRef = nchars;
   if (i == len && (capacity == -1 || pos < capacity))
     buffer[pos++] = '\0';
   return pos;
index 122fbba..feb912f 100644 (file)
@@ -495,7 +495,9 @@ BUILTIN(ArrayShift) {
   }
 
   if (Heap::new_space()->Contains(elms)) {
-    array->set_elements(LeftTrimFixedArray(elms));
+    // As elms still in the same space they used to be (new space),
+    // there is no need to update remembered set.
+    array->set_elements(LeftTrimFixedArray(elms), SKIP_WRITE_BARRIER);
   } else {
     // Shift the elements.
     AssertNoAllocation no_gc;
index c7c3940..46769c6 100644 (file)
@@ -121,9 +121,16 @@ function EquivalentTime(t) {
 }
 
 
-// Because computing the DST offset is a pretty expensive operation
-// we keep a cache of last computed offset along with a time interval
+// local_time_offset is initialized when the DST_offset_cache is missed.
+// It must not be used until after a call to DaylightSavingsOffset().
+// In this way, only one check, for a DST cache miss, is needed.
+var local_time_offset;
+
+
+// Because computing the DST offset is an expensive operation,
+// we keep a cache of the last computed DST offset along with a time interval
 // where we know the cache is valid.
+// When the cache is valid, local_time_offset is also valid.
 var DST_offset_cache = {
   // Cached DST offset.
   offset: 0,
@@ -149,6 +156,11 @@ function DaylightSavingsOffset(t) {
     // If the time fits in the cached interval, return the cached offset.
     if (t <= end) return cache.offset;
 
+    // If the cache misses, the local_time_offset may not be initialized.
+    if (IS_UNDEFINED(local_time_offset)) {
+      local_time_offset = %DateLocalTimeOffset();
+    }
+
     // Compute a possible new interval end.
     var new_end = end + cache.increment;
 
@@ -185,6 +197,10 @@ function DaylightSavingsOffset(t) {
     }
   }
 
+  // If the cache misses, the local_time_offset may not be initialized.
+  if (IS_UNDEFINED(local_time_offset)) {
+    local_time_offset = %DateLocalTimeOffset();
+  }
   // Compute the DST offset for the time and shrink the cache interval
   // to only contain the time. This allows fast repeated DST offset
   // computations for the same time.
@@ -215,11 +231,11 @@ function WeekDay(time) {
   return Modulo(DAY(time) + 4, 7);
 }
 
-var local_time_offset = %DateLocalTimeOffset();
 
 function LocalTime(time) {
   if (NUMBER_IS_NAN(time)) return time;
-  return time + local_time_offset + DaylightSavingsOffset(time);
+  // DaylightSavingsOffset called before local_time_offset used.
+  return time + DaylightSavingsOffset(time) + local_time_offset;
 }
 
 function LocalTimeNoCheck(time) {
@@ -228,6 +244,8 @@ function LocalTimeNoCheck(time) {
   }
 
   // Inline the DST offset cache checks for speed.
+  // The cache is hit, or DaylightSavingsOffset is called,
+  // before local_time_offset is used.
   var cache = DST_offset_cache;
   if (cache.start <= time && time <= cache.end) {
     var dst_offset = cache.offset;
@@ -240,6 +258,11 @@ function LocalTimeNoCheck(time) {
 
 function UTC(time) {
   if (NUMBER_IS_NAN(time)) return time;
+  // local_time_offset is needed before the call to DaylightSavingsOffset,
+  // so it may be uninitialized.
+  if (IS_UNDEFINED(local_time_offset)) {
+    local_time_offset = %DateLocalTimeOffset();
+  }
   var tmp = time - local_time_offset;
   return tmp - DaylightSavingsOffset(tmp);
 }
@@ -566,7 +589,7 @@ function TimeString(time) {
 
 function LocalTimezoneString(time) {
   var timezoneOffset =
-      (local_time_offset + DaylightSavingsOffset(time)) / msPerMinute;
+      (DaylightSavingsOffset(time) + local_time_offset) / msPerMinute;
   var sign = (timezoneOffset >= 0) ? 1 : -1;
   var hours = FLOOR((sign * timezoneOffset)/60);
   var min   = FLOOR((sign * timezoneOffset)%60);
index 83db5c3..48bb354 100644 (file)
@@ -28,7 +28,7 @@
 #ifndef V8_FRAME_ELEMENT_H_
 #define V8_FRAME_ELEMENT_H_
 
-#include "type-info-inl.h"
+#include "type-info.h"
 #include "macro-assembler.h"
 #include "zone.h"
 
index 1f1599a..5421dcc 100644 (file)
@@ -1961,8 +1961,9 @@ Object* Heap::AllocateConsString(String* first, String* second) {
     return MakeOrFindTwoCharacterString(c1, c2);
   }
 
-  bool is_ascii = first->IsAsciiRepresentation()
-      && second->IsAsciiRepresentation();
+  bool first_is_ascii = first->IsAsciiRepresentation();
+  bool second_is_ascii = second->IsAsciiRepresentation();
+  bool is_ascii = first_is_ascii && second_is_ascii;
 
   // Make sure that an out of memory exception is thrown if the length
   // of the new cons string is too large.
@@ -1997,6 +1998,25 @@ Object* Heap::AllocateConsString(String* first, String* second) {
       for (int i = 0; i < second_length; i++) *dest++ = src[i];
       return result;
     } else {
+      // For short external two-byte strings we check whether they can
+      // be represented using ascii.
+      if (!first_is_ascii) {
+        first_is_ascii = first->IsExternalTwoByteStringWithAsciiChars();
+      }
+      if (first_is_ascii && !second_is_ascii) {
+        second_is_ascii = second->IsExternalTwoByteStringWithAsciiChars();
+      }
+      if (first_is_ascii && second_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, dest, 0, first_length);
+        String::WriteToFlat(second, dest + first_length, 0, second_length);
+        Counters::string_add_runtime_ext_to_ascii.Increment();
+        return result;
+      }
+
       Object* result = AllocateRawTwoByteString(length);
       if (result->IsFailure()) return result;
       // Copy the characters into the new object.
index a26da7d..d363d4d 100644 (file)
@@ -255,6 +255,16 @@ bool String::IsTwoByteRepresentation() {
 }
 
 
+bool String::IsExternalTwoByteStringWithAsciiChars() {
+  if (!IsExternalTwoByteString()) return false;
+  const uc16* data = ExternalTwoByteString::cast(this)->resource()->data();
+  for (int i = 0, len = length(); i < len; i++) {
+    if (data[i] > kMaxAsciiCharCode) return false;
+  }
+  return true;
+}
+
+
 bool StringShape::IsCons() {
   return (type_ & kStringRepresentationMask) == kConsStringTag;
 }
@@ -732,7 +742,8 @@ Object* Object::GetProperty(String* key, PropertyAttributes* attributes) {
   } else { \
     ASSERT(mode == SKIP_WRITE_BARRIER); \
     ASSERT(Heap::InNewSpace(object) || \
-           !Heap::InNewSpace(READ_FIELD(object, offset))); \
+           !Heap::InNewSpace(READ_FIELD(object, offset)) || \
+           Page::IsRSetSet(object->address(), offset)); \
   }
 
 #define READ_DOUBLE_FIELD(p, offset) \
index a1fbc99..02ea5b0 100644 (file)
@@ -4660,13 +4660,38 @@ bool String::IsEqualTo(Vector<const char> str) {
 }
 
 
+template <typename schar>
+static inline uint32_t HashSequentialString(const schar* chars, int length) {
+  StringHasher hasher(length);
+  if (!hasher.has_trivial_hash()) {
+    int i;
+    for (i = 0; hasher.is_array_index() && (i < length); i++) {
+      hasher.AddCharacter(chars[i]);
+    }
+    for (; i < length; i++) {
+      hasher.AddCharacterNoIndex(chars[i]);
+    }
+  }
+  return hasher.GetHashField();
+}
+
+
 uint32_t String::ComputeAndSetHash() {
   // Should only be called if hash code has not yet been computed.
   ASSERT(!(hash_field() & kHashComputedMask));
 
+  const int len = length();
+
   // Compute the hash code.
-  StringInputBuffer buffer(this);
-  uint32_t field = ComputeHashField(&buffer, length());
+  uint32_t field = 0;
+  if (StringShape(this).IsSequentialAscii()) {
+    field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
+  } else if (StringShape(this).IsSequentialTwoByte()) {
+    field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
+  } else {
+    StringInputBuffer buffer(this);
+    field = ComputeHashField(&buffer, len);
+  }
 
   // Store the hash code in the object.
   set_hash_field(field);
index 01977f0..5a0db01 100644 (file)
@@ -3919,6 +3919,13 @@ class String: public HeapObject {
   inline bool IsAsciiRepresentation();
   inline bool IsTwoByteRepresentation();
 
+  // Check whether this string is an external two-byte string that in
+  // fact contains only ascii characters.
+  //
+  // Such strings may appear when the embedder prefers two-byte
+  // representations even for ascii data.
+  inline bool IsExternalTwoByteStringWithAsciiChars();
+
   // Get and set individual two byte chars in the string.
   inline void Set(int index, uint16_t value);
   // Get individual two byte char in the string.  Repeated calls
index dc1b042..e2492f7 100644 (file)
@@ -344,7 +344,6 @@ function RegExpToString() {
 // on the captures array of the last successful match and the subject string
 // of the last successful match.
 function RegExpGetLastMatch() {
-  if (lastMatchInfoOverride) { return lastMatchInfoOverride[0]; }
   var regExpSubject = LAST_SUBJECT(lastMatchInfo);
   return SubString(regExpSubject,
                    lastMatchInfo[CAPTURE0],
@@ -353,11 +352,6 @@ function RegExpGetLastMatch() {
 
 
 function RegExpGetLastParen() {
-  if (lastMatchInfoOverride) {
-    var override = lastMatchInfoOverride;
-    if (override.length <= 3) return ''; 
-    return override[override.length - 3];
-  }
   var length = NUMBER_OF_CAPTURES(lastMatchInfo);
   if (length <= 2) return '';  // There were no captures.
   // We match the SpiderMonkey behavior: return the substring defined by the
@@ -374,32 +368,17 @@ function RegExpGetLastParen() {
 
 
 function RegExpGetLeftContext() {
-  var start_index;
-  var subject;
-  if (!lastMatchInfoOverride) {
-    start_index = lastMatchInfo[CAPTURE0];
-    subject = LAST_SUBJECT(lastMatchInfo);
-  } else {
-    var override = lastMatchInfoOverride;
-    start_index = override[override.length - 2];
-    subject = override[override.length - 1];
-  }
-  return SubString(subject, 0, start_index);
+  return SubString(LAST_SUBJECT(lastMatchInfo),
+                   0,
+                   lastMatchInfo[CAPTURE0]);
 }
 
 
 function RegExpGetRightContext() {
-  var start_index;
-  var subject;
-  if (!lastMatchInfoOverride) {
-    start_index = lastMatchInfo[CAPTURE1];
-    subject = LAST_SUBJECT(lastMatchInfo);
-  } else {
-    var override = lastMatchInfoOverride;
-    subject = override[override.length - 1];
-    start_index = override[override.length - 2] + subject.length;
-  }
-  return SubString(subject, start_index, subject.length);
+  var subject = LAST_SUBJECT(lastMatchInfo);
+  return SubString(subject,
+                   lastMatchInfo[CAPTURE1],
+                   subject.length);
 }
 
 
@@ -408,10 +387,6 @@ function RegExpGetRightContext() {
 // called with indices from 1 to 9.
 function RegExpMakeCaptureGetter(n) {
   return function() {
-    if (lastMatchInfoOverride) {
-      if (n < lastMatchInfoOverride.length - 2) return lastMatchInfoOverride[n];
-      return '';
-    }
     var index = n * 2;
     if (index >= NUMBER_OF_CAPTURES(lastMatchInfo)) return '';
     var matchStart = lastMatchInfo[CAPTURE(index)];
@@ -436,12 +411,6 @@ var lastMatchInfo = [
     0,                 // REGEXP_FIRST_CAPTURE + 1
 ];
 
-// Override last match info with an array of actual substrings.
-// Used internally by replace regexp with function.
-// The array has the format of an "apply" argument for a replacement 
-// function. 
-var lastMatchInfoOverride = null;
-
 // -------------------------------------------------------------------
 
 function SetupRegExp() {
index 0fbc83b..4564533 100644 (file)
@@ -29,7 +29,7 @@
 #define V8_REGISTER_ALLOCATOR_H_
 
 #include "macro-assembler.h"
-#include "type-info-inl.h"
+#include "type-info.h"
 
 #if V8_TARGET_ARCH_IA32
 #include "ia32/register-allocator-ia32.h"
index c77d518..b349815 100644 (file)
@@ -1567,91 +1567,9 @@ static Object* Runtime_CharFromCode(Arguments args) {
   return CharFromCode(args[0]);
 }
 
-
-class FixedArrayBuilder {
- public:
-  explicit FixedArrayBuilder(int initial_capacity)
-      : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
-        length_(0) {
-    // Require a non-zero initial size. Ensures that doubling the size to
-    // extend the array will work.
-    ASSERT(initial_capacity > 0);
-  }
-
-  explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
-      : array_(backing_store),
-        length_(0) {
-    // Require a non-zero initial size. Ensures that doubling the size to
-    // extend the array will work.
-    ASSERT(backing_store->length() > 0);
-  }
-
-  bool HasCapacity(int elements) {
-    int length = array_->length();
-    int required_length = length_ + elements;
-    return (length >= required_length);
-  }
-
-  void EnsureCapacity(int elements) {
-    int length = array_->length();
-    int required_length = length_ + elements;
-    if (length < required_length) {
-      int new_length = length;
-      do {
-        new_length *= 2;
-      } while (new_length < required_length);
-      Handle<FixedArray> extended_array =
-          Factory::NewFixedArrayWithHoles(new_length);
-      array_->CopyTo(0, *extended_array, 0, length_);
-      array_ = extended_array;
-    }
-  }
-
-  void Add(Object* value) {
-    ASSERT(length_ < capacity());
-    array_->set(length_, value);
-    length_++;
-  }
-
-  void Add(Smi* value) {
-    ASSERT(length_ < capacity());
-    array_->set(length_, value);
-    length_++;
-  }
-
-  Handle<FixedArray> array() {
-    return array_;
-  }
-
-  int length() {
-    return length_;
-  }
-
-  int capacity() {
-    return array_->length();
-  }
-
-  Handle<JSArray> ToJSArray() {
-    Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
-    result_array->set_length(Smi::FromInt(length_));
-    return result_array;
-  }
-
-  Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
-    target_array->set_elements(*array_);
-    target_array->set_length(Smi::FromInt(length_));
-    return target_array;
-  }
-
- private:
-  Handle<FixedArray> array_;
-  int length_;
-};
-
-
 // Forward declarations.
-const int kStringBuilderConcatHelperLengthBits = 11;
-const int kStringBuilderConcatHelperPositionBits = 19;
+static const int kStringBuilderConcatHelperLengthBits = 11;
+static const int kStringBuilderConcatHelperPositionBits = 19;
 
 template <typename schar>
 static inline void StringBuilderConcatHelper(String*,
@@ -1659,19 +1577,15 @@ static inline void StringBuilderConcatHelper(String*,
                                              FixedArray*,
                                              int);
 
-typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
-    StringBuilderSubstringLength;
-typedef BitField<int,
-                 kStringBuilderConcatHelperLengthBits,
-                 kStringBuilderConcatHelperPositionBits>
-    StringBuilderSubstringPosition;
-
+typedef BitField<int, 0, 11> StringBuilderSubstringLength;
+typedef BitField<int, 11, 19> StringBuilderSubstringPosition;
 
 class ReplacementStringBuilder {
  public:
   ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
-      : array_builder_(estimated_part_count),
-        subject_(subject),
+      : subject_(subject),
+        parts_(Factory::NewFixedArray(estimated_part_count)),
+        part_count_(0),
         character_count_(0),
         is_ascii_(subject->IsAsciiRepresentation()) {
     // Require a non-zero initial size. Ensures that doubling the size to
@@ -1679,35 +1593,38 @@ class ReplacementStringBuilder {
     ASSERT(estimated_part_count > 0);
   }
 
-  static inline void AddSubjectSlice(FixedArrayBuilder* builder,
-                                     int from,
-                                     int to) {
+  void EnsureCapacity(int elements) {
+    int length = parts_->length();
+    int required_length = part_count_ + elements;
+    if (length < required_length) {
+      int new_length = length;
+      do {
+        new_length *= 2;
+      } while (new_length < required_length);
+      Handle<FixedArray> extended_array =
+          Factory::NewFixedArray(new_length);
+      parts_->CopyTo(0, *extended_array, 0, part_count_);
+      parts_ = extended_array;
+    }
+  }
+
+  void AddSubjectSlice(int from, int to) {
     ASSERT(from >= 0);
     int length = to - from;
     ASSERT(length > 0);
+    // Can we encode the slice in 11 bits for length and 19 bits for
+    // start position - as used by StringBuilderConcatHelper?
     if (StringBuilderSubstringLength::is_valid(length) &&
         StringBuilderSubstringPosition::is_valid(from)) {
       int encoded_slice = StringBuilderSubstringLength::encode(length) |
           StringBuilderSubstringPosition::encode(from);
-      builder->Add(Smi::FromInt(encoded_slice));
+      AddElement(Smi::FromInt(encoded_slice));
     } else {
       // Otherwise encode as two smis.
-      builder->Add(Smi::FromInt(-length));
-      builder->Add(Smi::FromInt(from));
+      AddElement(Smi::FromInt(-length));
+      AddElement(Smi::FromInt(from));
     }
-  }
-
-
-  void EnsureCapacity(int elements) {
-    array_builder_.EnsureCapacity(elements);
-  }
-
-
-  void AddSubjectSlice(int from, int to) {
-    AddSubjectSlice(&array_builder_, from, to);
-    // Can we encode the slice in 11 bits for length and 19 bits for
-    // start position - as used by StringBuilderConcatHelper?
-    IncrementCharacterCount(to - from);
+    IncrementCharacterCount(length);
   }
 
 
@@ -1723,7 +1640,7 @@ class ReplacementStringBuilder {
 
 
   Handle<String> ToString() {
-    if (array_builder_.length() == 0) {
+    if (part_count_ == 0) {
       return Factory::empty_string();
     }
 
@@ -1735,8 +1652,8 @@ class ReplacementStringBuilder {
       char* char_buffer = seq->GetChars();
       StringBuilderConcatHelper(*subject_,
                                 char_buffer,
-                                *array_builder_.array(),
-                                array_builder_.length());
+                                *parts_,
+                                part_count_);
     } else {
       // Non-ASCII.
       joined_string = NewRawTwoByteString(character_count_);
@@ -1745,8 +1662,8 @@ class ReplacementStringBuilder {
       uc16* char_buffer = seq->GetChars();
       StringBuilderConcatHelper(*subject_,
                                 char_buffer,
-                                *array_builder_.array(),
-                                array_builder_.length());
+                                *parts_,
+                                part_count_);
     }
     return joined_string;
   }
@@ -1759,14 +1676,8 @@ class ReplacementStringBuilder {
     character_count_ += by;
   }
 
-  Handle<JSArray> GetParts() {
-    Handle<JSArray> result =
-        Factory::NewJSArrayWithElements(array_builder_.array());
-    result->set_length(Smi::FromInt(array_builder_.length()));
-    return result;
-  }
-
  private:
+
   Handle<String> NewRawAsciiString(int size) {
     CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
   }
@@ -1779,12 +1690,14 @@ class ReplacementStringBuilder {
 
   void AddElement(Object* element) {
     ASSERT(element->IsSmi() || element->IsString());
-    ASSERT(array_builder_.capacity() > array_builder_.length());
-    array_builder_.Add(element);
+    ASSERT(parts_->length() > part_count_);
+    parts_->set(part_count_, element);
+    part_count_++;
   }
 
-  FixedArrayBuilder array_builder_;
   Handle<String> subject_;
+  Handle<FixedArray> parts_;
+  int part_count_;
   int character_count_;
   bool is_ascii_;
 };
@@ -2192,6 +2105,7 @@ static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
 }
 
 
+
 // Cap on the maximal shift in the Boyer-Moore implementation. By setting a
 // limit, we can fix the size of tables.
 static const int kBMMaxShift = 0xff;
@@ -2955,468 +2869,6 @@ static Object* Runtime_StringMatch(Arguments args) {
 }
 
 
-// Two smis before and after the match, for very long strings.
-const int kMaxBuilderEntriesPerRegExpMatch = 5;
-
-
-static void SetLastMatchInfoNoCaptures(Handle<String> subject,
-                                       Handle<JSArray> last_match_info,
-                                       int match_start,
-                                       int match_end) {
-  // Fill last_match_info with a single capture.
-  last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
-  AssertNoAllocation no_gc;
-  FixedArray* elements = FixedArray::cast(last_match_info->elements());
-  RegExpImpl::SetLastCaptureCount(elements, 2);
-  RegExpImpl::SetLastInput(elements, *subject);
-  RegExpImpl::SetLastSubject(elements, *subject);
-  RegExpImpl::SetCapture(elements, 0, match_start);
-  RegExpImpl::SetCapture(elements, 1, match_end);
-}
-
-
-template <typename schar>
-static bool SearchCharMultiple(Vector<schar> subject,
-                               String* pattern,
-                               schar pattern_char,
-                               FixedArrayBuilder* builder,
-                               int* match_pos) {
-  // Position of last match.
-  int pos = *match_pos;
-  int subject_length = subject.length();
-  while (pos < subject_length) {
-    int match_end = pos + 1;
-    if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
-      *match_pos = pos;
-      return false;
-    }
-    int new_pos = SingleCharIndexOf(subject, pattern_char, match_end);
-    if (new_pos >= 0) {
-      // Match has been found.
-      if (new_pos > match_end) {
-        ReplacementStringBuilder::AddSubjectSlice(builder, match_end, new_pos);
-      }
-      pos = new_pos;
-      builder->Add(pattern);
-    } else {
-      break;
-    }
-  }
-  if (pos + 1 < subject_length) {
-    ReplacementStringBuilder::AddSubjectSlice(builder, pos + 1, subject_length);
-  }
-  *match_pos = pos;
-  return true;
-}
-
-
-static bool SearchCharMultiple(Handle<String> subject,
-                               Handle<String> pattern,
-                               Handle<JSArray> last_match_info,
-                               FixedArrayBuilder* builder) {
-  ASSERT(subject->IsFlat());
-  ASSERT_EQ(1, pattern->length());
-  uc16 pattern_char = pattern->Get(0);
-  // Treating position before first as initial "previous match position".
-  int match_pos = -1;
-
-  for (;;) {  // Break when search complete.
-    builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
-    AssertNoAllocation no_gc;
-    if (subject->IsAsciiRepresentation()) {
-      if (pattern_char > String::kMaxAsciiCharCode) {
-        break;
-      }
-      Vector<const char> subject_vector = subject->ToAsciiVector();
-      char pattern_ascii_char = static_cast<char>(pattern_char);
-      bool complete = SearchCharMultiple<const char>(subject_vector,
-                                                     *pattern,
-                                                     pattern_ascii_char,
-                                                     builder,
-                                                     &match_pos);
-      if (complete) break;
-    } else {
-      Vector<const uc16> subject_vector = subject->ToUC16Vector();
-      bool complete = SearchCharMultiple<const uc16>(subject_vector,
-                                                     *pattern,
-                                                     pattern_char,
-                                                     builder,
-                                                     &match_pos);
-      if (complete) break;
-    }
-  }
-
-  if (match_pos >= 0) {
-    SetLastMatchInfoNoCaptures(subject,
-                               last_match_info,
-                               match_pos,
-                               match_pos + 1);
-    return true;
-  }
-  return false;  // No matches at all.
-}
-
-
-template <typename schar, typename pchar>
-static bool SearchStringMultiple(Vector<schar> subject,
-                                 String* pattern,
-                                 Vector<pchar> pattern_string,
-                                 FixedArrayBuilder* builder,
-                                 int* match_pos) {
-  int pos = *match_pos;
-  int subject_length = subject.length();
-  int pattern_length = pattern_string.length();
-  int max_search_start = subject_length - pattern_length;
-  bool is_ascii = (sizeof(schar) == 1);
-  StringSearchStrategy strategy =
-      InitializeStringSearch(pattern_string, is_ascii);
-  switch (strategy) {
-    case SEARCH_FAIL: return false;
-    case SEARCH_SHORT:
-      while (pos <= max_search_start) {
-        if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
-          *match_pos = pos;
-          return false;
-        }
-        // Position of end of previous match.
-        int match_end = pos + pattern_length;
-        int new_pos = SimpleIndexOf(subject, pattern_string, match_end);
-        if (new_pos >= 0) {
-          // A match.
-          if (new_pos > match_end) {
-            ReplacementStringBuilder::AddSubjectSlice(builder,
-                                                      match_end,
-                                                      new_pos);
-          }
-          pos = new_pos;
-          builder->Add(pattern);
-        } else {
-          break;
-        }
-      }
-      break;
-    case SEARCH_LONG:
-      while (pos  <= max_search_start) {
-        if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
-         *match_pos = pos;
-         return false;
-        }
-        int new_pos = ComplexIndexOf(subject,
-                                     pattern_string,
-                                     pos + pattern_length);
-        if (new_pos >= 0) {
-         // A match has been found.
-          if (new_pos > pos) {
-           ReplacementStringBuilder::AddSubjectSlice(builder, pos, new_pos);
-          }
-          pos = new_pos;
-          builder->Add(pattern);
-        } else {
-         break;
-        }
-      }
-      break;
-  }
-  if (pos < max_search_start) {
-    ReplacementStringBuilder::AddSubjectSlice(builder,
-                                              pos + pattern_length,
-                                              subject_length);
-  }
-  *match_pos = pos;
-  return true;
-}
-
-
-static bool SearchStringMultiple(Handle<String> subject,
-                                 Handle<String> pattern,
-                                 Handle<JSArray> last_match_info,
-                                 FixedArrayBuilder* builder) {
-  ASSERT(subject->IsFlat());
-  ASSERT(pattern->IsFlat());
-  ASSERT(pattern->length() > 1);
-
-  // Treating as if a previous match was before first character.
-  int match_pos = -pattern->length();
-
-  for (;;) {  // Break when search complete.
-    builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
-    AssertNoAllocation no_gc;
-    if (subject->IsAsciiRepresentation()) {
-      Vector<const char> subject_vector = subject->ToAsciiVector();
-      if (pattern->IsAsciiRepresentation()) {
-        if (SearchStringMultiple(subject_vector,
-                                 *pattern,
-                                 pattern->ToAsciiVector(),
-                                 builder,
-                                 &match_pos)) break;
-      } else {
-        if (SearchStringMultiple(subject_vector,
-                                 *pattern,
-                                 pattern->ToUC16Vector(),
-                                 builder,
-                                 &match_pos)) break;
-      }
-    } else {
-      Vector<const uc16> subject_vector = subject->ToUC16Vector();
-      if (pattern->IsAsciiRepresentation()) {
-        if (SearchStringMultiple(subject_vector,
-                                 *pattern,
-                                 pattern->ToAsciiVector(),
-                                 builder,
-                                 &match_pos)) break;
-      } else {
-        if (SearchStringMultiple(subject_vector,
-                                 *pattern,
-                                 pattern->ToUC16Vector(),
-                                 builder,
-                                 &match_pos)) break;
-      }
-    }
-  }
-
-  if (match_pos >= 0) {
-    SetLastMatchInfoNoCaptures(subject,
-                               last_match_info,
-                               match_pos,
-                               match_pos + pattern->length());
-    return true;
-  }
-  return false;  // No matches at all.
-}
-
-
-static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
-    Handle<String> subject,
-    Handle<JSRegExp> regexp,
-    Handle<JSArray> last_match_array,
-    FixedArrayBuilder* builder) {
-  ASSERT(subject->IsFlat());
-  int match_start = -1;
-  int match_end = 0;
-  int pos = 0;
-  int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
-  if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
-
-  OffsetsVector registers(required_registers);
-  Vector<int> register_vector(registers.vector(), registers.length());
-  int subject_length = subject->length();
-
-  for (;;) {  // Break on failure, return on exception.
-    RegExpImpl::IrregexpResult result =
-        RegExpImpl::IrregexpExecOnce(regexp,
-                                     subject,
-                                     pos,
-                                     register_vector);
-    if (result == RegExpImpl::RE_SUCCESS) {
-      match_start = register_vector[0];
-      builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
-      if (match_end < match_start) {
-        ReplacementStringBuilder::AddSubjectSlice(builder,
-                                                  match_end,
-                                                  match_start);
-      }
-      match_end = register_vector[1];
-      HandleScope loop_scope;
-      builder->Add(*Factory::NewSubString(subject, match_start, match_end));
-      if (match_start != match_end) {
-        pos = match_end;
-      } else {
-        pos = match_end + 1;
-        if (pos > subject_length) break;
-      }
-    } else if (result == RegExpImpl::RE_FAILURE) {
-      break;
-    } else {
-      ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
-      return result;
-    }
-  }
-
-  if (match_start >= 0) {
-    if (match_end < subject_length) {
-      ReplacementStringBuilder::AddSubjectSlice(builder,
-                                                match_end,
-                                                subject_length);
-    }
-    SetLastMatchInfoNoCaptures(subject,
-                               last_match_array,
-                               match_start,
-                               match_end);
-    return RegExpImpl::RE_SUCCESS;
-  } else {
-    return RegExpImpl::RE_FAILURE;  // No matches at all.
-  }
-}
-
-
-static RegExpImpl::IrregexpResult SearchRegExpMultiple(
-    Handle<String> subject,
-    Handle<JSRegExp> regexp,
-    Handle<JSArray> last_match_array,
-    FixedArrayBuilder* builder) {
-
-  ASSERT(subject->IsFlat());
-  int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
-  if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
-
-  OffsetsVector registers(required_registers);
-  Vector<int> register_vector(registers.vector(), registers.length());
-
-  RegExpImpl::IrregexpResult result =
-      RegExpImpl::IrregexpExecOnce(regexp,
-                                   subject,
-                                   0,
-                                   register_vector);
-
-  int capture_count = regexp->CaptureCount();
-  int subject_length = subject->length();
-
-  // Position to search from.
-  int pos = 0;
-  // End of previous match. Differs from pos if match was empty.
-  int match_end = 0;
-  if (result == RegExpImpl::RE_SUCCESS) {
-    // Need to keep a copy of the previous match for creating last_match_info
-    // at the end, so we have two vectors that we swap between.
-    OffsetsVector registers2(required_registers);
-    Vector<int> prev_register_vector(registers2.vector(), registers2.length());
-
-    do {
-      int match_start = register_vector[0];
-      builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
-      if (match_end < match_start) {
-        ReplacementStringBuilder::AddSubjectSlice(builder,
-                                                  match_end,
-                                                  match_start);
-      }
-      match_end = register_vector[1];
-
-      {
-        // Avoid accumulating new handles inside loop.
-        HandleScope temp_scope;
-        // Arguments array to replace function is match, captures, index and
-        // subject, i.e., 3 + capture count in total.
-        Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
-        elements->set(0, *Factory::NewSubString(subject,
-                                                match_start,
-                                                match_end));
-        for (int i = 1; i <= capture_count; i++) {
-          Handle<String> substring =
-              Factory::NewSubString(subject,
-                                    register_vector[i * 2],
-                                    register_vector[i * 2 + 1]);
-          elements->set(i, *substring);
-        }
-        elements->set(capture_count + 1, Smi::FromInt(match_start));
-        elements->set(capture_count + 2, *subject);
-        builder->Add(*Factory::NewJSArrayWithElements(elements));
-      }
-      // Swap register vectors, so the last successful match is in
-      // prev_register_vector.
-      Vector<int> tmp = prev_register_vector;
-      prev_register_vector = register_vector;
-      register_vector = tmp;
-
-      if (match_end > match_start) {
-        pos = match_end;
-      } else {
-        pos = match_end + 1;
-        if (pos > subject_length) {
-          break;
-        }
-      }
-
-      result = RegExpImpl::IrregexpExecOnce(regexp,
-                                            subject,
-                                            pos,
-                                            register_vector);
-    } while (result == RegExpImpl::RE_SUCCESS);
-
-    if (result != RegExpImpl::RE_EXCEPTION) {
-      // Finished matching, with at least one match.
-      if (match_end < subject_length) {
-        ReplacementStringBuilder::AddSubjectSlice(builder,
-                                                  match_end,
-                                                  subject_length);
-      }
-
-      int last_match_capture_count = (capture_count + 1) * 2;
-      int last_match_array_size =
-          last_match_capture_count + RegExpImpl::kLastMatchOverhead;
-      last_match_array->EnsureSize(last_match_array_size);
-      AssertNoAllocation no_gc;
-      FixedArray* elements = FixedArray::cast(last_match_array->elements());
-      RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
-      RegExpImpl::SetLastSubject(elements, *subject);
-      RegExpImpl::SetLastInput(elements, *subject);
-      for (int i = 0; i < last_match_capture_count; i++) {
-        RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
-      }
-      return RegExpImpl::RE_SUCCESS;
-    }
-  }
-  // No matches at all, return failure or exception result directly.
-  return result;
-}
-
-
-static Object* Runtime_RegExpExecMultiple(Arguments args) {
-  ASSERT(args.length() == 4);
-  HandleScope handles;
-
-  CONVERT_ARG_CHECKED(String, subject, 1);
-  if (!subject->IsFlat()) { FlattenString(subject); }
-  CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
-  CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
-  CONVERT_ARG_CHECKED(JSArray, result_array, 3);
-
-  ASSERT(last_match_info->HasFastElements());
-  ASSERT(regexp->GetFlags().is_global());
-  Handle<FixedArray> result_elements;
-  if (result_array->HasFastElements()) {
-    result_elements =
-        Handle<FixedArray>(FixedArray::cast(result_array->elements()));
-  } else {
-    result_elements = Factory::NewFixedArrayWithHoles(16);
-  }
-  FixedArrayBuilder builder(result_elements);
-
-  if (regexp->TypeTag() == JSRegExp::ATOM) {
-    Handle<String> pattern(
-        String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
-    int pattern_length = pattern->length();
-    if (pattern_length == 1) {
-      if (SearchCharMultiple(subject, pattern, last_match_info, &builder)) {
-        return *builder.ToJSArray(result_array);
-      }
-      return Heap::null_value();
-    }
-
-    if (!pattern->IsFlat()) FlattenString(pattern);
-    if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
-      return *builder.ToJSArray(result_array);
-    }
-    return Heap::null_value();
-  }
-
-  ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
-
-  RegExpImpl::IrregexpResult result;
-  if (regexp->CaptureCount() == 0) {
-    result = SearchRegExpNoCaptureMultiple(subject,
-                                           regexp,
-                                           last_match_info,
-                                           &builder);
-  } else {
-    result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
-  }
-  if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
-  if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
-  ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
-  return Failure::Exception();
-}
-
-
 static Object* Runtime_NumberToRadixString(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 2);
index 42af3df..4175902 100644 (file)
@@ -153,7 +153,6 @@ namespace internal {
   /* Regular expressions */ \
   F(RegExpCompile, 3, 1) \
   F(RegExpExec, 4, 1) \
-  F(RegExpExecMultiple, 4, 1) \
   \
   /* Strings */ \
   F(StringCharCodeAt, 2, 1) \
index f4489ef..ca438fd 100644 (file)
@@ -405,91 +405,97 @@ function addCaptureString(builder, matchInfo, index) {
   builder.addSpecialSlice(start, end);
 };
 
-// TODO(lrn): This array will survive indefinitely if replace is never
-// called again. However, it will be empty, since the contents are cleared 
-// in the finally block.
-var reusableReplaceArray = $Array(16);
 
 // Helper function for replacing regular expressions with the result of a
-// function application in String.prototype.replace.
+// function application in String.prototype.replace.  The function application
+// must be interleaved with the regexp matching (contrary to ECMA-262
+// 15.5.4.11) to mimic SpiderMonkey and KJS behavior when the function uses
+// the static properties of the RegExp constructor.  Example:
+//     'abcd'.replace(/(.)/g, function() { return RegExp.$1; }
+// should be 'abcd' and not 'dddd' (or anything else).
 function StringReplaceRegExpWithFunction(subject, regexp, replace) {
+  var matchInfo = DoRegExpExec(regexp, subject, 0);
+  if (IS_NULL(matchInfo)) return subject;
+
+  var result = new ReplaceResultBuilder(subject);
+  // There's at least one match.  If the regexp is global, we have to loop
+  // over all matches.  The loop is not in C++ code here like the one in
+  // RegExp.prototype.exec, because of the interleaved function application.
+  // Unfortunately, that means this code is nearly duplicated, here and in
+  // jsregexp.cc.
   if (regexp.global) {
-    var resultArray = reusableReplaceArray;
-    if (resultArray) {
-      reusableReplaceArray = null;
+    var previous = 0;
+    var startOfMatch;
+    if (NUMBER_OF_CAPTURES(matchInfo) == 2) {
+      // Both branches contain essentially the same loop except for the call
+      // to the replace function. The branch is put outside of the loop for
+      // speed
+      do {
+        startOfMatch = matchInfo[CAPTURE0];
+        result.addSpecialSlice(previous, startOfMatch);
+        previous = matchInfo[CAPTURE1];
+        var match = SubString(subject, startOfMatch, previous);
+        // Don't call directly to avoid exposing the built-in global object.
+        result.add(replace.call(null, match, startOfMatch, subject));
+        // Can't use matchInfo any more from here, since the function could
+        // overwrite it.
+        // Continue with the next match.
+        // Increment previous if we matched an empty string, as per ECMA-262
+        // 15.5.4.10.
+        if (previous == startOfMatch) {
+          // Add the skipped character to the output, if any.
+          if (previous < subject.length) {
+            result.addSpecialSlice(previous, previous + 1);
+          }
+          previous++;
+          // Per ECMA-262 15.10.6.2, if the previous index is greater than the
+          // string length, there is no match
+          if (previous > subject.length) {
+            return result.generate();
+          }
+        }
+        matchInfo = DoRegExpExec(regexp, subject, previous);
+      } while (!IS_NULL(matchInfo));
     } else {
-      // Inside a nested replace (replace called from the replacement function
-      // of another replace) or we have failed to set the reusable array
-      // back due to an exception in a replacement function. Create a new
-      // array to use in the future, or until the original is written back.
-      resultArray = $Array(16);
-    }
-    try {
-      // Must handle exceptions thrown by the replace functions correctly,
-      // including unregistering global regexps.
-      var res = %RegExpExecMultiple(regexp, 
-                                    subject, 
-                                    lastMatchInfo, 
-                                    resultArray);
-      regexp.lastIndex = 0;
-      if (IS_NULL(res)) {
-        // No matches at all. 
-        return subject;  
-      }  
-      var len = res.length; 
-      var i = 0;
-      if (NUMBER_OF_CAPTURES(lastMatchInfo) == 2) {
-        var match_start = 0;
-        while (i < len) {
-          var elem = res[i];
-          if (%_IsSmi(elem)) {
-            if (elem > 0) {
-              match_start = (elem >> 11) + (elem & 0x7ff);
-            } else {
-              match_start = res[++i] - elem;
-            }
-          } else {
-            var func_result = replace.call(null, elem, match_start, subject);
-            if (!IS_STRING(func_result)) func_result = TO_STRING(func_result);
-            res[i] = func_result;
-            match_start += elem.length; 
+      do {
+        startOfMatch = matchInfo[CAPTURE0];
+        result.addSpecialSlice(previous, startOfMatch);
+        previous = matchInfo[CAPTURE1];
+        result.add(ApplyReplacementFunction(replace, matchInfo, subject));
+        // Can't use matchInfo any more from here, since the function could
+        // overwrite it.
+        // Continue with the next match.
+        // Increment previous if we matched an empty string, as per ECMA-262
+        // 15.5.4.10.
+        if (previous == startOfMatch) {
+          // Add the skipped character to the output, if any.
+          if (previous < subject.length) {
+            result.addSpecialSlice(previous, previous + 1);
           }
-          i++;
-        }      
-      } else {      
-        while (i < len) {
-          var elem = res[i];
-          if (!%_IsSmi(elem)) {
-            // elem must be an Array.
-            // Use the apply argument as backing for global RegExp properties.
-            lastMatchInfoOverride = elem;
-            var func_result = replace.apply(null, elem);
-            if (!IS_STRING(func_result)) func_result = TO_STRING(func_result);
-            res[i] = func_result;
+          previous++;
+          // Per ECMA-262 15.10.6.2, if the previous index is greater than the
+          // string length, there is no match
+          if (previous > subject.length) {
+            return result.generate();
           }
-          i++;
         }
-      }
-      var result = new ReplaceResultBuilder(subject, res);
-      return result.generate();
-    } finally {
-      lastMatchInfoOverride = null;
-      resultArray.length = 0;
-      reusableReplaceArray = resultArray;
+        matchInfo = DoRegExpExec(regexp, subject, previous);
+      } while (!IS_NULL(matchInfo));
     }
+
+    // Tack on the final right substring after the last match.
+    result.addSpecialSlice(previous, subject.length);
+
   } else { // Not a global regexp, no need to loop.
-    var matchInfo = DoRegExpExec(regexp, subject, 0);
-    if (IS_NULL(matchInfo)) return subject;
-    
-    var result = new ReplaceResultBuilder(subject);
     result.addSpecialSlice(0, matchInfo[CAPTURE0]);
     var endOfMatch = matchInfo[CAPTURE1];
     result.add(ApplyReplacementFunction(replace, matchInfo, subject));
     // Can't use matchInfo any more from here, since the function could
     // overwrite it.
     result.addSpecialSlice(endOfMatch, subject.length);
-    return result.generate();
   }
+
+  return result.generate();
 }
 
 
@@ -888,11 +894,8 @@ function StringSup() {
 
 // ReplaceResultBuilder support.
 function ReplaceResultBuilder(str) {
-  if (%_ArgumentsLength() > 1) {
-    this.elements = %_Arguments(1);
-  } else {
-    this.elements = new $Array();
-  }
+  this.__proto__ = void 0;
+  this.elements = new $Array();
   this.special_string = str;
 }
 
similarity index 95%
rename from deps/v8/src/type-info-inl.h
rename to deps/v8/src/type-info.cc
index 90d3f55..b1bde59 100644 (file)
@@ -25,9 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#ifndef V8_TYPE_INFO_INL_H_
-#define V8_TYPE_INFO_INL_H_
-
+#include "v8.h"
 #include "type-info.h"
 #include "objects-inl.h"
 
@@ -51,5 +49,3 @@ TypeInfo TypeInfo::TypeFromValue(Handle<Object> value) {
 
 
 } }  // namespace v8::internal
-
-#endif  // V8_TYPE_INFO_INL_H_
index 15bc128..1d82634 100644 (file)
@@ -130,7 +130,7 @@ class TypeInfo {
     return false;
   }
 
-  static inline TypeInfo TypeFromValue(Handle<Object> value);
+  static TypeInfo TypeFromValue(Handle<Object> value);
 
   inline bool IsUnknown() {
     return type_ == kUnknownType;
index a5f3594..bd671a1 100644 (file)
@@ -166,6 +166,7 @@ namespace internal {
   SC(generic_binary_stub_calls_regs, V8.GenericBinaryStubCallsRegs)   \
   SC(string_add_runtime, V8.StringAddRuntime)                         \
   SC(string_add_native, V8.StringAddNative)                           \
+  SC(string_add_runtime_ext_to_ascii, V8.StringAddRuntimeExtToAscii)  \
   SC(sub_string_runtime, V8.SubStringRuntime)                         \
   SC(sub_string_native, V8.SubStringNative)                           \
   SC(string_compare_native, V8.StringCompareNative)                   \
index e3d0887..9d1aa72 100644 (file)
@@ -33,9 +33,9 @@
 // NOTE these macros are used by the SCons build script so their names
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     2
-#define MINOR_VERSION     1
-#define BUILD_NUMBER      10
-#define PATCH_LEVEL       0
+#define MINOR_VERSION     2
+#define BUILD_NUMBER      0
+#define PATCH_LEVEL       3
 #define CANDIDATE_VERSION false
 
 // Define SONAME to have the SCons build the put a specific SONAME into the
index 59a40af..a873987 100644 (file)
@@ -323,6 +323,7 @@ TEST(Utf8Conversion) {
       0xE3, 0x81, 0x85, 0x00};
   // The number of bytes expected to be written for each length
   const int lengths[12] = {0, 0, 2, 3, 3, 3, 6, 7, 7, 7, 10, 11};
+  const int charLengths[12] = {0, 0, 1, 2, 2, 2, 3, 4, 4, 4, 5, 5};
   v8::Handle<v8::String> mixed = v8::String::New(mixed_string, 5);
   CHECK_EQ(10, mixed->Utf8Length());
   // Try encoding the string with all capacities
@@ -332,8 +333,10 @@ TEST(Utf8Conversion) {
     // Clear the buffer before reusing it
     for (int j = 0; j < 11; j++)
       buffer[j] = kNoChar;
-    int written = mixed->WriteUtf8(buffer, i);
+    int charsWritten;
+    int written = mixed->WriteUtf8(buffer, i, &charsWritten);
     CHECK_EQ(lengths[i], written);
+    CHECK_EQ(charLengths[i], charsWritten);
     // Check that the contents are correct
     for (int j = 0; j < lengths[i]; j++)
       CHECK_EQ(as_utf8[j], static_cast<unsigned char>(buffer[j]));
index d5bb0cb..7d0e699 100644 (file)
         '../../src/token.h',
         '../../src/top.cc',
         '../../src/top.h',
-       '../../src/type-info-inl.h',
+       '../../src/type-info.cc',
        '../../src/type-info.h',
         '../../src/unicode-inl.h',
         '../../src/unicode.cc',
index 58bf92f..5fa08f7 100644 (file)
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\type-info-inl.h"
+                               RelativePath="..\..\src\type-info.cc"
                                >
                        </File>
                        <File
index d72b303..1a1f007 100644 (file)
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\type-info-inl.h"
+                               RelativePath="..\..\src\type-info.cc"
                                >
                        </File>
                        <File
index 6d43023..2052fa8 100644 (file)
                                >
                        </File>
                        <File
-                               RelativePath="..\..\src\type-info-inl.h"
+                               RelativePath="..\..\src\type-info.cc"
                                >
                        </File>
                        <File