add function to test whether string contents are definitely one byte
R=yangguo@chromium.org BUG= Review URL: https://codereview.chromium.org/16530003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14976 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
98b97d9edb
commit
6f5d899248
10
include/v8.h
10
include/v8.h
@ -1524,10 +1524,18 @@ class V8EXPORT String : public Primitive {
|
||||
V8_DEPRECATED(V8_INLINE(bool MayContainNonAscii()) const) { return true; }
|
||||
|
||||
/**
|
||||
* Returns whether this string contains only one byte data.
|
||||
* Returns whether this string is known to contain only one byte data.
|
||||
* Does not read the string.
|
||||
* False negatives are possible.
|
||||
*/
|
||||
bool IsOneByte() const;
|
||||
|
||||
/**
|
||||
* Returns whether this string contain only one byte data.
|
||||
* Will read the entire string in some cases.
|
||||
*/
|
||||
bool ContainsOnlyOneByte() const;
|
||||
|
||||
/**
|
||||
* Write the contents of the string to an external buffer.
|
||||
* If no arguments are given, expects the buffer to be large
|
||||
|
79
src/api.cc
79
src/api.cc
@ -4304,6 +4304,85 @@ bool String::IsOneByte() const {
|
||||
}
|
||||
|
||||
|
||||
class ContainsOnlyOneByteHelper {
|
||||
public:
|
||||
ContainsOnlyOneByteHelper() : is_one_byte_(true) {}
|
||||
bool Check(i::String* string) {
|
||||
i::ConsString* cons_string = i::String::VisitFlat(this, string, 0);
|
||||
if (cons_string == NULL) return is_one_byte_;
|
||||
return CheckCons(cons_string);
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (total != 0) is_one_byte_ = false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool CheckCons(i::ConsString* cons_string) {
|
||||
while (true) {
|
||||
// Check left side if flat.
|
||||
i::String* left = cons_string->first();
|
||||
i::ConsString* left_as_cons =
|
||||
i::String::VisitFlat(this, left, 0);
|
||||
if (!is_one_byte_) return false;
|
||||
// Check right side if flat.
|
||||
i::String* right = cons_string->second();
|
||||
i::ConsString* right_as_cons =
|
||||
i::String::VisitFlat(this, right, 0);
|
||||
if (!is_one_byte_) return false;
|
||||
// Standard recurse/iterate trick.
|
||||
if (left_as_cons != NULL && right_as_cons != NULL) {
|
||||
if (left->length() < right->length()) {
|
||||
CheckCons(left_as_cons);
|
||||
cons_string = right_as_cons;
|
||||
} else {
|
||||
CheckCons(right_as_cons);
|
||||
cons_string = left_as_cons;
|
||||
}
|
||||
// Check fast return.
|
||||
if (!is_one_byte_) return false;
|
||||
continue;
|
||||
}
|
||||
// Descend left in place.
|
||||
if (left_as_cons != NULL) {
|
||||
cons_string = left_as_cons;
|
||||
continue;
|
||||
}
|
||||
// Descend right in place.
|
||||
if (right_as_cons != NULL) {
|
||||
cons_string = right_as_cons;
|
||||
continue;
|
||||
}
|
||||
// Terminate.
|
||||
break;
|
||||
}
|
||||
return is_one_byte_;
|
||||
}
|
||||
bool is_one_byte_;
|
||||
DISALLOW_COPY_AND_ASSIGN(ContainsOnlyOneByteHelper);
|
||||
};
|
||||
|
||||
|
||||
bool String::ContainsOnlyOneByte() const {
|
||||
i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
if (IsDeadCheck(str->GetIsolate(),
|
||||
"v8::String::ContainsOnlyOneByte()")) {
|
||||
return false;
|
||||
}
|
||||
if (str->HasOnlyOneByteChars()) return true;
|
||||
ContainsOnlyOneByteHelper helper;
|
||||
return helper.Check(*str);
|
||||
}
|
||||
|
||||
|
||||
class Utf8LengthHelper : public i::AllStatic {
|
||||
public:
|
||||
enum State {
|
||||
|
@ -1205,6 +1205,11 @@ bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
|
||||
if (FLAG_enable_slow_asserts) {
|
||||
// Assert that the resource and the string are equivalent.
|
||||
ASSERT(static_cast<size_t>(this->length()) == resource->length());
|
||||
if (this->IsTwoByteRepresentation()) {
|
||||
ScopedVector<uint16_t> smart_chars(this->length());
|
||||
String::WriteToFlat(this, smart_chars.start(), 0, this->length());
|
||||
ASSERT(String::IsOneByte(smart_chars.start(), this->length()));
|
||||
}
|
||||
ScopedVector<char> smart_chars(this->length());
|
||||
String::WriteToFlat(this, smart_chars.start(), 0, this->length());
|
||||
ASSERT(memcmp(smart_chars.start(),
|
||||
|
@ -16881,6 +16881,51 @@ THREADED_TEST(TwoByteStringInAsciiCons) {
|
||||
}
|
||||
|
||||
|
||||
TEST(ContainsOnlyOneByte) {
|
||||
v8::V8::Initialize();
|
||||
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]);
|
||||
// Set to contain only one byte.
|
||||
for (int i = 0; i < length-1; i++) {
|
||||
string_contents[i] = 0x41;
|
||||
}
|
||||
string_contents[length-1] = 0;
|
||||
// Simple case.
|
||||
Handle<String> string;
|
||||
string = String::NewExternal(new TestResource(*string_contents));
|
||||
CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
|
||||
// Counter example.
|
||||
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");
|
||||
Handle<String> left = base;
|
||||
Handle<String> right = base;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
left = String::Concat(base, left);
|
||||
right = String::Concat(right, base);
|
||||
}
|
||||
Handle<String> balanced = String::Concat(left, base);
|
||||
balanced = String::Concat(balanced, right);
|
||||
Handle<String> cons_strings[] = {left, balanced, right};
|
||||
Handle<String> two_byte =
|
||||
String::NewExternal(new TestResource(*string_contents));
|
||||
for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
|
||||
// Base assumptions.
|
||||
string = cons_strings[i];
|
||||
CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
|
||||
// Test left and right concatentation.
|
||||
string = String::Concat(two_byte, cons_strings[i]);
|
||||
CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
|
||||
string = String::Concat(cons_strings[i], two_byte);
|
||||
CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Failed access check callback that performs a GC on each invocation.
|
||||
void FailedAccessCheckCallbackGC(Local<v8::Object> target,
|
||||
v8::AccessType type,
|
||||
|
Loading…
Reference in New Issue
Block a user