Reviewers: dcarney,

Message:
This is a follow-up to http://codereview.chromium.org/10918169/

I changed the encoding to use an enum instead of constants.

I also changed the signature of GetExternalStringResourceBase to return the
resource base as return value and return the encoding as call-by-reference
variable. The semantic changed slightly: if the string is not an external
string, the encoding is returned nevertheless (bit masking should be just as
cheap as assigning 0 to the return value).

Description:
Introduce new API to expose external string resource regardless of encoding.

BUG=


Please review this at http://codereview.chromium.org/10917211/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files:
  M include/v8.h
  M src/api.cc
  M src/objects-inl.h
  M test/cctest/test-api.cc


Index: include/v8.h
diff --git a/include/v8.h b/include/v8.h
index ddde388cd4f27c970c29e351333b06cd94b5c026..37d66586aa08f0aea782f8152bc9639e4bef4de8 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1018,6 +1018,11 @@ class Boolean : public Primitive {
  */
 class String : public Primitive {
  public:
+  enum Encoding {
+    UNKNOWN_ENCODING = 0x1,
+    TWO_BYTE_ENCODING = 0x0,
+    ASCII_ENCODING = 0x4
+  };
   /**
    * Returns the number of characters in this string.
    */
@@ -1181,6 +1186,14 @@ class String : public Primitive {
   };

   /**
+ * If the string is an external string, return the ExternalStringResourceBase + * regardless of the encoding, otherwise return NULL. The encoding of the
+   * string is returned in type_out.
+   */
+  inline ExternalStringResourceBase* GetExternalStringResourceBase(
+      Encoding* encoding_out) const;
+
+  /**
    * Get the ExternalStringResource for an external string.  Returns
    * NULL if IsExternal() doesn't return true.
    */
@@ -1226,6 +1239,8 @@ class String : public Primitive {
* this function should not otherwise delete or modify the resource. Neither * should the underlying buffer be deallocated or modified except through the
    * destructor of the external string resource.
+   * The optional encoding argument provides a hint on whether scanning for
+   * ASCII content is necessary.
    */
V8EXPORT static Local<String> NewExternal(ExternalStringResource* resource);

@@ -1343,6 +1358,8 @@ class String : public Primitive {
   };

  private:
+ V8EXPORT void VerifyExternalStringResourceBase(ExternalStringResourceBase* v, + Encoding encoding_out) const; V8EXPORT void VerifyExternalStringResource(ExternalStringResource* val) const;
   V8EXPORT static void CheckCast(v8::Value* obj);
 };
@@ -4033,7 +4050,9 @@ class Internals {
   static const int kForeignAddressOffset = kApiPointerSize;
   static const int kJSObjectHeaderSize = 3 * kApiPointerSize;
   static const int kFullStringRepresentationMask = 0x07;
+  static const int kStringEncodingMask = 0x4;
   static const int kExternalTwoByteRepresentationTag = 0x02;
+  static const int kExternalAsciiRepresentationTag = 0x06;

   static const int kIsolateStateOffset = 0;
   static const int kIsolateEmbedderDataOffset = 1 * kApiPointerSize;
@@ -4388,6 +4407,26 @@ String::ExternalStringResource* String::GetExternalStringResource() const {
 }


+String::ExternalStringResourceBase* String::GetExternalStringResourceBase(
+    String::Encoding* encoding_out) const {
+  typedef internal::Object O;
+  typedef internal::Internals I;
+  O* obj = *reinterpret_cast<O**>(const_cast<String*>(this));
+  int type = I::GetInstanceType(obj) & I::kFullStringRepresentationMask;
+  *encoding_out = static_cast<Encoding>(type & I::kStringEncodingMask);
+  ExternalStringResourceBase* resource = NULL;
+  if (type == I::kExternalAsciiRepresentationTag ||
+      type == I::kExternalTwoByteRepresentationTag) {
+    void* value = I::ReadField<void*>(obj, I::kStringResourceOffset);
+    resource = static_cast<ExternalStringResourceBase*>(value);
+  }
+#ifdef V8_ENABLE_CHECKS
+    VerifyExternalStringResourceBase(resource, *encoding_out);
+#endif
+  return resource;
+}
+
+
 bool Value::IsUndefined() const {
 #ifdef V8_ENABLE_CHECKS
   return FullIsUndefined();
Index: src/api.cc
diff --git a/src/api.cc b/src/api.cc
index 5c76e32a1b4ec24734b2279c29c1ab8f0f1a428e..9dd6dae8d135f186b4cb1b9645b163c76159c90b 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -4089,6 +4089,30 @@ void v8::String::VerifyExternalStringResource(
   CHECK_EQ(expected, value);
 }

+void v8::String::VerifyExternalStringResourceBase(
+    v8::String::ExternalStringResourceBase* value,
+    Encoding encoding) const {
+  i::Handle<i::String> str = Utils::OpenHandle(this);
+  const v8::String::ExternalStringResourceBase* expected;
+  Encoding expectedEncoding;
+  if (i::StringShape(*str).IsExternalAscii()) {
+    const void* resource =
+        i::Handle<i::ExternalAsciiString>::cast(str)->resource();
+ expected = reinterpret_cast<const ExternalStringResourceBase*>(resource);
+    expectedEncoding = ASCII_ENCODING;
+  } else if (i::StringShape(*str).IsExternalTwoByte()) {
+    const void* resource =
+        i::Handle<i::ExternalTwoByteString>::cast(str)->resource();
+ expected = reinterpret_cast<const ExternalStringResourceBase*>(resource);
+    expectedEncoding = TWO_BYTE_ENCODING;
+  } else {
+    expected = NULL;
+    expectedEncoding = str->IsAsciiRepresentation() ? ASCII_ENCODING
+                                                    : TWO_BYTE_ENCODING;
+  }
+  CHECK_EQ(expected, value);
+  CHECK_EQ(expectedEncoding, encoding);
+}

 const v8::String::ExternalAsciiStringResource*
       v8::String::GetExternalAsciiStringResource() const {
Index: src/objects-inl.h
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 3b9bb0a13783fd6829bbffe3a678b6babeeb08c4..391358386d5102d26f22c236e4fe81a061698378 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -382,6 +382,9 @@ uint32_t StringShape::full_representation_tag() {
 STATIC_CHECK((kStringRepresentationMask | kStringEncodingMask) ==
              Internals::kFullStringRepresentationMask);

+STATIC_CHECK(static_cast<uint32_t>(kStringEncodingMask) ==
+             Internals::kStringEncodingMask);
+

 bool StringShape::IsSequentialAscii() {
   return full_representation_tag() == (kSeqStringTag | kAsciiStringTag);
@@ -398,6 +401,12 @@ bool StringShape::IsExternalAscii() {
 }


+STATIC_CHECK((kExternalStringTag | kAsciiStringTag) ==
+             Internals::kExternalAsciiRepresentationTag);
+
+STATIC_CHECK(v8::String::ASCII_ENCODING == kAsciiStringTag);
+
+
 bool StringShape::IsExternalTwoByte() {
return full_representation_tag() == (kExternalStringTag | kTwoByteStringTag);
 }
@@ -406,6 +415,7 @@ bool StringShape::IsExternalTwoByte() {
 STATIC_CHECK((kExternalStringTag | kTwoByteStringTag) ==
              Internals::kExternalTwoByteRepresentationTag);

+STATIC_CHECK(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag);

 uc32 FlatStringReader::Get(int index) {
   ASSERT(0 <= index && index <= length_);
Index: test/cctest/test-api.cc
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 4bd99a6d9e940abd97ba243ecb383a119f4854f3..09125e1407c1ae84921005737437dc74f79ddf0d 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -404,6 +404,10 @@ THREADED_TEST(ScriptUsingStringResource) {
     CHECK(source->IsExternal());
     CHECK_EQ(resource,
static_cast<TestResource*>(source->GetExternalStringResource()));
+    String::Encoding encoding = String::UNKNOWN_ENCODING;
+ CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
+             source->GetExternalStringResourceBase(&encoding));
+    CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
     HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
     CHECK_EQ(0, dispose_count);
   }
@@ -419,9 +423,16 @@ THREADED_TEST(ScriptUsingAsciiStringResource) {
   {
     v8::HandleScope scope;
     LocalContext env;
-    Local<String> source =
-        String::NewExternal(new TestAsciiResource(i::StrDup(c_source),
-                                                  &dispose_count));
+ TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
+                                                        &dispose_count);
+    Local<String> source = String::NewExternal(resource);
+    CHECK(source->IsExternalAscii());
+ CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
+             source->GetExternalAsciiStringResource());
+    String::Encoding encoding = String::UNKNOWN_ENCODING;
+ CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
+             source->GetExternalStringResourceBase(&encoding));
+    CHECK_EQ(String::ASCII_ENCODING, encoding);
     Local<Script> script = Script::Compile(source);
     Local<Value> value = script->Run();
     CHECK(value->IsNumber());
@@ -445,6 +456,11 @@ THREADED_TEST(ScriptMakingExternalString) {
     // Trigger GCs so that the newly allocated string moves to old gen.
     HEAP->CollectGarbage(i::NEW_SPACE);  // in survivor space now
     HEAP->CollectGarbage(i::NEW_SPACE);  // in old gen now
+    CHECK_EQ(source->IsExternal(), false);
+    CHECK_EQ(source->IsExternalAscii(), false);
+    String::Encoding encoding = String::UNKNOWN_ENCODING;
+    CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
+    CHECK_EQ(String::ASCII_ENCODING, encoding);
     bool success = source->MakeExternal(new TestResource(two_byte_source,
                                                          &dispose_count));
     CHECK(success);


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

Reply via email to