blob: 0b7808b73aa9e3b3361f157fdd93ec7b35aaecbe [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bindings/core/v8/serialization/SerializedScriptValue.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/V8BindingForTesting.h"
#include "bindings/core/v8/WorkerOrWorkletScriptController.h"
#include "bindings/core/v8/serialization/UnpackedSerializedScriptValue.h"
#include "build/build_config.h"
#include "core/dom/Document.h"
#include "core/typed_arrays/DOMArrayBuffer.h"
#include "core/workers/WorkerThreadTestHelper.h"
#include "platform/bindings/ToV8.h"
namespace blink {
// On debug builds, Oilpan contains checks that will fail if a persistent handle
// is destroyed on the wrong thread.
TEST(SerializedScriptValueThreadedTest,
SafeDestructionIfSendingThreadKeepsAlive) {
V8TestingScope scope;
// Start a worker.
WorkerReportingProxy proxy;
WorkerThreadForTest worker_thread(nullptr, proxy);
ParentFrameTaskRunners* parent_frame_task_runners =
ParentFrameTaskRunners::Create(&scope.GetDocument());
worker_thread.StartWithSourceCode(scope.GetDocument().GetSecurityOrigin(),
"/* no worker script */",
parent_frame_task_runners);
// Create a serialized script value that contains transferred array buffer
// contents.
DOMArrayBuffer* array_buffer = DOMArrayBuffer::Create(1, 1);
Transferables transferables;
transferables.array_buffers.push_back(array_buffer);
SerializedScriptValue::SerializeOptions options;
options.transferables = &transferables;
scoped_refptr<SerializedScriptValue> serialized =
SerializedScriptValue::Serialize(
scope.GetIsolate(),
ToV8(array_buffer, scope.GetContext()->Global(), scope.GetIsolate()),
options, ASSERT_NO_EXCEPTION);
EXPECT_TRUE(serialized);
EXPECT_TRUE(array_buffer->IsNeutered());
// Deserialize the serialized value on the worker.
// Intentionally keep a reference on this thread while this occurs.
worker_thread.GetWorkerBackingThread().BackingThread().PostTask(
FROM_HERE,
CrossThreadBind(
[](WorkerThread* worker_thread,
scoped_refptr<SerializedScriptValue> serialized) {
WorkerOrWorkletScriptController* script =
worker_thread->GlobalScope()->ScriptController();
EXPECT_TRUE(script->IsContextInitialized());
ScriptState::Scope worker_scope(script->GetScriptState());
SerializedScriptValue::Unpack(serialized)
->Deserialize(worker_thread->GetIsolate());
// Make sure this thread's references in the Oilpan heap are dropped
// before the main thread continues.
ThreadState::Current()->CollectAllGarbage();
},
CrossThreadUnretained(&worker_thread), serialized));
// Wait for a subsequent task on the worker to finish, to ensure that the
// references held by the task are dropped.
WaitableEvent done;
worker_thread.GetWorkerBackingThread().BackingThread().PostTask(
FROM_HERE,
CrossThreadBind(&WaitableEvent::Signal, CrossThreadUnretained(&done)));
done.Wait();
// Now destroy the value on the main thread.
EXPECT_TRUE(serialized->HasOneRef());
serialized = nullptr;
// Finally, shut down the worker thread.
worker_thread.Terminate();
worker_thread.WaitForShutdownForTesting();
}
} // namespace blink