From: dcarney@chromium.org Date: Mon, 10 Jun 2013 07:34:58 +0000 (+0000) Subject: do aligned reads in ContainsOnlyOneByte X-Git-Tag: upstream/4.7.83~13944 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8c892ea2a8749c79bc6a16cb0472b2182e521961;p=platform%2Fupstream%2Fv8.git do aligned reads in ContainsOnlyOneByte 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 --- diff --git a/src/api.cc b/src/api.cc index ed1e265..3c1a003 100644 --- a/src/api.cc +++ b/src/api.cc @@ -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(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(0xFF00FF00FF00FF00ULL); + static const uintptr_t kAlignmentMask = sizeof(uintptr_t) - 1; + static inline bool Unaligned(const uint16_t* chars) { + return reinterpret_cast(chars) & kAlignmentMask; + } + static inline const uint16_t* Align(const uint16_t* chars) { + return reinterpret_cast( + reinterpret_cast(chars) & ~kAlignmentMask); + } bool CheckCons(i::ConsString* cons_string) { while (true) { // Check left side if flat. diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index a59dd16..10f8af1 100755 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -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 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 + aligned_contents(new uintptr_t[aligned_length]); + uint16_t* string_contents = reinterpret_cast(*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::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 base = String::NewFromUtf8(isolate, "a"); @@ -17059,7 +17063,7 @@ TEST(ContainsOnlyOneByte) { balanced = String::Concat(balanced, right); Handle cons_strings[] = {left, balanced, right}; Handle 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; + } + } }