Revision: 4298
Author: [email protected]
Date: Fri Mar 26 07:19:47 2010
Log: Pre-create properties on JSRegExp objects
Initialize properties in single runtime call.

Review URL: http://codereview.chromium.org/1350003
http://code.google.com/p/v8/source/detail?r=4298

Modified:
 /branches/bleeding_edge/src/bootstrapper.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/regexp.js
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/runtime.h
 /branches/bleeding_edge/test/mjsunit/mirror-regexp.js
 /branches/bleeding_edge/test/mjsunit/regexp.js

=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Wed Mar 24 06:24:46 2010
+++ /branches/bleeding_edge/src/bootstrapper.cc Fri Mar 26 07:19:47 2010
@@ -723,8 +723,68 @@
         InstallFunction(global, "RegExp", JS_REGEXP_TYPE, JSRegExp::kSize,
                         Top::initial_object_prototype(), Builtins::Illegal,
                         true);
-
     global_context()->set_regexp_function(*regexp_fun);
+
+    ASSERT(regexp_fun->has_initial_map());
+    Handle<Map> initial_map(regexp_fun->initial_map());
+
+    ASSERT_EQ(0, initial_map->inobject_properties());
+
+    Handle<DescriptorArray> descriptors = Factory::NewDescriptorArray(5);
+    PropertyAttributes final =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+    int enum_index = 0;
+    {
+      // ECMA-262, section 15.10.7.1.
+      FieldDescriptor field(Heap::source_symbol(),
+                            JSRegExp::kSourceFieldIndex,
+                            final,
+                            enum_index++);
+      descriptors->Set(0, &field);
+    }
+    {
+      // ECMA-262, section 15.10.7.2.
+      FieldDescriptor field(Heap::global_symbol(),
+                            JSRegExp::kGlobalFieldIndex,
+                            final,
+                            enum_index++);
+      descriptors->Set(1, &field);
+    }
+    {
+      // ECMA-262, section 15.10.7.3.
+      FieldDescriptor field(Heap::ignore_case_symbol(),
+                            JSRegExp::kIgnoreCaseFieldIndex,
+                            final,
+                            enum_index++);
+      descriptors->Set(2, &field);
+    }
+    {
+      // ECMA-262, section 15.10.7.4.
+      FieldDescriptor field(Heap::multiline_symbol(),
+                            JSRegExp::kMultilineFieldIndex,
+                            final,
+                            enum_index++);
+      descriptors->Set(3, &field);
+    }
+    {
+      // ECMA-262, section 15.10.7.5.
+      PropertyAttributes writable =
+          static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
+      FieldDescriptor field(Heap::last_index_symbol(),
+                            JSRegExp::kLastIndexFieldIndex,
+                            writable,
+                            enum_index++);
+      descriptors->Set(4, &field);
+    }
+    descriptors->SetNextEnumerationIndex(enum_index);
+    descriptors->Sort();
+
+    initial_map->set_inobject_properties(5);
+    initial_map->set_pre_allocated_property_fields(5);
+    initial_map->set_unused_property_fields(0);
+    initial_map->set_instance_size(
+        initial_map->instance_size() + 5 * kPointerSize);
+    initial_map->set_instance_descriptors(*descriptors);
   }

   {  // -- J S O N
=======================================
--- /branches/bleeding_edge/src/heap.h  Thu Mar 25 08:32:58 2010
+++ /branches/bleeding_edge/src/heap.h  Fri Mar 26 07:19:47 2010
@@ -149,6 +149,11 @@
   V(number_symbol, "number")                                             \
   V(Number_symbol, "Number")                                             \
   V(RegExp_symbol, "RegExp")                                             \
+  V(source_symbol, "source")                                             \
+  V(global_symbol, "global")                                             \
+  V(ignore_case_symbol, "ignoreCase")                                    \
+  V(multiline_symbol, "multiline")                                       \
+  V(last_index_symbol, "lastIndex")                                      \
   V(object_symbol, "object")                                             \
   V(prototype_symbol, "prototype")                                       \
   V(string_symbol, "string")                                             \
=======================================
--- /branches/bleeding_edge/src/objects.h       Tue Mar 23 04:40:38 2010
+++ /branches/bleeding_edge/src/objects.h       Fri Mar 26 07:19:47 2010
@@ -3667,6 +3667,13 @@
       FixedArray::kHeaderSize + kIrregexpUC16CodeIndex * kPointerSize;
   static const int kIrregexpCaptureCountOffset =
       FixedArray::kHeaderSize + kIrregexpCaptureCountIndex * kPointerSize;
+
+  // In-object fields.
+  static const int kSourceFieldIndex = 0;
+  static const int kGlobalFieldIndex = 1;
+  static const int kIgnoreCaseFieldIndex = 2;
+  static const int kMultilineFieldIndex = 3;
+  static const int kLastIndexFieldIndex = 4;
 };


