diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 32730ebc5f1332..218e919a167727 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -1006,6 +1006,24 @@ class ScriptOrigin { Handle script_id_; }; +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_; +}; + /** * A compiled JavaScript script, not yet tied to a Context. diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 88d3c889b96cab..c3f84534b4b5df 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -515,6 +515,27 @@ i::Object** EscapableHandleScope::Escape(i::Object** escape_value) { } +SealHandleScope::SealHandleScope(Isolate* isolate) { + i::Isolate* internal_isolate = reinterpret_cast(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 env = Utils::OpenHandle(this); i::Isolate* isolate = env->GetIsolate(); diff --git a/deps/v8/src/api.h b/deps/v8/src/api.h index 1d2a8c8e82829f..62f9f1e0b351b0 100644 --- a/deps/v8/src/api.h +++ b/deps/v8/src/api.h @@ -650,7 +650,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 @@ -658,9 +658,6 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) { #endif break; } -#else - if (prev_limit == block_limit) break; -#endif blocks_.RemoveLast(); #ifdef ENABLE_HANDLE_ZAPPING diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index cc5414da27364e..95fb839aa6236d 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/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], diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 06cf5532e244e3..17de186b9c4c3d 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -21895,6 +21895,38 @@ void CallCompletedCallbackException() { } +TEST(SealHandleScope) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; + + v8::SealHandleScope seal(isolate); + + // Should fail + v8::Local obj = v8::Object::New(isolate); + + USE(obj); +} + + +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 obj = v8::Object::New(isolate); + + USE(obj); + } +} + + TEST(CallCompletedCallbackOneException) { LocalContext env; v8::HandleScope scope(env->GetIsolate());