- Do not allocate proxy objects if the pointer can be wrapped in a Smi representation.
authoriposva@chromium.org <iposva@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 20 Mar 2009 22:13:50 +0000 (22:13 +0000)
committeriposva@chromium.org <iposva@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 20 Mar 2009 22:13:50 +0000 (22:13 +0000)
Review URL: http://codereview.chromium.org/42466

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

include/v8.h
src/api.cc
src/api.h
test/cctest/test-api.cc

index fb142d7a366ccd353a4ef2573ebb8fac079a6aa8..dfba9dbae422e3afadd549036a5188bce0810638 100644 (file)
@@ -1151,6 +1151,10 @@ class V8EXPORT External : public Value {
   static External* Cast(Value* obj);
   void* Value() const;
  private:
+  enum {
+    kAlignedPointerMask = 3,
+    kAlignedPointerShift = 2
+  };
   External();
 };
 
index 5c48e5e98a567bc568f284a9766a14d2ed22205d..5ae13a12d8705c25026994e0b8c47b6c949d8015 100644 (file)
@@ -1447,7 +1447,7 @@ Local<Integer> Value::ToInteger() const {
 External* External::Cast(v8::Value* that) {
   if (IsDeadCheck("v8::External::Cast()")) return 0;
   i::Handle<i::Object> obj = Utils::OpenHandle(that);
-  ApiCheck(obj->IsProxy(),
+  ApiCheck(obj->IsProxy() || obj->IsSmi(),
            "v8::External::Cast()",
            "Could not convert to external");
   return static_cast<External*>(that);
@@ -2229,6 +2229,11 @@ int32_t Int32::Value() const {
 void* External::Value() const {
   if (IsDeadCheck("v8::External::Value()")) return 0;
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) {
+    // The external value was an aligned pointer.
+    return reinterpret_cast<void*>(
+        i::Smi::cast(*obj)->value() << kAlignedPointerShift);
+  }
   return reinterpret_cast<void*>(i::Proxy::cast(*obj)->proxy());
 }
 
@@ -2467,8 +2472,14 @@ Local<External> v8::External::New(void* data) {
   STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
   LOG_API("External::New");
   EnsureInitialized("v8::External::New()");
-  i::Handle<i::Proxy> obj = i::Factory::NewProxy(static_cast<i::Address>(data));
-  return Utils::ToLocal(obj);
+  if ((reinterpret_cast<intptr_t>(data) & kAlignedPointerMask) == 0) {
+    uintptr_t data_ptr = reinterpret_cast<uintptr_t>(data);
+    int data_value = static_cast<int>(data_ptr >> kAlignedPointerShift);
+    STATIC_ASSERT(sizeof(data_ptr) == sizeof(data_value));
+    i::Handle<i::Smi> obj(i::Smi::FromInt(data_value));
+    return Utils::ToLocal(obj);
+  }
+  return Utils::ToLocal(i::Factory::NewProxy(static_cast<i::Address>(data)));
 }
 
 
index 85b13ec9a670296e926440016f0c30cb1ec0da0d..27ec3415d56ed421748cd8b4b85e765842f51e25 100644 (file)
--- a/src/api.h
+++ b/src/api.h
@@ -181,6 +181,8 @@ class Utils {
       v8::internal::Handle<v8::internal::JSArray> obj);
   static inline Local<External> ToLocal(
       v8::internal::Handle<v8::internal::Proxy> obj);
+  static inline Local<External> ToLocal(
+      v8::internal::Handle<v8::internal::Smi> obj);
   static inline Local<Message> MessageToLocal(
       v8::internal::Handle<v8::internal::Object> obj);
   static inline Local<Number> NumberToLocal(
@@ -256,6 +258,7 @@ MAKE_TO_LOCAL(ToLocal, String, String)
 MAKE_TO_LOCAL(ToLocal, JSObject, Object)
 MAKE_TO_LOCAL(ToLocal, JSArray, Array)
 MAKE_TO_LOCAL(ToLocal, Proxy, External)
+MAKE_TO_LOCAL(ToLocal, Smi, External)
 MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate)
 MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate)
 MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature)
index 2f7f16d3e5ad3483fe3c41a3c307747927090236..a1fcfa8edbf0f46b3902791b74b666f5dd49c541 100644 (file)
@@ -1339,6 +1339,22 @@ THREADED_TEST(External) {
   CHECK_EQ(x, 3);
   *ptr = 10;
   CHECK_EQ(x, 10);
+
+  // Make sure unaligned pointers are wrapped properly.
+  char* data = "0123456789";
+  Local<v8::External> zero = v8::External::New(&data[0]);
+  Local<v8::External> one = v8::External::New(&data[1]);
+  Local<v8::External> two = v8::External::New(&data[2]);
+  Local<v8::External> three = v8::External::New(&data[3]);
+
+  char* char_ptr = reinterpret_cast<char*>(zero->Value());
+  CHECK_EQ('0', *char_ptr);
+  char_ptr = reinterpret_cast<char*>(one->Value());
+  CHECK_EQ('1', *char_ptr);
+  char_ptr = reinterpret_cast<char*>(two->Value());
+  CHECK_EQ('2', *char_ptr);
+  char_ptr = reinterpret_cast<char*>(three->Value());
+  CHECK_EQ('3', *char_ptr);
 }