=======================================
--- /branches/bleeding_edge/src/regexp.js       Thu Mar 25 05:57:58 2010
+++ /branches/bleeding_edge/src/regexp.js       Fri Mar 26 07:19:47 2010
@@ -71,32 +71,10 @@
     }
   }

-  if (isConstructorCall) {
-    // ECMA-262, section 15.10.7.1.
-    %SetProperty(object, 'source', pattern,
-                 DONT_DELETE |  READ_ONLY | DONT_ENUM);
-
-    // ECMA-262, section 15.10.7.2.
- %SetProperty(object, 'global', global, DONT_DELETE | READ_ONLY | DONT_ENUM);
-
-    // ECMA-262, section 15.10.7.3.
-    %SetProperty(object, 'ignoreCase', ignoreCase,
-                 DONT_DELETE | READ_ONLY | DONT_ENUM);
-
-    // ECMA-262, section 15.10.7.4.
-    %SetProperty(object, 'multiline', multiline,
-                 DONT_DELETE | READ_ONLY | DONT_ENUM);
-
-    // ECMA-262, section 15.10.7.5.
-    %SetProperty(object, 'lastIndex', 0, DONT_DELETE | DONT_ENUM);
-  } else { // RegExp is being recompiled via RegExp.prototype.compile.
-    %IgnoreAttributesAndSetProperty(object, 'source', pattern);
-    %IgnoreAttributesAndSetProperty(object, 'global', global);
-    %IgnoreAttributesAndSetProperty(object, 'ignoreCase', ignoreCase);
-    %IgnoreAttributesAndSetProperty(object, 'multiline', multiline);
-    %IgnoreAttributesAndSetProperty(object, 'lastIndex', 0);
+  if (!isConstructorCall) {
     regExpCache.type = 'none';
   }
+  %RegExpInitializeObject(object, pattern, global, ignoreCase, multiline);

   // Call internal function to compile the pattern.
   %RegExpCompile(object, pattern, flags);
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Thu Mar 25 05:57:58 2010
+++ /branches/bleeding_edge/src/runtime.cc      Fri Mar 26 07:19:47 2010
@@ -1226,6 +1226,62 @@
   if (result.is_null()) return Failure::Exception();
   return *result;
 }
