Created
October 6, 2010 21:57
-
-
Save ry/614169 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 9241b751f9b42d970844fdc62fe84a01aa6d5203 Mon Sep 17 00:00:00 2001 | |
From: Ryan Dahl <ry@tinyclouds.org> | |
Date: Wed, 6 Oct 2010 14:57:46 -0700 | |
Subject: [PATCH] Raw string access | |
--- | |
include/v8.h | 26 +++++++++ | |
src/api.cc | 12 ++++ | |
src/objects.cc | 65 ++++++++++++++++++++++ | |
src/objects.h | 5 ++ | |
test/cctest/test-api.cc | 136 +++++++++++++++++++++++++++++++++++++++++++++++ | |
5 files changed, 244 insertions(+), 0 deletions(-) | |
diff --git a/include/v8.h b/include/v8.h | |
index 9ee1687..81cbc0f 100644 | |
--- a/include/v8.h | |
+++ b/include/v8.h | |
@@ -1207,6 +1207,32 @@ class String : public Primitive { | |
*/ | |
V8EXPORT bool CanMakeExternal(); | |
+ | |
+ struct Pointer { | |
+ const char* data; | |
+ int length; // in bytes | |
+ enum { OneByte, TwoByte } chartype; | |
+ }; | |
+ | |
+ /** | |
+ * Fills the suppied vectors, pointerv, with the addresses of the string | |
+ * in the V8 heap. This is intended to be used to immediately flush the | |
+ * data to socket. These pointers will become invalid the next time V8 is | |
+ * entered, so use this function with exterme care. | |
+ * | |
+ * \param offset the number of characters into the string to start | |
+ * \param pointerv an empty array of pointer vectors to be filled with data. | |
+ * \param pointerv_size the size of the passed array. | |
+ * \param pointerv_filled will be set with the number of vectored filled | |
+ * after the operation. | |
+ * \returns the number of characters of the string represented in the | |
+ * pointers | |
+ */ | |
+ V8EXPORT int Pointers(int offset, | |
+ Pointer *pointerv, | |
+ int pointerv_size, | |
+ int* pointerv_filled); | |
+ | |
/** Creates an undetectable string from the supplied ascii or utf-8 data.*/ | |
V8EXPORT static Local<String> NewUndetectable(const char* data, | |
int length = -1); | |
diff --git a/src/api.cc b/src/api.cc | |
index 7ca9e8f..29e4db5 100644 | |
--- a/src/api.cc | |
+++ b/src/api.cc | |
@@ -3686,6 +3686,18 @@ bool v8::String::CanMakeExternal() { | |
} | |
+int v8::String::Pointers(int offset, | |
+ Pointer *pointerv, | |
+ int pointerv_size, | |
+ int* pointerv_filled) { | |
+ if (IsDeadCheck("v8::String::Pointers()")) return false; | |
+ i::Handle<i::String> obj = Utils::OpenHandle(this); | |
+ | |
+ *pointerv_filled = 0; | |
+ return (*obj)->Pointers(offset, pointerv, pointerv_size, pointerv_filled); | |
+} | |
+ | |
+ | |
Local<v8::Object> v8::Object::New() { | |
EnsureInitialized("v8::Object::New()"); | |
LOG_API("Object::New"); | |
diff --git a/src/objects.cc b/src/objects.cc | |
index 1a3dc4e..c9b6e1c 100644 | |
--- a/src/objects.cc | |
+++ b/src/objects.cc | |
@@ -3987,6 +3987,71 @@ int String::Utf8Length() { | |
} | |
+int String::Pointers(int offset, | |
+ v8::String::Pointer *pointerv, | |
+ int pointerv_size, | |
+ int* pointerv_filled) { | |
+ if (this->length() == 0) return 0; | |
+ if (*pointerv_filled >= pointerv_size) return 0; | |
+ | |
+ int chars = 0; | |
+ const char *start; | |
+ | |
+ switch (StringShape(this).representation_tag()) { | |
+ case kConsStringTag: { | |
+ // TODO: keep track of how far we recurse, if it's very deep, pull out | |
+ // and flatten. | |
+ ConsString* cons = ConsString::cast(this); | |
+ String* first = cons->first(); | |
+ String* second = cons->second(); | |
+ | |
+ if (offset < first->length() && first->length()) { | |
+ // Need to take the first into consideration. | |
+ chars += first->Pointers(offset, pointerv, pointerv_size, pointerv_filled); | |
+ if (*pointerv_filled >= pointerv_size) return chars; | |
+ offset = 0; | |
+ } else { | |
+ offset -= first->length(); | |
+ } | |
+ | |
+ chars += second->Pointers(offset, pointerv, pointerv_size, pointerv_filled); | |
+ return chars; | |
+ } | |
+ | |
+ case kSeqStringTag: { | |
+ start = this->IsTwoByteRepresentation() | |
+ ? reinterpret_cast<char*>(SeqTwoByteString::cast(this)->GetChars()) | |
+ : SeqAsciiString::cast(this)->GetChars(); | |
+ break; | |
+ } | |
+ | |
+ case kExternalStringTag: { | |
+ start = this->IsTwoByteRepresentation() | |
+ ? (char*)(ExternalTwoByteString::cast(this)->resource()->data()) | |
+ : ExternalAsciiString::cast(this)->resource()->data(); | |
+ break; | |
+ } | |
+ | |
+ default: | |
+ ASSERT(0); | |
+ *pointerv_filled = 0; | |
+ return 0; | |
+ } | |
+ | |
+ if (this->IsTwoByteRepresentation()) { | |
+ pointerv[*pointerv_filled].data = start + (2 * offset); | |
+ pointerv[*pointerv_filled].length = 2 * (this->length() - offset); | |
+ pointerv[*pointerv_filled].chartype = v8::String::Pointer::TwoByte; | |
+ } else { | |
+ pointerv[*pointerv_filled].data = start + offset; | |
+ pointerv[*pointerv_filled].length = this->length() - offset; | |
+ pointerv[*pointerv_filled].chartype = v8::String::Pointer::OneByte; | |
+ } | |
+ *pointerv_filled += 1; | |
+ return this->length() - offset; | |
+} | |
+ | |
+ | |
Vector<const char> String::ToAsciiVector() { | |
ASSERT(IsAsciiRepresentation()); | |
ASSERT(IsFlat()); | |
diff --git a/src/objects.h b/src/objects.h | |
index e284454..b0e25fd 100644 | |
--- a/src/objects.h | |
+++ b/src/objects.h | |
@@ -4510,6 +4510,11 @@ class String: public HeapObject { | |
Vector<const char> ToAsciiVector(); | |
Vector<const uc16> ToUC16Vector(); | |
+ int Pointers(int offset, | |
+ v8::String::Pointer *pointerv, | |
+ int pointerv_size, | |
+ int* pointerv_filled); | |
+ | |
// Mark the string as an undetectable object. It only applies to | |
// ascii and two byte string types. | |
bool MarkAsUndetectable(); | |
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc | |
index 0631351..72136c1 100644 | |
--- a/test/cctest/test-api.cc | |
+++ b/test/cctest/test-api.cc | |
@@ -743,6 +743,142 @@ THREADED_TEST(StringConcat) { | |
} | |
+THREADED_TEST(StringPointersFlat) { | |
+ { | |
+ v8::HandleScope scope; | |
+ LocalContext env; | |
+ const char* hello_world = "hello world"; | |
+ Local<String> s = v8_str(hello_world); | |
+ | |
+ String::Pointer ptrs[2]; | |
+ int used; | |
+ | |
+ int chars = s->Pointers(0, ptrs, 2, &used); | |
+ | |
+ CHECK_EQ(1, used); | |
+ CHECK_EQ(11, ptrs[0].length); | |
+ CHECK_EQ(11, chars); | |
+ CHECK_EQ('h', ptrs[0].data[0]); | |
+ CHECK_EQ('e', ptrs[0].data[1]); | |
+ CHECK_EQ('l', ptrs[0].data[2]); | |
+ CHECK_EQ('l', ptrs[0].data[3]); | |
+ CHECK_EQ('o', ptrs[0].data[4]); | |
+ CHECK_EQ(' ', ptrs[0].data[5]); | |
+ CHECK_EQ('w', ptrs[0].data[6]); | |
+ CHECK_EQ('o', ptrs[0].data[7]); | |
+ CHECK_EQ('r', ptrs[0].data[8]); | |
+ CHECK_EQ('l', ptrs[0].data[9]); | |
+ CHECK_EQ('d', ptrs[0].data[10]); | |
+ CHECK_EQ(v8::String::Pointer::OneByte, ptrs[0].chartype); | |
+ } | |
+ i::CompilationCache::Clear(); | |
+ i::Heap::CollectAllGarbage(false); | |
+ i::Heap::CollectAllGarbage(false); | |
+} | |
+ | |
+ | |
+THREADED_TEST(StringPointersCons) { | |
+ { | |
+ v8::HandleScope scope; | |
+ LocalContext env; | |
+ | |
+ const char* hello = "hello hello hello hello hello hello "; | |
+ const char* world = "world world world world world world world world "; | |
+ | |
+ | |
+ Local<String> s = v8_str(hello); | |
+ Local<String> t = v8_str(world); | |
+ | |
+ Local<String> c = v8::String::Concat(s,t); | |
+ | |
+ // This isn't part of the actual test. Just want to make sure that this | |
+ // is actually a cons string. If the following test fails, maybe | |
+ // increase the size of s and t. | |
+ i::Handle<i::String> str = v8::Utils::OpenHandle(*c); | |
+ CHECK(i::StringShape(*str).IsCons()); | |
+ | |
+ | |
+ String::Pointer ptrs[3]; | |
+ int used; | |
+ | |
+ int chars = c->Pointers(0, ptrs, 3, &used); | |
+ | |
+ CHECK_EQ(2, used); | |
+ CHECK_EQ(strlen(hello) + strlen(world), chars); | |
+ | |
+ CHECK_EQ(strlen(hello), ptrs[0].length); | |
+ CHECK_EQ(v8::String::Pointer::OneByte, ptrs[0].chartype); | |
+ for (unsigned int i = 0; i < strlen(hello); i++) { | |
+ CHECK_EQ(hello[i], ptrs[0].data[i]); | |
+ } | |
+ | |
+ CHECK_EQ(strlen(world), ptrs[1].length); | |
+ CHECK_EQ(v8::String::Pointer::OneByte, ptrs[1].chartype); | |
+ for (unsigned int i = 0; i < strlen(world); i++) { | |
+ CHECK_EQ(world[i], ptrs[1].data[i]); | |
+ } | |
+ } | |
+ i::CompilationCache::Clear(); | |
+ i::Heap::CollectAllGarbage(false); | |
+ i::Heap::CollectAllGarbage(false); | |
+} | |
+ | |
+ | |
+THREADED_TEST(StringPointersCons2) { | |
+ { | |
+ v8::HandleScope scope; | |
+ LocalContext env; | |
+ | |
+ const char* hello = "hello hello hello hello hello hello "; | |
+ const char* world = "world world world world world world world world "; | |
+ | |
+ Local<String> s = v8_str(hello); | |
+ Local<String> t = v8_str(world); | |
+ Local<String> c = v8::String::Concat(v8::String::Concat(s,t), | |
+ v8::String::Concat(v8::String::Concat(s,t), | |
+ t)); | |
+ | |
+ // This isn't part of the actual test. Just want to make sure that this | |
+ // is actually a cons string. If the following test fails, maybe | |
+ // increase the size of s and t. | |
+ i::Handle<i::String> str = v8::Utils::OpenHandle(*c); | |
+ CHECK(i::StringShape(*str).IsCons()); | |
+ | |
+ | |
+ String::Pointer ptrs[10]; | |
+ int used; | |
+ | |
+ int chars = c->Pointers(0, ptrs, 10, &used); | |
+ | |
+ CHECK_EQ(5, used); | |
+ CHECK_EQ(2 * strlen(hello) + 3 * strlen(world), chars); | |
+ | |
+ CHECK_EQ(strlen(hello), ptrs[0].length); | |
+ CHECK_EQ(v8::String::Pointer::OneByte, ptrs[0].chartype); | |
+ CHECK_EQ('h', ptrs[0].data[0]); | |
+ | |
+ CHECK_EQ(strlen(world), ptrs[1].length); | |
+ CHECK_EQ(v8::String::Pointer::OneByte, ptrs[1].chartype); | |
+ CHECK_EQ('w', ptrs[1].data[0]); | |
+ | |
+ CHECK_EQ(strlen(hello), ptrs[2].length); | |
+ CHECK_EQ(v8::String::Pointer::OneByte, ptrs[2].chartype); | |
+ CHECK_EQ('h', ptrs[2].data[0]); | |
+ | |
+ CHECK_EQ(strlen(world), ptrs[3].length); | |
+ CHECK_EQ(v8::String::Pointer::OneByte, ptrs[3].chartype); | |
+ CHECK_EQ('w', ptrs[3].data[0]); | |
+ | |
+ CHECK_EQ(strlen(world), ptrs[4].length); | |
+ CHECK_EQ(v8::String::Pointer::OneByte, ptrs[4].chartype); | |
+ CHECK_EQ('w', ptrs[4].data[0]); | |
+ } | |
+ i::CompilationCache::Clear(); | |
+ i::Heap::CollectAllGarbage(false); | |
+ i::Heap::CollectAllGarbage(false); | |
+} | |
+ | |
+ | |
THREADED_TEST(GlobalProperties) { | |
v8::HandleScope scope; | |
LocalContext env; | |
-- | |
1.7.2 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment