Revision: 8772
Author:   [email protected]
Date:     Mon Aug  1 11:06:10 2011
Log:      Merge regexp codeflushing (r8532+r8560) to the 3.3 branch.

Slava and Danno: this was a clean merge, but please do take a good look anyway.
Review URL: http://codereview.chromium.org/7540025
http://code.google.com/p/v8/source/detail?r=8772

Added:
 /branches/3.3/test/mjsunit/regress/regress-regexp-codeflush.js
Modified:
 /branches/3.3/src/arm/code-stubs-arm.cc
 /branches/3.3/src/factory.cc
 /branches/3.3/src/heap.cc
 /branches/3.3/src/heap.h
 /branches/3.3/src/ia32/code-stubs-ia32.cc
 /branches/3.3/src/jsregexp.cc
 /branches/3.3/src/mark-compact.cc
 /branches/3.3/src/objects-debug.cc
 /branches/3.3/src/objects-inl.h
 /branches/3.3/src/objects-visiting.cc
 /branches/3.3/src/objects-visiting.h
 /branches/3.3/src/objects.h
 /branches/3.3/src/regexp.js
 /branches/3.3/src/string.js
 /branches/3.3/src/version.cc
 /branches/3.3/src/x64/code-stubs-x64.cc

=======================================
--- /dev/null
+++ /branches/3.3/test/mjsunit/regress/regress-regexp-codeflush.js Mon Aug 1 11:06:10 2011
@@ -0,0 +1,55 @@
+// Copyright 2011 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:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --gc_global
+
+// Regression test for regexp that has multiple matches and which
+// internally calls RegExpImpl::IrregexpExecOnce more than once without
+// ensuring that the regexp is compiled.
+// This can create a crash if the code was exchanged with the sweep
+// generation (for code flushing support) in GC durring the matching.
+
+var re = new RegExp('(s)', "g");
+
+function foo() {
+  return "42";
+}
+
+// Run enough times to get a number of GC's (all mark sweep because of the
+// --gc_global) flag.
+for ( var i = 0; i < 10; i++) {
+  // Make a long string with plenty of matches for re.
+  var x = "s foo s bar s foo s bar s";
+  x = x + x;
+  x = x + x;
+  x = x + x;
+  x = x + x;
+  x = x + x;
+  x = x + x;
+  x = x + x;
+  x.replace(re, foo);
+}
=======================================
--- /branches/3.3/src/arm/code-stubs-arm.cc     Fri Jun 24 04:54:25 2011
+++ /branches/3.3/src/arm/code-stubs-arm.cc     Mon Aug  1 11:06:10 2011
@@ -4226,9 +4226,8 @@

   // Check that the irregexp code has been generated for the actual string
// encoding. If it has, the field contains a code object otherwise it contains
-  // the hole.
-  __ CompareObjectType(r7, r0, r0, CODE_TYPE);
-  __ b(ne, &runtime);
+  // a smi (code flushing support).
+  __ JumpIfSmi(r7, &runtime);

   // r3: encoding of subject string (1 if ASCII, 0 if two_byte);
   // r7: code
=======================================
--- /branches/3.3/src/factory.cc        Wed May 25 00:58:50 2011
+++ /branches/3.3/src/factory.cc        Mon Aug  1 11:06:10 2011
@@ -1189,12 +1189,14 @@
                                     JSRegExp::Flags flags,
                                     int capture_count) {
   Handle<FixedArray> store = NewFixedArray(JSRegExp::kIrregexpDataSize);
-
+  Smi* uninitialized = Smi::FromInt(JSRegExp::kUninitializedValue);
   store->set(JSRegExp::kTagIndex, Smi::FromInt(type));
   store->set(JSRegExp::kSourceIndex, *source);
   store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags.value()));
-  store->set(JSRegExp::kIrregexpASCIICodeIndex, HEAP->the_hole_value());
-  store->set(JSRegExp::kIrregexpUC16CodeIndex, HEAP->the_hole_value());
+  store->set(JSRegExp::kIrregexpASCIICodeIndex, uninitialized);
+  store->set(JSRegExp::kIrregexpUC16CodeIndex, uninitialized);
+  store->set(JSRegExp::kIrregexpASCIICodeSavedIndex, uninitialized);
+  store->set(JSRegExp::kIrregexpUC16CodeSavedIndex, uninitialized);
   store->set(JSRegExp::kIrregexpMaxRegisterCountIndex, Smi::FromInt(0));
   store->set(JSRegExp::kIrregexpCaptureCountIndex,
              Smi::FromInt(capture_count));
