Author: [email protected]
Date: Wed Mar  4 08:36:53 2009
New Revision: 1421

Removed:
    trunk/test/mjsunit/regexp-string-methods.js
Modified:
    trunk/src/api.cc
    trunk/src/jsregexp.cc
    trunk/src/jsregexp.h
    trunk/src/macros.py
    trunk/src/objects.cc
    trunk/src/objects.h
    trunk/src/regexp-delay.js
    trunk/src/runtime.cc
    trunk/src/runtime.h
    trunk/src/string.js
    trunk/test/mjsunit/regexp-static.js
    trunk/tools/js2c.py

Log:
Pull out bleeding_edge revision 1383, 1391 and 1491 from trunk since it is
causing selenium test failures and potentially reliability test failures
as well.
Review URL: http://codereview.chromium.org/39134

Modified: trunk/src/api.cc
==============================================================================
--- trunk/src/api.cc    (original)
+++ trunk/src/api.cc    Wed Mar  4 08:36:53 2009
@@ -2185,7 +2185,7 @@


  const char* v8::V8::GetVersion() {
-  return "1.0.3.3";
+  return "1.0.3.4";
  }



Modified: trunk/src/jsregexp.cc
==============================================================================
--- trunk/src/jsregexp.cc       (original)
+++ trunk/src/jsregexp.cc       Wed Mar  4 08:36:53 2009
@@ -256,14 +256,12 @@

  Handle<Object> RegExpImpl::Exec(Handle<JSRegExp> regexp,
                                  Handle<String> subject,
-                                int index,
-                                Handle<JSArray> last_match_info) {
+                                Handle<Object> index) {
    switch (regexp->TypeTag()) {
      case JSRegExp::ATOM:
-      return AtomExec(regexp, subject, index, last_match_info);
+      return AtomExec(regexp, subject, index);
      case JSRegExp::IRREGEXP: {
-      Handle<Object> result =
-          IrregexpExec(regexp, subject, index, last_match_info);
+      Handle<Object> result = IrregexpExec(regexp, subject, index);
        ASSERT(!result.is_null() || Top::has_pending_exception());
        return result;
      }
@@ -275,14 +273,12 @@


  Handle<Object> RegExpImpl::ExecGlobal(Handle<JSRegExp> regexp,
-                                Handle<String> subject,
-                                Handle<JSArray> last_match_info) {
+                                Handle<String> subject) {
    switch (regexp->TypeTag()) {
      case JSRegExp::ATOM:
-      return AtomExecGlobal(regexp, subject, last_match_info);
+      return AtomExecGlobal(regexp, subject);
      case JSRegExp::IRREGEXP: {
-      Handle<Object> result =
-          IrregexpExecGlobal(regexp, subject, last_match_info);
+      Handle<Object> result = IrregexpExecGlobal(regexp, subject);
        ASSERT(!result.is_null() || Top::has_pending_exception());
        return result;
      }
@@ -305,79 +301,51 @@
  }


-static void SetAtomLastCapture(FixedArray* array,
-                               String* subject,
-                               int from,
-                               int to) {
-  RegExpImpl::SetLastCaptureCount(array, 2);
-  RegExpImpl::SetLastSubject(array, subject);
-  RegExpImpl::SetLastInput(array, subject);
-  RegExpImpl::SetCapture(array, 0, from);
-  RegExpImpl::SetCapture(array, 1, to);
-}
-
-
  Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
                                      Handle<String> subject,
-                                    int index,
-                                    Handle<JSArray> last_match_info) {
+                                    Handle<Object> index) {
    Handle<String>  
needle(String::cast(re->DataAt(JSRegExp::kAtomPatternIndex)));

-  uint32_t start_index = index;
+  uint32_t start_index;
+  if (!Array::IndexFromObject(*index, &start_index)) {
+    return Handle<Smi>(Smi::FromInt(-1));
+  }

    int value = Runtime::StringMatch(subject, needle, start_index);
    if (value == -1) return Factory::null_value();
-  ASSERT(last_match_info->HasFastElements());

-  Handle<FixedArray> array(last_match_info->elements());
-  SetAtomLastCapture(*array, *subject, value, value + needle->length());
-  return last_match_info;
+  Handle<FixedArray> array = Factory::NewFixedArray(2);
+  array->set(0, Smi::FromInt(value));
+  array->set(1, Smi::FromInt(value + needle->length()));
+  return Factory::NewJSArrayWithElements(array);
  }


  Handle<Object> RegExpImpl::AtomExecGlobal(Handle<JSRegExp> re,
-                                          Handle<String> subject,
-                                          Handle<JSArray> last_match_info)  
{
+                                          Handle<String> subject) {
    Handle<String>  
needle(String::cast(re->DataAt(JSRegExp::kAtomPatternIndex)));
-  ASSERT(last_match_info->HasFastElements());
    Handle<JSArray> result = Factory::NewJSArray(1);
    int index = 0;
    int match_count = 0;
    int subject_length = subject->length();
    int needle_length = needle->length();
-  int last_value = -1;
    while (true) {
-    HandleScope scope;
      int value = -1;
      if (index + needle_length <= subject_length) {
        value = Runtime::StringMatch(subject, needle, index);
      }
-    if (value == -1) {
-      if (last_value != -1) {
-        Handle<FixedArray> array(last_match_info->elements());
-        SetAtomLastCapture(*array,
-                           *subject,
-                           last_value,
-                           last_value + needle->length());
-      }
-      break;
-    }
-
+    if (value == -1) break;
+    HandleScope scope;
      int end = value + needle_length;

-    // Create an array that looks like the static last_match_info array
-    // that is attached to the global RegExp object.  We will be returning
-    // an array of these.
-    Handle<FixedArray> array = Factory::NewFixedArray(kFirstCapture + 2);
-    SetCapture(*array, 0, value);
-    SetCapture(*array, 1, end);
-    SetLastCaptureCount(*array, 2);
+    Handle<FixedArray> array = Factory::NewFixedArray(2);
+    array->set(0, Smi::FromInt(value));
+    array->set(1, Smi::FromInt(end));
      Handle<JSArray> pair = Factory::NewJSArrayWithElements(array);
      SetElement(result, match_count, pair);
      match_count++;
      index = end;
      if (needle_length == 0) index++;
-    last_value = value;
    }
    return result;
  }
@@ -477,8 +445,7 @@

  Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> regexp,
                                          Handle<String> subject,
-                                        int index,
-                                        Handle<JSArray> last_match_info) {
+                                        Handle<Object> index) {
    ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
    ASSERT(regexp->DataAt(JSRegExp::kIrregexpDataIndex)->IsFixedArray());

@@ -490,11 +457,12 @@
    }

    // Prepare space for the return values.
-  int number_of_capture_registers =
-      (IrregexpNumberOfCaptures(irregexp) + 1) * 2;
-  OffsetsVector offsets(number_of_capture_registers);
+  int number_of_registers = IrregexpNumberOfRegisters(irregexp);
+  OffsetsVector offsets(number_of_registers);

-  int previous_index = index;
+  int num_captures = IrregexpNumberOfCaptures(irregexp);
+
+  int previous_index = static_cast<int>(DoubleToInteger(index->Number()));

  #ifdef DEBUG
    if (FLAG_trace_regexp_bytecodes) {
@@ -508,11 +476,8 @@
      FlattenString(subject);
    }

-  last_match_info->EnsureSize(number_of_capture_registers +  
kLastMatchOverhead);
-
    return IrregexpExecOnce(irregexp,
-                          number_of_capture_registers,
-                          last_match_info,
+                          num_captures,
                            subject,
                            previous_index,
                            offsets.vector(),
@@ -521,8 +486,7 @@


  Handle<Object> RegExpImpl::IrregexpExecGlobal(Handle<JSRegExp> regexp,
-                                              Handle<String> subject,
-                                              Handle<JSArray>  
last_match_info) {
+                                              Handle<String> subject) {
    ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);

    bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
@@ -532,22 +496,19 @@
    }

    // Prepare space for the return values.
-  int number_of_capture_registers =
-      (IrregexpNumberOfCaptures(irregexp) + 1) * 2;
-  OffsetsVector offsets(number_of_capture_registers);
+  int number_of_registers = IrregexpNumberOfRegisters(irregexp);
+  OffsetsVector offsets(number_of_registers);

    int previous_index = 0;

    Handle<JSArray> result = Factory::NewJSArray(0);
-  int result_length = 0;
+  int i = 0;
    Handle<Object> matches;

    if (!subject->IsFlat(StringShape(*subject))) {
      FlattenString(subject);
    }

-  last_match_info->EnsureSize(number_of_capture_registers +  
kLastMatchOverhead);
-
    while (true) {
      if (previous_index > subject->length() || previous_index < 0) {
        // Per ECMA-262 15.10.6.2, if the previous index is greater than the
@@ -562,10 +523,8 @@
          PrintF("\n\nSubject string: '%s'\n\n", *(subject->ToCString()));
        }
  #endif
-      HandleScope scope;
        matches = IrregexpExecOnce(irregexp,
-                                 number_of_capture_registers,
-                                 last_match_info,
+                                 IrregexpNumberOfCaptures(irregexp),
                                   subject,
                                   previous_index,
                                   offsets.vector(),
@@ -577,25 +536,12 @@
        }

        if (matches->IsJSArray()) {
-        // Create an array that looks like the static last_match_info array
-        // that is attached to the global RegExp object.  We will be  
returning
-        // an array of these.
-        Handle<FixedArray>  
matches_array(JSArray::cast(*matches)->elements());
-        Handle<JSArray> latest_match =
-            Factory::NewJSArray(kFirstCapture +  
number_of_capture_registers);
-        Handle<FixedArray> latest_match_array(latest_match->elements());
-
-        for (int i = 0; i < number_of_capture_registers; i++) {
-          SetCapture(*latest_match_array, i, GetCapture(*matches_array,  
i));
-        }
-        SetLastCaptureCount(*latest_match_array,  
number_of_capture_registers);
-
-        SetElement(result, result_length, latest_match);
-        result_length++;
-        previous_index = GetCapture(*matches_array, 1);
-        if (GetCapture(*matches_array, 0) == previous_index)
+        SetElement(result, i, matches);
+        i++;
+        previous_index = offsets.vector()[1];
+        if (offsets.vector()[0] == offsets.vector()[1]) {
            previous_index++;
-
+        }
        } else {
          ASSERT(matches->IsNull());
          return result;
@@ -606,8 +552,7 @@


  Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<FixedArray> irregexp,
-                                            int  
number_of_capture_registers,
-                                            Handle<JSArray>  
last_match_info,
+                                            int num_captures,
                                              Handle<String> subject,
                                              int previous_index,
                                              int* offsets_vector,
@@ -697,7 +642,7 @@
  #endif
      }
      case RegExpMacroAssembler::kBytecodeImplementation: {
-      for (int i = number_of_capture_registers - 1; i >= 0; i--) {
+      for (int i = (num_captures + 1) * 2 - 1; i >= 0; i--) {
          offsets_vector[i] = -1;
        }
        Handle<ByteArray> byte_codes = IrregexpByteCode(irregexp);
@@ -719,16 +664,13 @@
      return Factory::null_value();
    }

-  Handle<FixedArray> array(last_match_info->elements());
+  Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1));
    // The captures come in (start, end+1) pairs.
-  for (int i = 0; i < number_of_capture_registers; i += 2) {
-    SetCapture(*array, i, offsets_vector[i]);
-    SetCapture(*array, i + 1, offsets_vector[i + 1]);
-  }
-  SetLastCaptureCount(*array, number_of_capture_registers);
-  SetLastSubject(*array, *subject);
-  SetLastInput(*array, *subject);
-  return last_match_info;
+  for (int i = 0; i < 2 * (num_captures + 1); i += 2) {
+    array->set(i, Smi::FromInt(offsets_vector[i]));
+    array->set(i + 1, Smi::FromInt(offsets_vector[i + 1]));
+  }
+  return Factory::NewJSArrayWithElements(array);
  }


