do aligned reads in ContainsOnlyOneByte
authordcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 10 Jun 2013 07:34:58 +0000 (07:34 +0000)
committerdcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 10 Jun 2013 07:34:58 +0000 (07:34 +0000)
R=yangguo@chromium.org
BUG=

Review URL: https://codereview.chromium.org/16147004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15023 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/api.cc
test/cctest/test-api.cc

index ed1e265..3c1a003 100644 (file)
@@ -4315,17 +4315,49 @@ class ContainsOnlyOneByteHelper {
   void VisitOneByteString(const uint8_t* chars, int length) {
     // Nothing to do.
   }
-  // TODO(dcarney): do word aligned read.
   void VisitTwoByteString(const uint16_t* chars, int length) {
-    // Check whole string without breaking.
-    uint16_t total = 0;
-    for (int i = 0; i < length; i++) {
-      total |= chars[i] >> 8;
+    // Accumulated bits.
+    uintptr_t acc = 0;
+    // Align to uintptr_t.
+    const uint16_t* end = chars + length;
+    while (Unaligned(chars) && chars != end) {
+        acc |= *chars++;
     }
-    if (total != 0) is_one_byte_ = false;
+    // Read word aligned in blocks,
+    // checking the return value at the end of each block.
+    const uint16_t* aligned_end = Align(end);
+    const int increment = sizeof(uintptr_t)/sizeof(uint16_t);
+    const int inner_loops = 16;
+    while (chars + inner_loops*increment < aligned_end) {
+      for (int i = 0; i < inner_loops; i++) {
+        acc |= *reinterpret_cast<const uintptr_t*>(chars);
+        chars += increment;
+      }
+      // Check for early return.
+      if ((acc & kOneByteMask) != 0) {
+        is_one_byte_ = false;
+        return;
+      }
+    }
+    // Read the rest.
+    while (chars != end) {
+      acc |= *chars++;
+    }
+    // Check result.
+    if ((acc & kOneByteMask) != 0) is_one_byte_ = false;
   }
 
  private:
+  static const uintptr_t kOneByteMask =
+      static_cast<uintptr_t>(0xFF00FF00FF00FF00ULL);
+  static const uintptr_t kAlignmentMask = sizeof(uintptr_t) - 1;
+  static inline bool Unaligned(const uint16_t* chars) {
+    return reinterpret_cast<const uintptr_t>(chars) & kAlignmentMask;
+  }
+  static inline const uint16_t* Align(const uint16_t* chars) {
+    return reinterpret_cast<uint16_t*>(
+        reinterpret_cast<uintptr_t>(chars) & ~kAlignmentMask);
+  }
   bool CheckCons(i::ConsString* cons_string) {
     while (true) {
       // Check left side if flat.
index a59dd16..10f8af1 100755 (executable)
@@ -17033,8 +17033,12 @@ TEST(ContainsOnlyOneByte) {
   v8::Isolate* isolate = v8::Isolate::GetCurrent();
   v8::HandleScope scope(isolate);
   // Make a buffer long enough that it won't automatically be converted.
-  const int length = 200;
-  i::SmartArrayPointer<uint16_t> string_contents(new uint16_t[length]);
+  const int length = 512;
+  // Ensure word aligned assignment.
+  const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
+  i::SmartArrayPointer<uintptr_t>
+  aligned_contents(new uintptr_t[aligned_length]);
+  uint16_t* string_contents = reinterpret_cast<uint16_t*>(*aligned_contents);
   // Set to contain only one byte.
   for (int i = 0; i < length-1; i++) {
     string_contents[i] = 0x41;
@@ -17042,10 +17046,10 @@ TEST(ContainsOnlyOneByte) {
   string_contents[length-1] = 0;
   // Simple case.
   Handle<String> string;
-  string = String::NewExternal(new TestResource(*string_contents));
+  string = String::NewExternal(new TestResource(string_contents));
   CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
   // Counter example.
-  string = String::NewFromTwoByte(isolate, *string_contents);
+  string = String::NewFromTwoByte(isolate, string_contents);
   CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
   // Test left right and balanced cons strings.
   Handle<String> base = String::NewFromUtf8(isolate, "a");
@@ -17059,7 +17063,7 @@ TEST(ContainsOnlyOneByte) {
   balanced = String::Concat(balanced, right);
   Handle<String> cons_strings[] = {left, balanced, right};
   Handle<String> two_byte =
-      String::NewExternal(new TestResource(*string_contents));
+      String::NewExternal(new TestResource(string_contents));
   for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
     // Base assumptions.
     string = cons_strings[i];
@@ -17070,6 +17074,24 @@ TEST(ContainsOnlyOneByte) {
     string = String::Concat(cons_strings[i], two_byte);
     CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
   }
+  // Set bits in different positions
+  // for strings of different lengths and alignments.
+  for (int alignment = 0; alignment < 7; alignment++) {
+    for (int size = 2; alignment + size < length; size *= 2) {
+      int zero_offset = size + alignment;
+      string_contents[zero_offset] = 0;
+      for (int i = 0; i < size; i++) {
+        int shift = 8 + (i % 7);
+        string_contents[alignment + i] = 1 << shift;
+        string =
+            String::NewExternal(new TestResource(string_contents + alignment));
+        CHECK_EQ(size, string->Length());
+        CHECK(!string->ContainsOnlyOneByte());
+        string_contents[alignment + i] = 0x41;
+      }
+      string_contents[zero_offset] = 0x41;
+    }
+  }
 }