| Index: test/cctest/test-debug.cc
|
| diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
|
| index 1e3f0ab707eab90451e4c762516ad0909bf53b6e..58c6bd87f9818f52d342fd095b882772b69b6897 100644
|
| --- a/test/cctest/test-debug.cc
|
| +++ b/test/cctest/test-debug.cc
|
| @@ -36,6 +36,7 @@
|
| #include "src/debug/debug.h"
|
| #include "src/deoptimizer.h"
|
| #include "src/frames.h"
|
| +#include "src/futex-emulation.h"
|
| #include "src/utils.h"
|
| #include "test/cctest/cctest.h"
|
|
|
| @@ -7626,3 +7627,147 @@ TEST(DebugBreakInLexicalScopes) {
|
| "x * y",
|
| 30);
|
| }
|
| +
|
| +
|
| +Barriers futex_barriers;
|
| +
|
| +
|
| +class FutexV8Thread : public v8::base::Thread {
|
| + public:
|
| + FutexV8Thread(void* sab_data, size_t sab_size)
|
| + : Thread(Options("V8Thread")), sab_data_(sab_data), sab_size_(sab_size) {}
|
| + void Run();
|
| + v8::Isolate* isolate() { return isolate_; }
|
| +
|
| + private:
|
| + v8::Isolate* isolate_;
|
| + void* sab_data_;
|
| + size_t sab_size_;
|
| +};
|
| +
|
| +
|
| +class FutexDebuggerThread : public v8::base::Thread {
|
| + public:
|
| + explicit FutexDebuggerThread(v8::Isolate* v8_isolate, void* sab_data,
|
| + size_t sab_size)
|
| + : Thread(Options("DebuggerThread")),
|
| + v8_isolate_(v8_isolate),
|
| + sab_data_(sab_data),
|
| + sab_size_(sab_size) {}
|
| + void Run();
|
| +
|
| + private:
|
| + v8::Isolate* v8_isolate_;
|
| + void* sab_data_;
|
| + size_t sab_size_;
|
| +};
|
| +
|
| +
|
| +static void FutexMessageHandler(const v8::Debug::Message& message) {
|
| + static char print_buffer[1000];
|
| + v8::String::Value json(message.GetJSON());
|
| + Utf16ToAscii(*json, json.length(), print_buffer);
|
| + if (IsBreakEventMessage(print_buffer)) {
|
| + // Check that we are inside the futex.
|
| + int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
|
| + CHECK(source_line == 1);
|
| + futex_barriers.barrier_2.Wait();
|
| + }
|
| +}
|
| +
|
| +
|
| +void FutexV8Thread::Run() {
|
| + const char* source =
|
| + "var i32a = new Int32Array(sab);\n"
|
| + "Atomics.futexWait(i32a, 0, 0, Infinity)\n";
|
| +
|
| + v8::Isolate::CreateParams create_params;
|
| + create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
| + isolate_ = v8::Isolate::New(create_params);
|
| + futex_barriers.barrier_3.Wait();
|
| + {
|
| + v8::Isolate::Scope isolate_scope(isolate_);
|
| + DebugLocalContext env(isolate_);
|
| + v8::HandleScope scope(isolate_);
|
| + v8::Debug::SetMessageHandler(&FutexMessageHandler);
|
| + v8::Handle<v8::ObjectTemplate> global_template =
|
| + v8::ObjectTemplate::New(env->GetIsolate());
|
| + global_template->Set(
|
| + v8::String::NewFromUtf8(env->GetIsolate(), "sab"),
|
| + v8::SharedArrayBuffer::New(isolate_, sab_data_, sab_size_));
|
| +
|
| + v8::Handle<v8::Context> context =
|
| + v8::Context::New(isolate_, NULL, global_template);
|
| + v8::Context::Scope context_scope(context);
|
| +
|
| + CompileRun(source);
|
| + }
|
| + futex_barriers.barrier_4.Wait();
|
| + isolate_->Dispose();
|
| +}
|
| +
|
| +
|
| +void FutexDebuggerThread::Run() {
|
| + v8::Isolate::CreateParams create_params;
|
| + create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
| + v8::Isolate* debug_isolate = v8::Isolate::New(create_params);
|
| + {
|
| + v8::Isolate::Scope isolate_scope(debug_isolate);
|
| + DebugLocalContext env(debug_isolate);
|
| + v8::HandleScope scope(debug_isolate);
|
| + v8::Handle<v8::SharedArrayBuffer> sab(
|
| + v8::SharedArrayBuffer::New(debug_isolate, sab_data_, sab_size_));
|
| +
|
| + i::Handle<i::JSArrayBuffer> i_sab = v8::Utils::OpenHandle(*sab);
|
| + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(debug_isolate);
|
| + // Spin loop until v8 thread is waiting on futex.
|
| + while (true) {
|
| + i::Object* num_waiters =
|
| + i::FutexEmulation::NumWaitersForTesting(i_isolate, i_sab, 0);
|
| + if (num_waiters->IsSmi() && i::Smi::cast(num_waiters)->value() > 0) {
|
| + break;
|
| + }
|
| + }
|
| +
|
| + v8::Debug::DebugBreak(v8_isolate_);
|
| + futex_barriers.barrier_2.Wait();
|
| +
|
| + i::FutexEmulation::Wake(i_isolate, i_sab, 0, 1);
|
| + {
|
| + const int kBufferSize = 1000;
|
| + uint16_t buffer[kBufferSize];
|
| + const char* command_continue =
|
| + "{\"seq\":0,"
|
| + "\"type\":\"request\","
|
| + "\"command\":\"continue\"}";
|
| +
|
| + v8::Debug::SendCommand(v8_isolate_, buffer,
|
| + AsciiToUtf16(command_continue, buffer));
|
| + }
|
| + futex_barriers.barrier_4.Wait();
|
| + }
|
| + debug_isolate->Dispose();
|
| +}
|
| +
|
| +
|
| +TEST(FutexDebugging) {
|
| + i::FLAG_harmony_sharedarraybuffer = true;
|
| + i::FLAG_harmony_atomics = true;
|
| +
|
| + size_t size = 16;
|
| + v8::ArrayBuffer::Allocator* array_buffer_allocator =
|
| + CcTest::array_buffer_allocator();
|
| + void* data = array_buffer_allocator->Allocate(size);
|
| +
|
| + FutexV8Thread v8_thread(data, size);
|
| +
|
| + // Create a V8 environment
|
| + v8_thread.Start();
|
| + futex_barriers.barrier_3.Wait();
|
| + FutexDebuggerThread debugger_thread(v8_thread.isolate(), data, size);
|
| + debugger_thread.Start();
|
| +
|
| + v8_thread.Join();
|
| + debugger_thread.Join();
|
| + array_buffer_allocator->Free(data, size);
|
| +}
|
|
|