=======================================
--- /branches/3.3/src/heap.cc   Wed May 25 00:58:50 2011
+++ /branches/3.3/src/heap.cc   Mon Aug  1 11:06:10 2011
@@ -96,6 +96,7 @@
 // Will be 4 * reserved_semispace_size_ to ensure that young
 // generation can be aligned to its size.
       survived_since_last_expansion_(0),
+      sweep_generation_(0),
       always_allocate_scope_depth_(0),
       linear_allocation_scope_depth_(0),
       contexts_disposed_(0),
@@ -736,7 +737,7 @@
   if (collector == MARK_COMPACTOR) {
     // Perform mark-sweep with optional compaction.
     MarkCompact(tracer);
-
+    sweep_generation_++;
     bool high_survival_rate_during_scavenges = IsHighSurvivalRate() &&
         IsStableOrIncreasingSurvivalTrend();

@@ -1292,6 +1293,10 @@
                     &ObjectEvacuationStrategy<POINTER_OBJECT>::
template VisitSpecialized<SharedFunctionInfo::kSize>);

+    table_.Register(kVisitJSRegExp,
+                    &ObjectEvacuationStrategy<POINTER_OBJECT>::
+                    Visit);
+
     table_.Register(kVisitJSFunction,
                     &ObjectEvacuationStrategy<POINTER_OBJECT>::
                         template VisitSpecialized<JSFunction::kSize>);
=======================================
--- /branches/3.3/src/heap.h    Wed May 25 00:58:50 2011
+++ /branches/3.3/src/heap.h    Mon Aug  1 11:06:10 2011
@@ -1227,6 +1227,11 @@
   ExternalStringTable* external_string_table() {
     return &external_string_table_;
   }
+
+  // Returns the current sweep generation.
+  int sweep_generation() {
+    return sweep_generation_;
+  }

   inline Isolate* isolate();
   bool is_safe_to_read_maps() { return is_safe_to_read_maps_; }
@@ -1257,6 +1262,9 @@
   // scavenge since last new space expansion.
   int survived_since_last_expansion_;

+  // For keeping track on when to flush RegExp code.
+  int sweep_generation_;
+
   int always_allocate_scope_depth_;
   int linear_allocation_scope_depth_;

=======================================
--- /branches/3.3/src/ia32/code-stubs-ia32.cc   Mon May 30 07:32:41 2011
+++ /branches/3.3/src/ia32/code-stubs-ia32.cc   Mon Aug  1 11:06:10 2011
@@ -3199,9 +3199,8 @@
   __ bind(&check_code);
   // Check that the irregexp code has been generated for the actual string
// encoding. If it has, the field contains a code object otherwise it contains
-  // the hole.
-  __ CmpObjectType(edx, CODE_TYPE, ebx);
-  __ j(not_equal, &runtime);
+  // a smi (code flushing support).
+  __ JumpIfSmi(edx, &runtime);

   // eax: subject string
   // edx: code
=======================================
--- /branches/3.3/src/jsregexp.cc       Mon Jun 20 06:21:43 2011
+++ /branches/3.3/src/jsregexp.cc       Mon Aug  1 11:06:10 2011
@@ -295,8 +295,33 @@
 #else  // V8_INTERPRETED_REGEXP (RegExp native code)
   if (compiled_code->IsCode()) return true;
 #endif
+  // We could potentially have marked this as flushable, but have kept
+  // a saved version if we did not flush it yet.
+  Object* saved_code = re->DataAt(JSRegExp::saved_code_index(is_ascii));
+  if (saved_code->IsCode()) {
+    // Reinstate the code in the original place.
+    re->SetDataAt(JSRegExp::code_index(is_ascii), saved_code);
+    ASSERT(compiled_code->IsSmi());
+    return true;
+  }
   return CompileIrregexp(re, is_ascii);
 }
+
+
+static bool CreateRegExpErrorObjectAndThrow(Handle<JSRegExp> re,
+                                            bool is_ascii,
+                                            Handle<String> error_message,
+                                            Isolate* isolate) {
+  Factory* factory = isolate->factory();
+  Handle<FixedArray> elements = factory->NewFixedArray(2);
+  elements->set(0, re->Pattern());
+  elements->set(1, *error_message);
+  Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
+  Handle<Object> regexp_err =
+      factory->NewSyntaxError("malformed_regexp", array);
+  isolate->Throw(*regexp_err);
+  return false;
+}


 bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) {
@@ -304,14 +329,28 @@
   Isolate* isolate = re->GetIsolate();
   CompilationZoneScope zone_scope(isolate, DELETE_ON_EXIT);
   PostponeInterruptsScope postpone(isolate);
+  // If we had a compilation error the last time this is saved at the
+  // saved code index.
   Object* entry = re->DataAt(JSRegExp::code_index(is_ascii));
-  if (entry->IsJSObject()) {
- // If it's a JSObject, a previous compilation failed and threw this object.
-    // Re-throw the object without trying again.
-    isolate->Throw(entry);
+  // When arriving here entry can only be a smi, either representing an
+  // uncompiled regexp, a previous compilation error, or code that has
+  // been flushed.
+  ASSERT(entry->IsSmi());
+  int entry_value = Smi::cast(entry)->value();
+  ASSERT(entry_value == JSRegExp::kUninitializedValue ||
+         entry_value == JSRegExp::kCompilationErrorValue ||
+         (entry_value < JSRegExp::kCodeAgeMask && entry_value >= 0));
+
+  if (entry_value == JSRegExp::kCompilationErrorValue) {
+    // A previous compilation failed and threw an error which we store in
+    // the saved code index (we store the error message, not the actual
+    // error). Recreate the error object and throw it.
+ Object* error_string = re->DataAt(JSRegExp::saved_code_index(is_ascii));
+    ASSERT(error_string->IsString());
+    Handle<String> error_message(String::cast(error_string));
+    CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate);
     return false;
   }
-  ASSERT(entry->IsTheHole());

   JSRegExp::Flags flags = re->GetFlags();

@@ -340,17 +379,9 @@
                             is_ascii);
   if (result.error_message != NULL) {
     // Unable to compile regexp.
-    Factory* factory = isolate->factory();
-    Handle<FixedArray> elements = factory->NewFixedArray(2);
-    elements->set(0, *pattern);
     Handle<String> error_message =
-        factory->NewStringFromUtf8(CStrVector(result.error_message));
-    elements->set(1, *error_message);
-    Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
-    Handle<Object> regexp_err =
-        factory->NewSyntaxError("malformed_regexp", array);
-    isolate->Throw(*regexp_err);
-    re->SetDataAt(JSRegExp::code_index(is_ascii), *regexp_err);
+ isolate->factory()->NewStringFromUtf8(CStrVector(result.error_message));
+    CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate);
     return false;
   }

@@ -460,6 +491,7 @@
   ASSERT(output.length() >= (IrregexpNumberOfCaptures(*irregexp) + 1) * 2);
   do {
     bool is_ascii = subject->IsAsciiRepresentation();
+    EnsureCompiledIrregexp(regexp, is_ascii);
     Handle<Code> code(IrregexpNativeCode(*irregexp, is_ascii), isolate);
     NativeRegExpMacroAssembler::Result res =
         NativeRegExpMacroAssembler::Match(code,
=======================================
--- /branches/3.3/src/mark-compact.cc   Wed May 25 00:58:50 2011
+++ /branches/3.3/src/mark-compact.cc   Mon Aug  1 11:06:10 2011
@@ -422,6 +422,9 @@
     table_.Register(kVisitJSFunction,
                     &VisitJSFunctionAndFlushCode);

+    table_.Register(kVisitJSRegExp,
+                    &VisitRegExpAndFlushCode);
+
     table_.Register(kVisitPropertyCell,
                     &FixedBodyVisitor<StaticMarkingVisitor,
                                       JSGlobalPropertyCell::BodyDescriptor,
@@ -562,6 +565,8 @@
   // flushed.
   static const int kCodeAgeThreshold = 5;

+  static const int kRegExpCodeThreshold = 5;
+
   inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) {
     Object* undefined = heap->raw_unchecked_undefined_value();
     return (info->script() != undefined) &&
@@ -695,6 +700,68 @@
                      SharedFunctionInfo::BodyDescriptor,
                      void>::Visit(map, object);
   }
+
+
+  static void UpdateRegExpCodeAgeAndFlush(Heap* heap,
+                                          JSRegExp* re,
+                                          bool is_ascii) {
+    // Make sure that the fixed array is in fact initialized on the RegExp.
+    // We could potentially trigger a GC when initializing the RegExp.
+    if (SafeMap(re->data())->instance_type() != FIXED_ARRAY_TYPE) return;
+
+    // Make sure this is a RegExp that actually contains code.
+    if (re->TypeTagUnchecked() != JSRegExp::IRREGEXP) return;
+
+    Object* code = re->DataAtUnchecked(JSRegExp::code_index(is_ascii));
+    if (!code->IsSmi() && SafeMap(code)->instance_type() == CODE_TYPE) {
+      // Save a copy that can be reinstated if we need the code again.
+      re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii),
+                             code,
+                             heap);
+      // Set a number in the 0-255 range to guarantee no smi overflow.
+      re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii),
+                             Smi::FromInt(heap->sweep_generation() & 0xff),
+                             heap);
+    } else if (code->IsSmi()) {
+      int value = Smi::cast(code)->value();
+ // The regexp has not been compiled yet or there was a compilation error.
+      if (value == JSRegExp::kUninitializedValue ||
+          value == JSRegExp::kCompilationErrorValue) {
+        return;
+      }
+
+      // Check if we should flush now.
+ if (value == ((heap->sweep_generation() - kRegExpCodeThreshold) & 0xff)) {
+        re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii),
+                               Smi::FromInt(JSRegExp::kUninitializedValue),
+                               heap);
+        re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii),
+                               Smi::FromInt(JSRegExp::kUninitializedValue),
+                               heap);
+      }
+    }
+  }
+
+
+  // Works by setting the current sweep_generation (as a smi) in the
+  // code object place in the data array of the RegExp and keeps a copy
+  // around that can be reinstated if we reuse the RegExp before flushing.
+  // If we did not use the code for kRegExpCodeThreshold mark sweep GCs
+  // we flush the code.
+  static void VisitRegExpAndFlushCode(Map* map, HeapObject* object) {
+    Heap* heap = map->heap();
+    MarkCompactCollector* collector = heap->mark_compact_collector();
+    if (!collector->is_code_flushing_enabled()) {
+      VisitJSRegExpFields(map, object);
+      return;
+    }
+    JSRegExp* re = reinterpret_cast<JSRegExp*>(object);
+    // Flush code or set age on both ascii and two byte code.
+    UpdateRegExpCodeAgeAndFlush(heap, re, true);
+    UpdateRegExpCodeAgeAndFlush(heap, re, false);
+    // Visit the fields of the RegExp, including the updated FixedArray.
+    VisitJSRegExpFields(map, object);
+  }


   static void VisitSharedFunctionInfoAndFlushCode(Map* map,
@@ -826,6 +893,15 @@

     // Don't visit the next function list field as it is a weak reference.
   }