@@ -3781,6 +3723,9 @@
    //               |
    //   [if r >= f] \----> ...
    //
+  //
+  // TODO(someone): clear captures on repetition and handle empty
+  //   matches.

    // 15.10.2.5 RepeatMatcher algorithm.
    // The parser has already eliminated the case where max is 0.  In the  
case

Modified: trunk/src/jsregexp.h
==============================================================================
--- trunk/src/jsregexp.h        (original)
+++ trunk/src/jsregexp.h        Wed Mar  4 08:36:53 2009
@@ -59,15 +59,13 @@
    // This function calls the garbage collector if necessary.
    static Handle<Object> Exec(Handle<JSRegExp> regexp,
                               Handle<String> subject,
-                             int index,
-                             Handle<JSArray> lastMatchInfo);
+                             Handle<Object> index);

    // Call RegExp.prototyp.exec(string) in a loop.
    // Used by String.prototype.match and String.prototype.replace.
    // This function calls the garbage collector if necessary.
    static Handle<Object> ExecGlobal(Handle<JSRegExp> regexp,
-                                   Handle<String> subject,
-                                   Handle<JSArray> lastMatchInfo);
+                                   Handle<String> subject);

    // Prepares a JSRegExp object with Irregexp-specific data.
    static Handle<Object> IrregexpPrepare(Handle<JSRegExp> re,
@@ -81,22 +79,18 @@
                                      Handle<String> match_pattern);
    static Handle<Object> AtomExec(Handle<JSRegExp> regexp,
                                   Handle<String> subject,
-                                 int index,
-                                 Handle<JSArray> lastMatchInfo);
+                                 Handle<Object> index);

    static Handle<Object> AtomExecGlobal(Handle<JSRegExp> regexp,
-                                       Handle<String> subject,
-                                       Handle<JSArray> lastMatchInfo);
+                                       Handle<String> subject);

    // Execute an Irregexp bytecode pattern.
    static Handle<Object> IrregexpExec(Handle<JSRegExp> regexp,
                                       Handle<String> subject,
-                                     int index,
-                                     Handle<JSArray> lastMatchInfo);
+                                     Handle<Object> index);

    static Handle<Object> IrregexpExecGlobal(Handle<JSRegExp> regexp,
-                                           Handle<String> subject,
-                                           Handle<JSArray> lastMatchInfo);
+                                           Handle<String> subject);

    static void NewSpaceCollectionPrologue();
    static void OldSpaceCollectionPrologue();
