Reviewers: yangguo, indutny,

Message:
Thank you!

Description:
api: introduce SealHandleScope

When debugging Handle leaks in io.js we found it very convenient to be
able to Seal some specific (root in our case) scope to prevent Handle
allocations in it, and easily find leakage.

R=yangguo
BUG=

Please review this at https://codereview.chromium.org/1079713002/

Base URL: https://chromium.googlesource.com/v8/v8.git@master

Affected files (+73, -4 lines):
  M include/v8.h
  M src/api.h
  M src/api.cc
  M test/cctest/cctest.status
  M test/cctest/test-api.cc


Index: include/v8.h
diff --git a/include/v8.h b/include/v8.h
index 8019a4522b4bafb811263bc39bb53e516fbeb2b6..d94e9b32b854826ba221abb3948f057fb74a9a26 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -1018,6 +1018,24 @@ class V8_EXPORT EscapableHandleScope : public HandleScope {
   internal::Object** escape_slot_;
 };

+class V8_EXPORT SealHandleScope {
+ public:
+  SealHandleScope(Isolate* isolate);
+  ~SealHandleScope();
+
+ private:
+  // Make it hard to create heap-allocated or illegal handle scopes by
+  // disallowing certain operations.
+  SealHandleScope(const SealHandleScope&);
+  void operator=(const SealHandleScope&);
+  void* operator new(size_t size);
+  void operator delete(void*, size_t);
+
+  internal::Isolate* isolate_;
+  int prev_level_;
+  internal::Object** prev_limit_;
+};
+

 // --- Special objects ---

Index: src/api.cc
diff --git a/src/api.cc b/src/api.cc
index 28c84106df4c260cfbd2e96972a12efcd1f10964..733214ec076712b31538853fe24fcc03162f80b9 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -674,6 +674,27 @@ i::Object** EscapableHandleScope::Escape(i::Object** escape_value) {
 }


+SealHandleScope::SealHandleScope(Isolate* isolate) {
+  i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
+
+  isolate_ = internal_isolate;
+  i::HandleScopeData* current = internal_isolate->handle_scope_data();
+  prev_limit_ = current->limit;
+  current->limit = current->next;
+  prev_level_ = current->level;
+  current->level = 0;
+}
+
+
+SealHandleScope::~SealHandleScope() {
+  i::HandleScopeData* current = isolate_->handle_scope_data();
+  DCHECK_EQ(0, current->level);
+  current->level = prev_level_;
+  DCHECK_EQ(current->next, current->limit);
+  current->limit = prev_limit_;
+}
+
+
 void Context::Enter() {
   i::Handle<i::Context> env = Utils::OpenHandle(this);
   i::Isolate* isolate = env->GetIsolate();
Index: src/api.h
diff --git a/src/api.h b/src/api.h
index fa8682bf572079558491ee7cba95e44e55ea73b3..7fce3e3b0a27e299e7a634ad3e947b5374df64fc 100644
--- a/src/api.h
+++ b/src/api.h
@@ -661,7 +661,7 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) {
   while (!blocks_.is_empty()) {
     internal::Object** block_start = blocks_.last();
     internal::Object** block_limit = block_start + kHandleBlockSize;
-#ifdef DEBUG
+
     // SealHandleScope may make the prev_limit to point inside the block.
     if (block_start <= prev_limit && prev_limit <= block_limit) {
 #ifdef ENABLE_HANDLE_ZAPPING
@@ -669,9 +669,6 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) {
 #endif
       break;
     }
-#else
-    if (prev_limit == block_limit) break;
-#endif

     blocks_.RemoveLast();
 #ifdef ENABLE_HANDLE_ZAPPING
Index: test/cctest/cctest.status
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 34cbab1dcb88d51c87deb6a956d7270c179f2a41..2fcf8a5e9da6ad06fdd89ed3b77fd75d63280eca 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -40,6 +40,7 @@
   # they don't fail then test.py has failed.
   'test-serialize/TestThatAlwaysFails': [FAIL],
   'test-serialize/DependentTestThatAlwaysFails': [FAIL],
+  'test-api/SealHandleScope': [FAIL],

# This test always fails. It tests that LiveEdit causes abort when turned off.
   'test-debug/LiveEditDisabled': [FAIL],
Index: test/cctest/test-api.cc
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index f7cbb8294d66d958ee16762a2b64c23646272e8f..18d2389409c6d97c9130bd22364895c60e21c610 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -21900,3 +21900,35 @@ TEST(NewStringRangeError) {
   }
   free(buffer);
 }
+
+
+TEST(SealHandleScope) {
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  v8::SealHandleScope seal(isolate);
+
+  // Should fail
+  v8::Local<v8::Object> obj = v8::Object::New(isolate);
+
+  USE(ob);
+}
+
+
+TEST(SealHandleScopeNested) {
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  v8::SealHandleScope seal(isolate);
+
+  {
+    v8::HandleScope handle_scope(isolate);
+
+    // Should work
+    v8::Local<v8::Object> obj = v8::Object::New(isolate);
+
+    USE(ob);
+  }
+}


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to