+
+  static inline void VisitJSRegExpFields(Map* map,
+                                         HeapObject* object) {
+    int last_property_offset =
+        JSRegExp::kSize + kPointerSize * map->inobject_properties();
+    VisitPointers(map->heap(),
+                  SLOT_ADDR(object, JSRegExp::kPropertiesOffset),
+                  SLOT_ADDR(object, last_property_offset));
+  }


   static void VisitSharedFunctionInfoFields(Heap* heap,
=======================================
--- /branches/3.3/src/objects-debug.cc  Wed May 25 00:58:50 2011
+++ /branches/3.3/src/objects-debug.cc  Mon Aug  1 11:06:10 2011
@@ -444,14 +444,22 @@

       FixedArray* arr = FixedArray::cast(data());
       Object* ascii_data = arr->get(JSRegExp::kIrregexpASCIICodeIndex);
-      // TheHole : Not compiled yet.
+      // Smi : Not compiled yet (-1) or code prepared for flushing.
       // JSObject: Compilation error.
       // Code/ByteArray: Compiled code.
-      ASSERT(ascii_data->IsTheHole() || ascii_data->IsJSObject() ||
-          (is_native ? ascii_data->IsCode() : ascii_data->IsByteArray()));
+      ASSERT(ascii_data->IsSmi() ||
+ (is_native ? ascii_data->IsCode() : ascii_data->IsByteArray()));
       Object* uc16_data = arr->get(JSRegExp::kIrregexpUC16CodeIndex);
-      ASSERT(uc16_data->IsTheHole() || uc16_data->IsJSObject() ||
-          (is_native ? uc16_data->IsCode() : uc16_data->IsByteArray()));
+      ASSERT(uc16_data->IsSmi() ||
+             (is_native ? uc16_data->IsCode() : uc16_data->IsByteArray()));
+
+ Object* ascii_saved = arr->get(JSRegExp::kIrregexpASCIICodeSavedIndex);
+      ASSERT(ascii_saved->IsSmi() || ascii_saved->IsString() ||
+             ascii_saved->IsCode());
+      Object* uc16_saved = arr->get(JSRegExp::kIrregexpUC16CodeSavedIndex);
+      ASSERT(uc16_saved->IsSmi() || uc16_saved->IsString() ||
+             uc16_saved->IsCode());
+
       ASSERT(arr->get(JSRegExp::kIrregexpCaptureCountIndex)->IsSmi());
       ASSERT(arr->get(JSRegExp::kIrregexpMaxRegisterCountIndex)->IsSmi());
       break;
=======================================
--- /branches/3.3/src/objects-inl.h     Wed May 25 00:58:50 2011
+++ /branches/3.3/src/objects-inl.h     Mon Aug  1 11:06:10 2011
@@ -3717,6 +3717,12 @@
   Smi* smi = Smi::cast(FixedArray::cast(data)->get(kTagIndex));
   return static_cast<JSRegExp::Type>(smi->value());
 }
+
+
+JSRegExp::Type JSRegExp::TypeTagUnchecked() {
+  Smi* smi = Smi::cast(DataAtUnchecked(kTagIndex));
+  return static_cast<JSRegExp::Type>(smi->value());
+}


 int JSRegExp::CaptureCount() {
@@ -3752,6 +3758,13 @@
   ASSERT(TypeTag() != NOT_COMPILED);
   return FixedArray::cast(data())->get(index);
 }
+
+
+Object* JSRegExp::DataAtUnchecked(int index) {
+  FixedArray* fa = reinterpret_cast<FixedArray*>(data());
+  int offset = FixedArray::kHeaderSize + index * kPointerSize;
+  return READ_FIELD(fa, offset);
+}


 void JSRegExp::SetDataAt(int index, Object* value) {
@@ -3759,6 +3772,17 @@
ASSERT(index >= kDataIndex); // Only implementation data can be set this way.
   FixedArray::cast(data())->set(index, value);
 }
+
+
+void JSRegExp::SetDataAtUnchecked(int index, Object* value, Heap* heap) {
+ ASSERT(index >= kDataIndex); // Only implementation data can be set this way.
+  FixedArray* fa = reinterpret_cast<FixedArray*>(data());
+  if (value->IsSmi()) {
+    fa->set_unchecked(index, Smi::cast(value));
+  } else {
+    fa->set_unchecked(heap, index, value, SKIP_WRITE_BARRIER);
+  }
+}


 JSObject::ElementsKind JSObject::GetElementsKind() {
=======================================
--- /branches/3.3/src/objects-visiting.cc       Wed May 25 00:58:50 2011
+++ /branches/3.3/src/objects-visiting.cc       Mon Aug  1 11:06:10 2011
@@ -85,6 +85,9 @@
     case JS_GLOBAL_PROPERTY_CELL_TYPE:
       return kVisitPropertyCell;

+    case JS_REGEXP_TYPE:
+      return kVisitJSRegExp;
+
     case SHARED_FUNCTION_INFO_TYPE:
       return kVisitSharedFunctionInfo;

@@ -105,7 +108,6 @@
     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
     case JS_VALUE_TYPE:
     case JS_ARRAY_TYPE:
-    case JS_REGEXP_TYPE:
     case JS_GLOBAL_PROXY_TYPE:
     case JS_GLOBAL_OBJECT_TYPE:
     case JS_BUILTINS_OBJECT_TYPE:
=======================================
--- /branches/3.3/src/objects-visiting.h        Mon May  9 02:42:16 2011
+++ /branches/3.3/src/objects-visiting.h        Mon Aug  1 11:06:10 2011
@@ -104,6 +104,7 @@
     kVisitPropertyCell,
     kVisitSharedFunctionInfo,
     kVisitJSFunction,
+    kVisitJSRegExp,

     kVisitorIdCount,
     kMinObjectSizeInWords = 2
@@ -297,6 +298,8 @@
                                       SharedFunctionInfo::BodyDescriptor,
                                       int>::Visit);