@@ -113,30 +107,6 @@
    static const int kIrregexpCodeIndex = 3;
    static const int kIrregexpDataLength = 4;

-  // Offsets in the lastMatchInfo array.
-  static const int kLastCaptureCount = 0;
-  static const int kLastSubject = 1;
-  static const int kLastInput = 2;
-  static const int kFirstCapture = 1;
-  static const int kLastMatchOverhead = 3;
-  static int GetCapture(FixedArray* array, int index) {
-    return Smi::cast(array->get(index + kFirstCapture))->value();
-  }
-  static void SetLastCaptureCount(FixedArray* array, int to) {
-    array->set(kLastCaptureCount, Smi::FromInt(to));
-  }
-  static void SetLastSubject(FixedArray* array, String* to) {
-    int capture_count = GetLastCaptureCount(array);
-    array->set(capture_count + kLastSubject, to);
-  }
-  static void SetLastInput(FixedArray* array, String* to) {
-    int capture_count = GetLastCaptureCount(array);
-    array->set(capture_count + kLastInput, to);
-  }
-  static void SetCapture(FixedArray* array, int index, int to) {
-    array->set(index + kFirstCapture, Smi::FromInt(to));
-  }
-
   private:
    static String* last_ascii_string_;
    static String* two_byte_cached_string_;
@@ -151,7 +121,6 @@
    // Returns an empty handle in case of an exception.
    static Handle<Object> IrregexpExecOnce(Handle<FixedArray> regexp,
                                           int num_captures,
-                                         Handle<JSArray> lastMatchInfo,
                                           Handle<String> subject16,
                                           int previous_index,
                                           int* ovector,
@@ -165,10 +134,6 @@
                                int character_position,
                                int utf8_position);

-  // Used to access the lastMatchInfo array.
-  static int GetLastCaptureCount(FixedArray* array) {
-    return Smi::cast(array->get(kLastCaptureCount))->value();
-  }
    // A one element cache of the last utf8_subject string and its length.   
The
    // subject JS String object is cached in the heap.  We also cache a
    // translation between position and utf8 position.

Modified: trunk/src/macros.py
==============================================================================
--- trunk/src/macros.py (original)
+++ trunk/src/macros.py Wed Mar  4 08:36:53 2009
@@ -1,4 +1,4 @@
-# Copyright 2006-2009 the V8 project authors. All rights reserved.
+# Copyright 2006-2008 the V8 project authors. All rights reserved.
  # Redistribution and use in source and binary forms, with or without
  # modification, are permitted provided that the following conditions are
  # met:
@@ -99,22 +99,3 @@
  # Accessors for original global properties that ensure they have been  
loaded.
  const ORIGINAL_REGEXP = (global.RegExp, $RegExp);
  const ORIGINAL_DATE   = (global.Date, $Date);
-
-# Constants used on an array to implement the properties of the RegExp  
object.
-const REGEXP_NUMBER_OF_CAPTURES = 0;
-const REGEXP_FIRST_CAPTURE = 1;
-
-# We can't put macros in macros so we use constants here.
-# REGEXP_NUMBER_OF_CAPTURES
-macro NUMBER_OF_CAPTURES(array) = ((array)[0]);
-
-# Last input and last subject are after the captures so we can omit them on
-# results returned from global searches.  Beware - these evaluate their
-# arguments twice.
-macro LAST_SUBJECT(array) = ((array)[(array)[0] + 1]);
-macro LAST_INPUT(array) = ((array)[(array)[0] + 2]);
-
-# REGEXP_FIRST_CAPTURE
-macro CAPTURE(index) = (1 + (index));
-const CAPTURE0 = 1;
-const CAPTURE1 = 2;