+
+
+static Object* Runtime_RegExpInitializeObject(Arguments args) {
+  AssertNoAllocation no_alloc;
+  ASSERT(args.length() == 5);
+  CONVERT_CHECKED(JSRegExp, regexp, args[0]);
+  CONVERT_CHECKED(String, source, args[1]);
+
+  Object* global = args[2];
+  if (!global->IsTrue()) global = Heap::false_value();
+
+  Object* ignoreCase = args[3];
+  if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
+
+  Object* multiline = args[4];
+  if (!multiline->IsTrue()) multiline = Heap::false_value();
+
+  Map* map = regexp->map();
+  Object* constructor = map->constructor();
+  if (constructor->IsJSFunction() &&
+      JSFunction::cast(constructor)->initial_map() == map) {
+ // If we still have the original map, set in-object properties directly.
+    regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
+    // TODO(lrn): Consider skipping write barrier on booleans as well.
+    // Both true and false should be in oldspace at all times.
+    regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
+ regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase); + regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
+    regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
+                                  Smi::FromInt(0),
+                                  SKIP_WRITE_BARRIER);
+    return regexp;
+  }
+
+  // Map has changed, so use generic, but slower, method.
+  PropertyAttributes final =
+      static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
+  PropertyAttributes writable =
+      static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
+  regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
+                                              source,
+                                              final);
+  regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
+                                              global,
+                                              final);
+  regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
+                                              ignoreCase,
+                                              final);
+  regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
+                                              multiline,
+                                              final);
+  regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
+                                              Smi::FromInt(0),
+                                              writable);
+  return regexp;
+}


 static Object* Runtime_FinishArrayPrototypeSetup(Arguments args) {
=======================================
--- /branches/bleeding_edge/src/runtime.h       Thu Mar 25 05:57:58 2010
+++ /branches/bleeding_edge/src/runtime.h       Fri Mar 26 07:19:47 2010
@@ -154,6 +154,7 @@
   F(RegExpCompile, 3, 1) \
   F(RegExpExec, 4, 1) \
   F(RegExpExecMultiple, 4, 1) \
+  F(RegExpInitializeObject, 5, 1) \
   \
   /* Strings */ \
   F(StringCharCodeAt, 2, 1) \
=======================================
--- /branches/bleeding_edge/test/mjsunit/mirror-regexp.js Fri May 15 00:35:11 2009 +++ /branches/bleeding_edge/test/mjsunit/mirror-regexp.js Fri Mar 26 07:19:47 2010
@@ -70,8 +70,8 @@
   assertEquals('regexp', mirror.type());
   assertFalse(mirror.isPrimitive());
   for (var p in expected_attributes) {
-    assertEquals(mirror.property(p).attributes(),
-                 expected_attributes[p],
+    assertEquals(expected_attributes[p],
+                 mirror.property(p).attributes(),
                  p + ' attributes');
   }

=======================================
--- /branches/bleeding_edge/test/mjsunit/regexp.js      Wed May 27 04:23:26 2009
+++ /branches/bleeding_edge/test/mjsunit/regexp.js      Fri Mar 26 07:19:47 2010
@@ -388,3 +388,51 @@
   assertTrue(String(e).indexOf("Stack overflow") >= 0, "overflow");
 }

+
+// Test that compile works on modified objects
+var re = /re+/;
+assertEquals("re+", re.source);
+assertFalse(re.global);
+assertFalse(re.ignoreCase);
+assertFalse(re.multiline);
+assertEquals(0, re.lastIndex);
+
+re.compile("ro+", "gim");
+assertEquals("ro+", re.source);
+assertTrue(re.global);
+assertTrue(re.ignoreCase);
+assertTrue(re.multiline);
+assertEquals(0, re.lastIndex);
+
+re.lastIndex = 42;
+re.someOtherProperty = 42;
+re.someDeletableProperty = 42;
+re[37] = 37;
+re[42] = 42;
+
+re.compile("ra+", "i");
+assertEquals("ra+", re.source);
+assertFalse(re.global);
+assertTrue(re.ignoreCase);
+assertFalse(re.multiline);
+assertEquals(0, re.lastIndex);
+
+assertEquals(42, re.someOtherProperty);
+assertEquals(42, re.someDeletableProperty);
+assertEquals(37, re[37]);
+assertEquals(42, re[42]);
+
+re.lastIndex = -1;
+re.someOtherProperty = 37;
+re[42] = 37;
+assertTrue(delete re[37]);
+assertTrue(delete re.someDeletableProperty);
+re.compile("ri+", "gm");
+
+assertEquals("ri+", re.source);
+assertTrue(re.global);
+assertFalse(re.ignoreCase);
+assertTrue(re.multiline);
+assertEquals(0, re.lastIndex);
+assertEquals(37, re.someOtherProperty);
+assertEquals(37, re[42]);

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

To unsubscribe from this group, send email to v8-dev+unsubscribegooglegroups.com or reply 
to this email with the words "REMOVE ME" as the subject.

Reply via email to