+    table_.Register(kVisitJSRegExp, &VisitJSRegExp);
+
     table_.Register(kVisitSeqAsciiString, &VisitSeqAsciiString);

     table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString);
@@ -333,6 +336,10 @@
     return SeqAsciiString::cast(object)->
         SeqAsciiStringSize(map->instance_type());
   }
+
+  static inline int VisitJSRegExp(Map* map, HeapObject* object) {
+    return JSObjectVisitor::Visit(map, object);
+  }

   static inline int VisitSeqTwoByteString(Map* map, HeapObject* object) {
     return SeqTwoByteString::cast(object)->
=======================================
--- /branches/3.3/src/objects.h Wed May 25 00:58:50 2011
+++ /branches/3.3/src/objects.h Mon Aug  1 11:06:10 2011
@@ -5053,8 +5053,10 @@
 // If it is an atom regexp
 // - a reference to a literal string to search for
 // If it is an irregexp regexp:
-// - a reference to code for ASCII inputs (bytecode or compiled).
-// - a reference to code for UC16 inputs (bytecode or compiled).
+// - a reference to code for ASCII inputs (bytecode or compiled), or a smi
+// used for tracking the last usage (used for code flushing).
+// - a reference to code for UC16 inputs (bytecode or compiled), or a smi
+// used for tracking the last usage (used for code flushing)..
 // - max number of registers used by irregexp implementations.
 // - number of capture registers (output values) of the regexp.
 class JSRegExp: public JSObject {
@@ -5087,6 +5089,12 @@
   inline Object* DataAt(int index);
   // Set implementation data after the object has been prepared.
   inline void SetDataAt(int index, Object* value);
+
+  // Used during GC when flushing code or setting age.
+  inline Object* DataAtUnchecked(int index);
+  inline void SetDataAtUnchecked(int index, Object* value, Heap* heap);
+  inline Type TypeTagUnchecked();
+
   static int code_index(bool is_ascii) {
     if (is_ascii) {
       return kIrregexpASCIICodeIndex;
@@ -5094,6 +5102,14 @@
       return kIrregexpUC16CodeIndex;
     }
   }
+
+  static int saved_code_index(bool is_ascii) {
+    if (is_ascii) {
+      return kIrregexpASCIICodeSavedIndex;
+    } else {
+      return kIrregexpUC16CodeSavedIndex;
+    }
+  }

   static inline JSRegExp* cast(Object* obj);

@@ -5125,11 +5141,19 @@
   // fails, this fields hold an exception object that should be
   // thrown if the regexp is used again.
   static const int kIrregexpUC16CodeIndex = kDataIndex + 1;
+
+  // Saved instance of Irregexp compiled code or bytecode for ASCII that
+  // is a potential candidate for flushing.
+  static const int kIrregexpASCIICodeSavedIndex = kDataIndex + 2;
+  // Saved instance of Irregexp compiled code or bytecode for UC16 that is
+  // a potential candidate for flushing.
+  static const int kIrregexpUC16CodeSavedIndex = kDataIndex + 3;
+
   // Maximal number of registers used by either ASCII or UC16.
   // Only used to check that there is enough stack space
-  static const int kIrregexpMaxRegisterCountIndex = kDataIndex + 2;
+  static const int kIrregexpMaxRegisterCountIndex = kDataIndex + 4;
   // Number of captures in the compiled regexp.
-  static const int kIrregexpCaptureCountIndex = kDataIndex + 3;
+  static const int kIrregexpCaptureCountIndex = kDataIndex + 5;

   static const int kIrregexpDataSize = kIrregexpCaptureCountIndex + 1;

@@ -5150,6 +5174,18 @@
   static const int kMultilineFieldIndex = 3;
   static const int kLastIndexFieldIndex = 4;
   static const int kInObjectFieldCount = 5;
+
+  // The uninitialized value for a regexp code object.
+  static const int kUninitializedValue = -1;
+
+  // The compilation error value for the regexp code object. The real error
+  // object is in the saved code field.
+  static const int kCompilationErrorValue = -2;
+
+  // When we store the sweep generation at which we moved the code from the
+  // code index to the saved code index we mask it of to be in the [0:255]
+  // range.
+  static const int kCodeAgeMask = 0xff;
 };


=======================================
--- /branches/3.3/src/regexp.js Sun May 22 23:06:11 2011
+++ /branches/3.3/src/regexp.js Mon Aug  1 11:06:10 2011
@@ -235,7 +235,7 @@
   // Conversion is required by the ES5 specification (RegExp.prototype.exec
// algorithm, step 5) even if the value is discarded for non-global RegExps.
   var i = TO_INTEGER(lastIndex);
-
+
   if (this.global) {
     if (i < 0 || i > string.length) {
       this.lastIndex = 0;
@@ -250,11 +250,11 @@
     }
     lastMatchInfoOverride = null;
     this.lastIndex = lastMatchInfo[CAPTURE1];
-    return true;
+    return true;
   } else {
     // Non-global regexp.
-    // Remove irrelevant preceeding '.*' in a non-global test regexp.
-    // The expression checks whether this.source starts with '.*' and
+    // Remove irrelevant preceeding '.*' in a non-global test regexp.
+    // The expression checks whether this.source starts with '.*' and
     // that the third char is not a '?'.
     if (%_StringCharCodeAt(this.source, 0) == 46 &&  // '.'
         %_StringCharCodeAt(this.source, 1) == 42 &&  // '*'
@@ -262,14 +262,14 @@
       if (!%_ObjectEquals(regexp_key, this)) {
         regexp_key = this;
regexp_val = new $RegExp(SubString(this.source, 2, this.source.length),
-                                 (!this.ignoreCase
+                                 (!this.ignoreCase
                                   ? !this.multiline ? "" : "m"
                                   : !this.multiline ? "i" : "im"));
       }
       if (%_RegExpExec(regexp_val, string, 0, lastMatchInfo) === null) {
         return false;
       }
-    }
+    }
     %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
     // matchIndices is either null or the lastMatchInfo array.
     var matchIndices = %_RegExpExec(this, string, 0, lastMatchInfo);
=======================================
--- /branches/3.3/src/string.js Mon May  9 02:42:16 2011
+++ /branches/3.3/src/string.js Mon Aug  1 11:06:10 2011
@@ -274,7 +274,7 @@
 // the result.
 function ExpandReplacement(string, subject, matchInfo, builder) {
   var length = string.length;
-  var builder_elements = builder.elements;
+  var builder_elements = builder.elements;
   var next = %StringIndexOf(string, '$', 0);
   if (next < 0) {
     if (length > 0) builder_elements.push(string);
=======================================
--- /branches/3.3/src/version.cc        Thu Jul 21 05:28:18 2011
+++ /branches/3.3/src/version.cc        Mon Aug  1 11:06:10 2011
@@ -35,7 +35,7 @@
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     3
 #define BUILD_NUMBER      10
-#define PATCH_LEVEL       22
+#define PATCH_LEVEL       23
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
 #define IS_CANDIDATE_VERSION 0
=======================================
--- /branches/3.3/src/x64/code-stubs-x64.cc     Mon May 30 07:32:41 2011
+++ /branches/3.3/src/x64/code-stubs-x64.cc     Mon Aug  1 11:06:10 2011
@@ -2239,9 +2239,8 @@
   __ bind(&check_code);
   // Check that the irregexp code has been generated for the actual string
// encoding. If it has, the field contains a code object otherwise it contains
-  // the hole.
-  __ CmpObjectType(r11, CODE_TYPE, kScratchRegister);
-  __ j(not_equal, &runtime);
+  // smi (code flushing support)
+  __ JumpIfSmi(r11, &runtime);

   // rdi: subject string
   // rcx: encoding of subject string (1 if ascii, 0 if two_byte);

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

Reply via email to