Modified: trunk/src/objects.cc
==============================================================================
--- trunk/src/objects.cc        (original)
+++ trunk/src/objects.cc        Wed Mar  4 08:36:53 2009
@@ -4879,22 +4879,6 @@
  }


-void JSArray::EnsureSize(int required_size) {
-  Handle<JSArray> self(this);
-  ASSERT(HasFastElements());
-  if (elements()->length() >= required_size) return;
-  Handle<FixedArray> old_backing(elements());
-  int old_size = old_backing->length();
-  // Doubling in size would be overkill, but leave some slack to avoid
-  // constantly growing.
-  int new_size = required_size + (required_size >> 3);
-  Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size);
-  // Can't use this any more now because we may have had a GC!
-  for (int i = 0; i < old_size; i++) new_backing->set(i,  
old_backing->get(i));
-  self->SetContent(*new_backing);
-}
-
-
  // Computes the new capacity when expanding the elements of a JSObject.
  static int NewElementsCapacity(int old_capacity) {
    // (old_capacity + 50%) + 16

Modified: trunk/src/objects.h
==============================================================================
--- trunk/src/objects.h (original)
+++ trunk/src/objects.h Wed Mar  4 08:36:53 2009
@@ -3786,10 +3786,6 @@
    // Casting.
    static inline JSArray* cast(Object* obj);

-  // Uses handles.  Ensures that the fixed array backing the JSArray has at
-  // least the stated size.
-  void EnsureSize(int minimum_size_of_backing_fixed_array);
-
    // Dispatched behavior.
  #ifdef DEBUG
    void JSArrayPrint();

Modified: trunk/src/regexp-delay.js
==============================================================================
--- trunk/src/regexp-delay.js   (original)
+++ trunk/src/regexp-delay.js   Wed Mar  4 08:36:53 2009
@@ -1,4 +1,4 @@
-// Copyright 2006-2009 the V8 project authors. All rights reserved.
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
@@ -52,7 +52,7 @@
    var multiline = false;

    for (var i = 0; i < flags.length; i++) {
-    var c = StringCharAt.call(flags, i);
+    var c = flags.charAt(i);
      switch (c) {
        case 'g':
          // Allow duplicate flags to be consistent with JSC and others.
@@ -117,15 +117,15 @@

  // Deprecated RegExp.prototype.compile method.  We behave like the  
constructor
  // were called again.  In SpiderMonkey, this method returns the regexp  
object.
-// In JSC, it returns undefined.  For compatibility with JSC, we match  
their
+// In KJS, it returns undefined.  For compatibility with KJS, we match  
their
  // behavior.
  function CompileRegExp(pattern, flags) {
-  // Both JSC and SpiderMonkey treat a missing pattern argument as the
+  // Both KJS and SpiderMonkey treat a missing pattern argument as the
    // empty subject string, and an actual undefined value passed as the
-  // pattern as the string 'undefined'.  Note that JSC is inconsistent
+  // patter as the string 'undefined'.  Note that KJS is inconsistent
    // here, treating undefined values differently in
    // RegExp.prototype.compile and in the constructor, where they are
-  // the empty string.  For compatibility with JSC, we match their
+  // the empty string.  For compatibility with KJS, we match their
    // behavior.
    if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) {
      DoConstructRegExp(this, 'undefined', flags, false);
@@ -135,20 +135,32 @@
  }


+// DoRegExpExec and DoRegExpExecGlobal are wrappers around the runtime
+// %RegExp and %RegExpGlobal functions that ensure that the static
+// properties of the RegExp constructor are set.
  function DoRegExpExec(regexp, string, index) {
-  return %RegExpExec(regexp, string, index, lastMatchInfo);
+  var matchIndices = %RegExpExec(regexp, string, index);
+  if (!IS_NULL(matchIndices)) {
+    regExpCaptures = matchIndices;
+    regExpSubject = regExpInput = string;
+  }
+  return matchIndices;
  }


  function DoRegExpExecGlobal(regexp, string) {
-  // Returns an array of arrays of substring indices.
-  return %RegExpExecGlobal(regexp, string, lastMatchInfo);
+  // Here, matchIndices is an array of arrays of substring indices.
+  var matchIndices = %RegExpExecGlobal(regexp, string);
+  if (matchIndices.length != 0) {
+    regExpCaptures = matchIndices[matchIndices.length - 1];
+    regExpSubject = regExpInput = string;
+  }
+  return matchIndices;
  }


  function RegExpExec(string) {
    if (%_ArgumentsLength() == 0) {
-    var regExpInput = LAST_INPUT(lastMatchInfo);
      if (IS_UNDEFINED(regExpInput)) {
        throw MakeError('no_input_to_regexp', [this]);
      }
@@ -165,21 +177,23 @@
    }

    %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
-  // matchIndices is either null or the lastMatchInfo array.
-  var matchIndices = %RegExpExec(this, s, i, lastMatchInfo);
+  // matchIndices is an array of integers with length of captures*2,
+  // each pair of integers specified the start and the end of index
+  // in the string.
+  var matchIndices = DoRegExpExec(this, s, i);

    if (matchIndices == null) {
      if (this.global) this.lastIndex = 0;
      return matchIndices; // no match
    }

-  var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
+  var numResults = matchIndices.length >> 1;
    var result = new $Array(numResults);
    for (var i = 0; i < numResults; i++) {
-    var matchStart = lastMatchInfo[CAPTURE(i << 1)];
-    var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)];
+    var matchStart = matchIndices[2*i];
+    var matchEnd = matchIndices[2*i + 1];
      if (matchStart != -1 && matchEnd != -1) {
-      result[i] = SubString(s, matchStart, matchEnd);
+      result[i] = s.slice(matchStart, matchEnd);
      } else {
        // Make sure the element is present. Avoid reading the undefined
        // property from the global object since this may change.
@@ -188,15 +202,13 @@
    }

    if (this.global)
-    this.lastIndex = lastMatchInfo[CAPTURE1];
-  result.index = lastMatchInfo[CAPTURE0];
+    this.lastIndex = matchIndices[1];
+  result.index = matchIndices[0];
    result.input = s;
    return result;
  }


-// Section 15.10.6.3 doesn't actually make sense, but the intention seems  
to be
-// that test is defined in terms of String.prototype.exec even if it  
changes.
  function RegExpTest(string) {
    var result = (%_ArgumentsLength() == 0) ? this.exec() :  
this.exec(string);
    return result != null;
@@ -224,69 +236,56 @@
  // on the captures array of the last successful match and the subject  
string
  // of the last successful match.
  function RegExpGetLastMatch() {
-  var regExpSubject = LAST_SUBJECT(lastMatchInfo);
-  return SubString(regExpSubject,
-                   lastMatchInfo[CAPTURE0],
-                   lastMatchInfo[CAPTURE1]);
+  return regExpSubject.slice(regExpCaptures[0], regExpCaptures[1]);
  }


  function RegExpGetLastParen() {
-  var length = NUMBER_OF_CAPTURES(lastMatchInfo);
-  if (length <= 2) return '';  // There were no captures.
+  var length = regExpCaptures.length;
+  if (length <= 2) return ''; // There were no captures.
    // We match the SpiderMonkey behavior: return the substring defined by  
the
    // last pair (after the first pair) of elements of the capture array  
even if
    // it is empty.
-  var regExpSubject = LAST_SUBJECT(lastMatchInfo);
-  return SubString(regExpSubject,
-                   lastMatchInfo[CAPTURE(length - 2)],
-                   lastMatchInfo[CAPTURE(length - 1)]);
+  return regExpSubject.slice(regExpCaptures[length - 2],
+                             regExpCaptures[length - 1]);
  }


  function RegExpGetLeftContext() {
-  return SubString(LAST_SUBJECT(lastMatchInfo),
-                   0,
-                   lastMatchInfo[CAPTURE0]);
+  return regExpSubject.slice(0, regExpCaptures[0]);
  }


  function RegExpGetRightContext() {
-  var subject = LAST_SUBJECT(lastMatchInfo);
-  return SubString(subject,
-                   lastMatchInfo[CAPTURE1],
-                   subject.length);
+  return regExpSubject.slice(regExpCaptures[1], regExpSubject.length);
  }


  // The properties $1..$9 are the first nine capturing substrings of the  
last
  // successful match, or ''.  The function RegExpMakeCaptureGetter will be
-// called with indeces from 1 to 9.
+// called with an index greater than or equal to 1 but it actually works  
for
+// any non-negative index.
  function RegExpMakeCaptureGetter(n) {
    return function() {
      var index = n * 2;
-    if (index >= NUMBER_OF_CAPTURES(lastMatchInfo)) return '';
-    var matchStart = lastMatchInfo[CAPTURE(index)];
-    var matchEnd = lastMatchInfo[CAPTURE(index + 1)];
+    if (index >= regExpCaptures.length) return '';
+    var matchStart = regExpCaptures[index];
+    var matchEnd = regExpCaptures[index + 1];
      if (matchStart == -1 || matchEnd == -1) return '';
-    return SubString(LAST_SUBJECT(lastMatchInfo), matchStart, matchEnd);
+    return regExpSubject.slice(matchStart, matchEnd);
    };
  }


-// Property of the builtins object for recording the result of the last
-// regexp match.  The property lastMatchInfo includes the matchIndices
-// array of the last successful regexp match (an array of start/end index
-// pairs for the match and all the captured substrings), the invariant is
-// that there are at least two capture indeces.  The array also contains
-// the subject string for the last successful match.
-var lastMatchInfo = [
-    2,                 // REGEXP_NUMBER_OF_CAPTURES
-    0,                 // REGEXP_FIRST_CAPTURE + 0
-    0,                 // REGEXP_FIRST_CAPTURE + 1
-    "",                // Last subject.
-    void 0,            // Last input - settable with RegExpSetInput.
-];
+// Properties of the builtins object for recording the result of the last
+// regexp match.  The property regExpCaptures is the matchIndices array of  
the
+// last successful regexp match (an array of start/end index pairs for the
+// match and all the captured substrings), the invariant is that there is  
at
+// least two elements.  The property regExpSubject is the subject string  
for
+// the last successful match.
+var regExpCaptures = [0, 0];
+var regExpSubject = '';
+var regExpInput;

  // -------------------------------------------------------------------

@@ -304,23 +303,19 @@
    ));

    // The spec says nothing about the length of exec and test, but
-  // SpiderMonkey and JSC have length equal to 0.
+  // SpiderMonkey and KJS have length equal to 0.
    %FunctionSetLength($RegExp.prototype.exec, 0);
    %FunctionSetLength($RegExp.prototype.test, 0);
    // The length of compile is 1 in SpiderMonkey.
    %FunctionSetLength($RegExp.prototype.compile, 1);

    // The properties input, $input, and $_ are aliases for each other.   
When this
-  // value is set the value it is set to is coerced to a string.
+  // value is set the value it is set to is coerced to a string.
    // Getter and setter for the input.
    function RegExpGetInput() {
-    var regExpInput = LAST_INPUT(lastMatchInfo);
      return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
    }
-  function RegExpSetInput(string) {
-    lastMatchInfo[lastMatchInfo[REGEXP_NUMBER_OF_CAPTURES] + 2] =
-        ToString(string);
-  };
+  function RegExpSetInput(string) { regExpInput = ToString(string); }

    %DefineAccessor($RegExp, 'input', GETTER, RegExpGetInput, DONT_DELETE);
    %DefineAccessor($RegExp, 'input', SETTER, RegExpSetInput, DONT_DELETE);

Modified: trunk/src/runtime.cc
==============================================================================
--- trunk/src/runtime.cc        (original)
+++ trunk/src/runtime.cc        Wed Mar  4 08:36:53 2009
@@ -858,21 +858,14 @@

  static Object* Runtime_RegExpExec(Arguments args) {
    HandleScope scope;
-  ASSERT(args.length() == 4);
+  ASSERT(args.length() == 3);
    CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
    Handle<JSRegExp> regexp(raw_regexp);
    CONVERT_CHECKED(String, raw_subject, args[1]);
    Handle<String> subject(raw_subject);
-  // Due to the way the JS files are constructed this must be less than the
-  // length of a string, i.e. it is always a Smi.  We check anyway for  
security.
-  CONVERT_CHECKED(Smi, index, args[2]);
-  CONVERT_CHECKED(JSArray, raw_last_match_info, args[3]);
-  Handle<JSArray> last_match_info(raw_last_match_info);
-  CHECK(last_match_info->HasFastElements());
-  Handle<Object> result = RegExpImpl::Exec(regexp,
-                                           subject,
-                                           index->value(),
-                                           last_match_info);
+  Handle<Object> index(args[2]);
+  ASSERT(index->IsNumber());
+  Handle<Object> result = RegExpImpl::Exec(regexp, subject, index);
    if (result.is_null()) return Failure::Exception();
    return *result;
  }
@@ -880,16 +873,12 @@

  static Object* Runtime_RegExpExecGlobal(Arguments args) {
    HandleScope scope;
-  ASSERT(args.length() == 3);
+  ASSERT(args.length() == 2);
    CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
    Handle<JSRegExp> regexp(raw_regexp);
    CONVERT_CHECKED(String, raw_subject, args[1]);
    Handle<String> subject(raw_subject);
-  CONVERT_CHECKED(JSArray, raw_last_match_info, args[2]);
-  Handle<JSArray> last_match_info(raw_last_match_info);
-  CHECK(last_match_info->HasFastElements());
-  Handle<Object> result =
-      RegExpImpl::ExecGlobal(regexp, subject, last_match_info);
+  Handle<Object> result = RegExpImpl::ExecGlobal(regexp, subject);
    if (result.is_null()) return Failure::Exception();
    return *result;
  }

Modified: trunk/src/runtime.h
==============================================================================
--- trunk/src/runtime.h (original)
+++ trunk/src/runtime.h Wed Mar  4 08:36:53 2009
@@ -137,8 +137,8 @@
    \
    /* Regular expressions */ \
    F(RegExpCompile, 3) \
-  F(RegExpExec, 4) \
-  F(RegExpExecGlobal, 3) \
+  F(RegExpExec, 3) \
+  F(RegExpExecGlobal, 2) \
    \
    /* Strings */ \
    F(StringCharCodeAt, 2) \

Modified: trunk/src/string.js
==============================================================================
--- trunk/src/string.js (original)
+++ trunk/src/string.js Wed Mar  4 08:36:53 2009
@@ -165,9 +165,8 @@
    // Build the result array.
    var result = new $Array(match_string);
    for (var i = 0; i < matches.length; ++i) {
-    var matchInfo = matches[i];
-    var match_string = subject.slice(matchInfo[CAPTURE0],
-                                     matchInfo[CAPTURE1]);
+    var match = matches[i];
+    var match_string = subject.slice(match[0], match[1]);
      result[i] = match_string;
    }

@@ -219,9 +218,7 @@
    if (IS_FUNCTION(replace)) {
      builder.add(replace.call(null, search, start, subject));
    } else {
-    reusableMatchInfo[CAPTURE0] = start;
-    reusableMatchInfo[CAPTURE1] = end;
-    ExpandReplacement(ToString(replace), subject, reusableMatchInfo,  
builder);
+    ExpandReplacement(ToString(replace), subject, [ start, end ], builder);
    }

    // suffix
@@ -231,15 +228,6 @@
  }


