| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "extensions/renderer/api_binding_test.h" | |
| 6 | |
| 7 #include "base/memory/ptr_util.h" | |
| 8 #include "base/threading/thread_task_runner_handle.h" | |
| 9 #include "gin/array_buffer.h" | |
| 10 #include "gin/public/context_holder.h" | |
| 11 #include "gin/public/isolate_holder.h" | |
| 12 #include "gin/v8_initializer.h" | |
| 13 | |
| 14 namespace extensions { | |
| 15 | |
| 16 APIBindingTest::APIBindingTest() {} | |
| 17 APIBindingTest::~APIBindingTest() {} | |
| 18 | |
| 19 v8::ExtensionConfiguration* APIBindingTest::GetV8ExtensionConfiguration() { | |
| 20 return nullptr; | |
| 21 } | |
| 22 | |
| 23 void APIBindingTest::SetUp() { | |
| 24 // Much of this initialization is stolen from the somewhat-similar | |
| 25 // gin::V8Test. | |
| 26 #ifdef V8_USE_EXTERNAL_STARTUP_DATA | |
| 27 gin::V8Initializer::LoadV8Snapshot(); | |
| 28 gin::V8Initializer::LoadV8Natives(); | |
| 29 #endif | |
| 30 | |
| 31 gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode, | |
| 32 gin::IsolateHolder::kStableV8Extras, | |
| 33 gin::ArrayBufferAllocator::SharedInstance()); | |
| 34 | |
| 35 isolate_holder_ = | |
| 36 base::MakeUnique<gin::IsolateHolder>(base::ThreadTaskRunnerHandle::Get()); | |
| 37 isolate()->Enter(); | |
| 38 | |
| 39 v8::HandleScope handle_scope(isolate()); | |
| 40 v8::Local<v8::Context> context = | |
| 41 v8::Context::New(isolate(), GetV8ExtensionConfiguration()); | |
| 42 context->Enter(); | |
| 43 main_context_holder_ = base::MakeUnique<gin::ContextHolder>(isolate()); | |
| 44 main_context_holder_->SetContext(context); | |
| 45 } | |
| 46 | |
| 47 void APIBindingTest::TearDown() { | |
| 48 if (main_context_holder_ || !additional_context_holders_.empty()) { | |
| 49 DisposeAllContexts(); | |
| 50 } else { | |
| 51 // The context was already deleted (as through DisposeContext()), but we | |
| 52 // still need to garbage collect. | |
| 53 RunGarbageCollection(); | |
| 54 } | |
| 55 | |
| 56 isolate()->Exit(); | |
| 57 isolate_holder_.reset(); | |
| 58 } | |
| 59 | |
| 60 void APIBindingTest::DisposeAllContexts() { | |
| 61 auto dispose_and_check_context = | |
| 62 [this](std::unique_ptr<gin::ContextHolder>& holder, bool exit) { | |
| 63 // Check for leaks - a weak handle to a context is invalidated on | |
| 64 // context destruction, so resetting the context should reset the | |
| 65 // handle. | |
| 66 v8::Global<v8::Context> weak_context; | |
| 67 { | |
| 68 v8::HandleScope handle_scope(isolate()); | |
| 69 v8::Local<v8::Context> context = holder->context(); | |
| 70 weak_context.Reset(isolate(), context); | |
| 71 weak_context.SetWeak(); | |
| 72 OnWillDisposeContext(context); | |
| 73 if (exit) | |
| 74 context->Exit(); | |
| 75 } | |
| 76 holder.reset(); | |
| 77 | |
| 78 // Garbage collect everything so that we find any issues where we might | |
| 79 // be double-freeing. | |
| 80 RunGarbageCollection(); | |
| 81 | |
| 82 // The context should have been deleted. | |
| 83 // (ASSERT_TRUE is not used, so that Isolate::Exit is still called.) | |
| 84 EXPECT_TRUE(weak_context.IsEmpty()); | |
| 85 }; | |
| 86 | |
| 87 for (auto& context_holder : additional_context_holders_) | |
| 88 dispose_and_check_context(context_holder, false); | |
| 89 additional_context_holders_.clear(); | |
| 90 | |
| 91 if (main_context_holder_) | |
| 92 dispose_and_check_context(main_context_holder_, true); | |
| 93 } | |
| 94 | |
| 95 v8::Local<v8::Context> APIBindingTest::AddContext() { | |
| 96 auto holder = base::MakeUnique<gin::ContextHolder>(isolate()); | |
| 97 v8::Local<v8::Context> context = | |
| 98 v8::Context::New(isolate(), GetV8ExtensionConfiguration()); | |
| 99 holder->SetContext(context); | |
| 100 additional_context_holders_.push_back(std::move(holder)); | |
| 101 return context; | |
| 102 } | |
| 103 | |
| 104 v8::Local<v8::Context> APIBindingTest::MainContext() { | |
| 105 return main_context_holder_->context(); | |
| 106 } | |
| 107 | |
| 108 void APIBindingTest::DisposeContext(v8::Local<v8::Context> context) { | |
| 109 if (main_context_holder_ && context == main_context_holder_->context()) { | |
| 110 OnWillDisposeContext(context); | |
| 111 main_context_holder_.reset(); | |
| 112 return; | |
| 113 } | |
| 114 | |
| 115 auto iter = std::find_if( | |
| 116 additional_context_holders_.begin(), additional_context_holders_.end(), | |
| 117 [context](const std::unique_ptr<gin::ContextHolder>& holder) { | |
| 118 return holder->context() == context; | |
| 119 }); | |
| 120 ASSERT_TRUE(iter != additional_context_holders_.end()) | |
| 121 << "Could not find context"; | |
| 122 OnWillDisposeContext(context); | |
| 123 additional_context_holders_.erase(iter); | |
| 124 } | |
| 125 | |
| 126 v8::Isolate* APIBindingTest::isolate() { | |
| 127 return isolate_holder_->isolate(); | |
| 128 } | |
| 129 | |
| 130 void APIBindingTest::RunGarbageCollection() { | |
| 131 // '5' is a magic number stolen from Blink; arbitrarily large enough to | |
| 132 // hopefully clean up all the various paths. | |
| 133 for (int i = 0; i < 5; ++i) { | |
| 134 isolate()->RequestGarbageCollectionForTesting( | |
| 135 v8::Isolate::kFullGarbageCollection); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 } // namespace extensions | |
| OLD | NEW |