-// This has the same size as the lastMatchInfo array, and can be used for
-// functions that expect that structure to be returned.  It is used when  
the
-// needle is a string rather than a regexp.  In this case we can't update
-// lastMatchArray without erroneously affecting the properties on the  
global
-// RegExp object.
-var reusableMatchInfo = [2, -1, -1, "", ""];
-var reusableMatchArray = [ void 0 ];
-
-
  // Helper function for regular expressions in String.prototype.replace.
  function StringReplaceRegExp(subject, regexp, replace) {
    // Compute an array of matches; each match is really a list of
@@ -249,10 +237,9 @@
      matches = DoRegExpExecGlobal(regexp, subject);
      if (matches.length == 0) return subject;
    } else {
-    var lastMatchInfo = DoRegExpExec(regexp, subject, 0);
-    if (IS_NULL(lastMatchInfo)) return subject;
-    reusableMatchArray[0] = lastMatchInfo;
-    matches = reusableMatchArray;
+    var captures = DoRegExpExec(regexp, subject, 0);
+    if (IS_NULL(captures)) return subject;
+    matches = [ captures ];
    }

    // Determine the number of matches.
@@ -266,17 +253,17 @@
    replace = ToString(replace);
    if (%StringIndexOf(replace, "$", 0) < 0) {
      for (var i = 0; i < length; i++) {
-      var matchInfo = matches[i];
-      result.addSpecialSlice(previous, matchInfo[CAPTURE0]);
+      var captures = matches[i];
+      result.addSpecialSlice(previous, captures[0]);
        result.add(replace);
-      previous = matchInfo[CAPTURE1];  // continue after match
+      previous = captures[1];  // continue after match
      }
    } else {
      for (var i = 0; i < length; i++) {
-      var matchInfo = matches[i];
-      result.addSpecialSlice(previous, matchInfo[CAPTURE0]);
-      ExpandReplacement(replace, subject, matchInfo, result);
-      previous = matchInfo[CAPTURE1];  // continue after match
+      var captures = matches[i];
+      result.addSpecialSlice(previous, captures[0]);
+      ExpandReplacement(replace, subject, captures, result);
+      previous = captures[1];  // continue after match
      }
    }
    result.addSpecialSlice(previous, subject.length);
@@ -286,7 +273,7 @@

  // Expand the $-expressions in the string and return a new string with
  // the result.
-function ExpandReplacement(string, subject, matchInfo, builder) {
+function ExpandReplacement(string, subject, captures, builder) {
    var next = %StringIndexOf(string, '$', 0);
    if (next < 0) {
      builder.add(string);
@@ -294,12 +281,11 @@
    }

    // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
-  var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;  // Includes the match.
+  var m = captures.length >> 1;  // includes the match

    if (next > 0) builder.add(SubString(string, 0, next));
    var length = string.length;

-
    while (true) {
      var expansion = '$';
      var position = next + 1;
@@ -313,14 +299,13 @@
          builder.add('$');
        } else if (peek == 38) {  // $& - match
          ++position;
-        builder.addSpecialSlice(matchInfo[CAPTURE0],
-                                matchInfo[CAPTURE1]);
+        builder.addSpecialSlice(captures[0], captures[1]);
        } else if (peek == 96) {  // $` - prefix
          ++position;
-        builder.addSpecialSlice(0, matchInfo[CAPTURE0]);
+        builder.addSpecialSlice(0, captures[0]);
        } else if (peek == 39) {  // $' - suffix
          ++position;
-        builder.addSpecialSlice(matchInfo[CAPTURE1], subject.length);
+        builder.addSpecialSlice(captures[1], subject.length);
        } else if (peek >= 48 && peek <= 57) {  // $n, 0 <= n <= 9
          ++position;
          var n = peek - 48;
@@ -344,7 +329,7 @@
            }
          }
          if (0 < n && n < m) {
-          addCaptureString(builder, matchInfo, n);
+          addCaptureString(builder, captures, n);
          } else {
            // Because of the captures range check in the parsing of two
            // digit capture references, we can only enter here when a
@@ -376,27 +361,26 @@
  };


-// Compute the string of a given regular expression capture.
-function CaptureString(string, lastCaptureInfo, index) {
+// Compute the string of a given PCRE capture.
+function CaptureString(string, captures, index) {
    // Scale the index.
    var scaled = index << 1;
    // Compute start and end.
-  var start = lastCaptureInfo[CAPTURE(scaled)];
-  var end = lastCaptureInfo[CAPTURE(scaled + 1)];
+  var start = captures[scaled];
+  var end = captures[scaled + 1];
    // If either start or end is missing return undefined.
    if (start < 0 || end < 0) return;
    return SubString(string, start, end);
  };


-// Add the string of a given regular expression capture to the
-// ReplaceResultBuilder
-function addCaptureString(builder, matchInfo, index) {
+// Add the string of a given PCRE capture to the ReplaceResultBuilder
+function addCaptureString(builder, captures, index) {
    // Scale the index.
    var scaled = index << 1;
    // Compute start and end.
-  var start = matchInfo[CAPTURE(scaled)];
-  var end = matchInfo[CAPTURE(scaled + 1)];
+  var start = captures[scaled];
+  var end = captures[scaled + 1];
    // If either start or end is missing return.
    if (start < 0 || end <= start) return;
    builder.addSpecialSlice(start, end);
@@ -412,8 +396,10 @@
  // should be 'abcd' and not 'dddd' (or anything else).
  function StringReplaceRegExpWithFunction(subject, regexp, replace) {
    var result = new ReplaceResultBuilder(subject);
-  var lastMatchInfo = DoRegExpExec(regexp, subject, 0);
-  if (IS_NULL(lastMatchInfo)) return subject;
+  // Captures is an array of pairs of (start, end) indices for the match  
and
+  // any captured substrings.
+  var captures = DoRegExpExec(regexp, subject, 0);
+  if (IS_NULL(captures)) return 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
@@ -423,16 +409,13 @@
    if (regexp.global) {
      var previous = 0;
      do {
-      result.addSpecialSlice(previous, lastMatchInfo[CAPTURE0]);
-      var startOfMatch = lastMatchInfo[CAPTURE0];
-      previous = lastMatchInfo[CAPTURE1];
-      result.add(ApplyReplacementFunction(replace, lastMatchInfo,  
subject));
-      // Can't use lastMatchInfo any more from here, since the function  
could
-      // overwrite it.
+      result.addSpecialSlice(previous, captures[0]);
+      result.add(ApplyReplacementFunction(replace, captures, subject));
        // Continue with the next match.
+      previous = captures[1];
        // Increment previous if we matched an empty string, as per ECMA-262
        // 15.5.4.10.
-      if (previous == startOfMatch) {
+      if (previous == captures[0]) {
          // Add the skipped character to the output, if any.
          if (previous < subject.length) {
            result.addSpecialSlice(previous, previous + 1);
@@ -442,22 +425,19 @@

        // Per ECMA-262 15.10.6.2, if the previous index is greater than the
        // string length, there is no match
-      lastMatchInfo = (previous > subject.length)
+      captures = (previous > subject.length)
            ? null
            : DoRegExpExec(regexp, subject, previous);
-    } while (!IS_NULL(lastMatchInfo));
+    } while (!IS_NULL(captures));

      // Tack on the final right substring after the last match, if  
necessary.
      if (previous < subject.length) {
        result.addSpecialSlice(previous, subject.length);
      }
    } else { // Not a global regexp, no need to loop.
-    result.addSpecialSlice(0, lastMatchInfo[CAPTURE0]);
-    var endOfMatch = lastMatchInfo[CAPTURE1];
-    result.add(ApplyReplacementFunction(replace, lastMatchInfo, subject));
-    // Can't use lastMatchInfo any more from here, since the function could
-    // overwrite it.
-    result.addSpecialSlice(endOfMatch, subject.length);
+    result.addSpecialSlice(0, captures[0]);
+    result.add(ApplyReplacementFunction(replace, captures, subject));
+    result.addSpecialSlice(captures[1], subject.length);
    }

    return result.generate();
@@ -465,20 +445,20 @@


  // Helper function to apply a string replacement function once.
-function ApplyReplacementFunction(replace, lastMatchInfo, subject) {
+function ApplyReplacementFunction(replace, captures, subject) {
    // Compute the parameter list consisting of the match, captures, index,
    // and subject for the replace function invocation.
-  var index = lastMatchInfo[CAPTURE0];
+  var index = captures[0];
    // The number of captures plus one for the match.
-  var m = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
+  var m = captures.length >> 1;
    if (m == 1) {
-    var s = CaptureString(subject, lastMatchInfo, 0);
+    var s = CaptureString(subject, captures, 0);
      // Don't call directly to avoid exposing the built-in global object.
      return ToString(replace.call(null, s, index, subject));
    }
    var parameters = $Array(m + 2);
    for (var j = 0; j < m; j++) {
-    parameters[j] = CaptureString(subject, lastMatchInfo, j);
+    parameters[j] = CaptureString(subject, captures, j);
    }
    parameters[j] = index;
    parameters[j + 1] = subject;
@@ -579,14 +559,14 @@
        return result;
      }

-    var lastMatchInfo = splitMatch(sep, subject, currentIndex, startIndex);
+    var match = splitMatch(sep, subject, currentIndex, startIndex);

-    if (IS_NULL(lastMatchInfo)) {
+    if (IS_NULL(match)) {
        result[result.length] = subject.slice(currentIndex, length);
        return result;
      }

-    var endIndex = lastMatchInfo[CAPTURE1];
+    var endIndex = match[0];

      // We ignore a zero-length match at the currentIndex.
      if (startIndex === endIndex && endIndex === currentIndex) {
@@ -594,20 +574,11 @@
        continue;
      }

-    result[result.length] =
-        SubString(subject, currentIndex, lastMatchInfo[CAPTURE0]);
+    result[result.length] = match[1];
      if (result.length === lim) return result;

-    for (var i = 2; i < NUMBER_OF_CAPTURES(lastMatchInfo); i += 2) {
-      var start = lastMatchInfo[CAPTURE(i)];
-      var end = lastMatchInfo[CAPTURE(i + 1)];
-      if (start != -1 && end != -1) {
-        result[result.length] = SubString(subject,
-                                          lastMatchInfo[CAPTURE(i)],
-                                          lastMatchInfo[CAPTURE(i + 1)]);
-      } else {
-        result[result.length] = void 0;
-      }
+    for (var i = 2; i < match.length; i++) {
+      result[result.length] = match[i];
        if (result.length === lim) return result;
      }

@@ -617,24 +588,32 @@


  // ECMA-262 section 15.5.4.14
-// Helper function used by split.  This version returns the lastMatchInfo
-// instead of allocating a new array with basically the same information.
+// Helper function used by split.
  function splitMatch(separator, subject, current_index, start_index) {
    if (IS_REGEXP(separator)) {
-    var lastMatchInfo = DoRegExpExec(separator, subject, start_index);
-    if (lastMatchInfo == null) return null;
+    var ovector = DoRegExpExec(separator, subject, start_index);
+    if (ovector == null) return null;
+    var nof_results = ovector.length >> 1;
+    var result = new $Array(nof_results + 1);
      // Section 15.5.4.14 paragraph two says that we do not allow zero  
length
      // matches at the end of the string.
-    if (lastMatchInfo[CAPTURE0] === subject.length) return null;
-    return lastMatchInfo;
+    if (ovector[0] === subject.length) return null;
+    result[0] = ovector[1];
+    result[1] = subject.slice(current_index, ovector[0]);
+    for (var i = 1; i < nof_results; i++) {
+      var matching_start = ovector[2*i];
+      var matching_end = ovector[2*i + 1];
+      if (matching_start != -1 && matching_end != -1) {
+        result[i + 1] = subject.slice(matching_start, matching_end);
+      }
+    }
+    return result;
    }

    var separatorIndex = subject.indexOf(separator, start_index);
    if (separatorIndex === -1) return null;

-  reusableMatchInfo[CAPTURE0] = separatorIndex;
-  reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length;
-  return reusableMatchInfo;
+  return [ separatorIndex + separator.length, subject.slice(current_index,  
separatorIndex) ];
  };



Modified: trunk/test/mjsunit/regexp-static.js
==============================================================================
--- trunk/test/mjsunit/regexp-static.js (original)
+++ trunk/test/mjsunit/regexp-static.js Wed Mar  4 08:36:53 2009
@@ -132,8 +132,3 @@
  re = /(.)/g;
  function f() { return RegExp.$1; };
  assertEquals('abcd', 'abcd'.replace(re, f));
-
-RegExp.multiline = "foo";
-assertTrue(typeof RegExp.multiline == typeof Boolean(), "RegExp.multiline  
coerces values to booleans");
-RegExp.input = Number();
-assertTrue(typeof RegExp.input == typeof String(), "RegExp.input coerces  
values to booleans");

Modified: trunk/tools/js2c.py
==============================================================================
--- trunk/tools/js2c.py (original)
+++ trunk/tools/js2c.py Wed Mar  4 08:36:53 2009
@@ -104,7 +104,7 @@

  def ExpandMacros(lines, macros):
    for name, macro in macros.items():
-    start = lines.find(name + '(', 0)
+    start = lines.find(name, 0)
      while start != -1:
        # Scan over the arguments
        assert lines[start + len(name)] == '('
@@ -132,7 +132,7 @@
        result = macro.expand(mapping)
        # Replace the occurrence of the macro with the expansion
        lines = lines[:start] + result + lines[end:]
-      start = lines.find(name + '(', end)
+      start = lines.find(name, end)
    return lines

  class TextMacro:

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

Reply via email to