| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e5b732f commit f729549
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,7 +29,7 @@ | |||
| 29 | 29 | ||
| 30 | 30 | # Reset this number to 0 on major V8 upgrades. | |
| 31 | 31 | # Increment by one for each non-official patch applied to deps/v8. | |
| 32 | - 'v8_embedder_string': '-node.24', | ||
| 32 | + 'v8_embedder_string': '-node.25', | ||
| 33 | 33 | ||
| 34 | 34 | # Enable disassembler for `--print-code` v8 options | |
| 35 | 35 | 'v8_enable_disassembler': 1, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -32,6 +32,7 @@ Facebook, Inc. <*@fb.com> | |||
| 32 | 32 | Facebook, Inc. <*@oculus.com> | |
| 33 | 33 | Vewd Software AS <*@vewd.com> | |
| 34 | 34 | Groupon <*@groupon.com> | |
| 35 | + Meteor Development Group <*@meteor.com> | ||
| 35 | 36 | Cloudflare, Inc. <*@cloudflare.com> | |
| 36 | 37 | ||
| 37 | 38 | Aaron Bieber <deftly@gmail.com> | |
@@ -49,6 +50,7 @@ Andrei Kashcha <anvaka@gmail.com> | |||
| 49 | 50 | Anna Henningsen <anna@addaleax.net> | |
| 50 | 51 | Bangfu Tao <bangfu.tao@samsung.com> | |
| 51 | 52 | Ben Coe <ben@npmjs.com> | |
| 53 | + Ben Newman <ben@meteor.com> | ||
| 52 | 54 | Ben Noordhuis <info@bnoordhuis.nl> | |
| 53 | 55 | Benjamin Tan <demoneaux@gmail.com> | |
| 54 | 56 | Bert Belder <bertbelder@gmail.com> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -355,19 +355,36 @@ void Debug::ThreadInit() { | |||
| 355 | 355 | ||
| 356 | 356 | ||
| 357 | 357 | char* Debug::ArchiveDebug(char* storage) { | |
| 358 | - // Simply reset state. Don't archive anything. | ||
| 359 | - ThreadInit(); | ||
| 358 | + MemCopy(storage, reinterpret_cast<char*>(&thread_local_), | ||
| 359 | + ArchiveSpacePerThread()); | ||
| 360 | 360 | return storage + ArchiveSpacePerThread(); | |
| 361 | 361 | } | |
| 362 | 362 | ||
| 363 | - | ||
| 364 | 363 | char* Debug::RestoreDebug(char* storage) { | |
| 365 | - // Simply reset state. Don't restore anything. | ||
| 366 | - ThreadInit(); | ||
| 364 | + MemCopy(reinterpret_cast<char*>(&thread_local_), storage, | ||
| 365 | + ArchiveSpacePerThread()); | ||
| 366 | + | ||
| 367 | + if (in_debug_scope()) { | ||
| 368 | + // If this thread was in a DebugScope when we archived it, restore the | ||
| 369 | + // previous debugging state now. Note that in_debug_scope() returns | ||
| 370 | + // true when thread_local_.current_debug_scope_ (restored by MemCopy | ||
| 371 | + // above) is non-null. | ||
| 372 | + | ||
| 373 | + // Clear any one-shot breakpoints that may have been set by the other | ||
| 374 | + // thread, and reapply breakpoints for this thread. | ||
| 375 | + HandleScope scope(isolate_); | ||
| 376 | + ClearOneShot(); | ||
| 377 | + | ||
| 378 | + if (thread_local_.last_step_action_ != StepNone) { | ||
| 379 | + // Reset the previous step action for this thread. | ||
| 380 | + PrepareStep(thread_local_.last_step_action_); | ||
| 381 | + } | ||
| 382 | + } | ||
| 383 | + | ||
| 367 | 384 | return storage + ArchiveSpacePerThread(); | |
| 368 | 385 | } | |
| 369 | 386 | ||
| 370 | - int Debug::ArchiveSpacePerThread() { return 0; } | ||
| 387 | + int Debug::ArchiveSpacePerThread() { return sizeof(ThreadLocal); } | ||
| 371 | 388 | ||
| 372 | 389 | void Debug::Iterate(RootVisitor* v) { | |
| 373 | 390 | v->VisitRootPointer(Root::kDebug, nullptr, &thread_local_.return_value_); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -327,6 +327,7 @@ class Debug { | |||
| 327 | 327 | static int ArchiveSpacePerThread(); | |
| 328 | 328 | void FreeThreadResources() { } | |
| 329 | 329 | void Iterate(RootVisitor* v); | |
| 330 | + void InitThread(const ExecutionAccess& lock) { ThreadInit(); } | ||
| 330 | 331 | ||
| 331 | 332 | bool CheckExecutionState(int id) { | |
| 332 | 333 | return CheckExecutionState() && break_id() == id; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -45,7 +45,7 @@ void Locker::Initialize(v8::Isolate* isolate) { | |||
| 45 | 45 | } else { | |
| 46 | 46 | internal::ExecutionAccess access(isolate_); | |
| 47 | 47 | isolate_->stack_guard()->ClearThread(access); | |
| 48 | - isolate_->stack_guard()->InitThread(access); | ||
| 48 | + isolate_->thread_manager()->InitThread(access); | ||
| 49 | 49 | } | |
| 50 | 50 | } | |
| 51 | 51 | DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread()); | |
@@ -95,6 +95,10 @@ Unlocker::~Unlocker() { | |||
| 95 | 95 | ||
| 96 | 96 | namespace internal { | |
| 97 | 97 | ||
| 98 | + void ThreadManager::InitThread(const ExecutionAccess& lock) { | ||
| 99 | + isolate_->stack_guard()->InitThread(lock); | ||
| 100 | + isolate_->debug()->InitThread(lock); | ||
| 101 | + } | ||
| 98 | 102 | ||
| 99 | 103 | bool ThreadManager::RestoreThread() { | |
| 100 | 104 | DCHECK(IsLockedByCurrentThread()); | |
@@ -127,7 +131,7 @@ bool ThreadManager::RestoreThread() { | |||
| 127 | 131 | isolate_->FindPerThreadDataForThisThread(); | |
| 128 | 132 | if (per_thread == nullptr || per_thread->thread_state() == nullptr) { | |
| 129 | 133 | // This is a new thread. | |
| 130 | - isolate_->stack_guard()->InitThread(access); | ||
| 134 | + InitThread(access); | ||
| 131 | 135 | return false; | |
| 132 | 136 | } | |
| 133 | 137 | ThreadState* state = per_thread->thread_state(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -67,6 +67,7 @@ class ThreadManager { | |||
| 67 | 67 | void Lock(); | |
| 68 | 68 | void Unlock(); | |
| 69 | 69 | ||
| 70 | + void InitThread(const ExecutionAccess&); | ||
| 70 | 71 | void ArchiveThread(); | |
| 71 | 72 | bool RestoreThread(); | |
| 72 | 73 | void FreeThreadResources(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6221,6 +6221,135 @@ TEST(DebugBreakOffThreadTerminate) { | |||
| 6221 | 6221 | } | |
| 6222 | 6222 | ||
| 6223 | 6223 | ||
| 6224 | + class ArchiveRestoreThread : public v8::base::Thread, | ||
| 6225 | + public v8::debug::DebugDelegate { | ||
| 6226 | + public: | ||
| 6227 | + ArchiveRestoreThread(v8::Isolate* isolate, int spawn_count) | ||
| 6228 | + : Thread(Options("ArchiveRestoreThread")), | ||
| 6229 | + isolate_(isolate), | ||
| 6230 | + debug_(reinterpret_cast<i::Isolate*>(isolate_)->debug()), | ||
| 6231 | + spawn_count_(spawn_count), | ||
| 6232 | + break_count_(0) {} | ||
| 6233 | + | ||
| 6234 | + virtual void Run() { | ||
| 6235 | + v8::Locker locker(isolate_); | ||
| 6236 | + isolate_->Enter(); | ||
| 6237 | + | ||
| 6238 | + v8::HandleScope scope(isolate_); | ||
| 6239 | + v8::Local<v8::Context> context = v8::Context::New(isolate_); | ||
| 6240 | + v8::Context::Scope context_scope(context); | ||
| 6241 | + | ||
| 6242 | + v8::Local<v8::Function> test = CompileFunction(isolate_, | ||
| 6243 | + "function test(n) {\n" | ||
| 6244 | + " debugger;\n" | ||
| 6245 | + " return n + 1;\n" | ||
| 6246 | + "}\n", | ||
| 6247 | + "test"); | ||
| 6248 | + | ||
| 6249 | + debug_->SetDebugDelegate(this, false); | ||
| 6250 | + v8::internal::DisableBreak enable_break(debug_, false); | ||
| 6251 | + | ||
| 6252 | + v8::Local<v8::Value> args[1] = {v8::Integer::New(isolate_, spawn_count_)}; | ||
| 6253 | + | ||
| 6254 | + int result = test->Call(context, context->Global(), 1, args) | ||
| 6255 | + .ToLocalChecked() | ||
| 6256 | + ->Int32Value(context) | ||
| 6257 | + .FromJust(); | ||
| 6258 | + | ||
| 6259 | + // Verify that test(spawn_count_) returned spawn_count_ + 1. | ||
| 6260 | + CHECK_EQ(spawn_count_ + 1, result); | ||
| 6261 | + | ||
| 6262 | + isolate_->Exit(); | ||
| 6263 | + } | ||
| 6264 | + | ||
| 6265 | + void BreakProgramRequested(v8::Local<v8::Context> context, | ||
| 6266 | + v8::Local<v8::Object> exec_state, | ||
| 6267 | + const std::vector<v8::debug::BreakpointId>&) { | ||
| 6268 | + auto stack_traces = v8::debug::StackTraceIterator::Create(isolate_); | ||
| 6269 | + if (!stack_traces->Done()) { | ||
| 6270 | + v8::debug::Location location = stack_traces->GetSourceLocation(); | ||
| 6271 | + | ||
| 6272 | + i::PrintF("ArchiveRestoreThread #%d hit breakpoint at line %d\n", | ||
| 6273 | + spawn_count_, location.GetLineNumber()); | ||
| 6274 | + | ||
| 6275 | + switch (location.GetLineNumber()) { | ||
| 6276 | + case 1: // debugger; | ||
| 6277 | + CHECK_EQ(break_count_, 0); | ||
| 6278 | + | ||
| 6279 | + // Attempt to stop on the next line after the first debugger | ||
| 6280 | + // statement. If debug->{Archive,Restore}Debug() improperly reset | ||
| 6281 | + // thread-local debug information, the debugger will fail to stop | ||
| 6282 | + // before the test function returns. | ||
| 6283 | + debug_->PrepareStep(StepNext); | ||
| 6284 | + | ||
| 6285 | + // Spawning threads while handling the current breakpoint verifies | ||
| 6286 | + // that the parent thread correctly archived and restored the | ||
| 6287 | + // state necessary to stop on the next line. If not, then control | ||
| 6288 | + // will simply continue past the `return n + 1` statement. | ||
| 6289 | + MaybeSpawnChildThread(); | ||
| 6290 | + | ||
| 6291 | + break; | ||
| 6292 | + | ||
| 6293 | + case 2: // return n + 1; | ||
| 6294 | + CHECK_EQ(break_count_, 1); | ||
| 6295 | + break; | ||
| 6296 | + | ||
| 6297 | + default: | ||
| 6298 | + CHECK(false); | ||
| 6299 | + } | ||
| 6300 | + } | ||
| 6301 | + | ||
| 6302 | + ++break_count_; | ||
| 6303 | + } | ||
| 6304 | + | ||
| 6305 | + void MaybeSpawnChildThread() { | ||
| 6306 | + if (spawn_count_ > 1) { | ||
| 6307 | + v8::Unlocker unlocker(isolate_); | ||
| 6308 | + | ||
| 6309 | + // Spawn a thread that spawns a thread that spawns a thread (and so | ||
| 6310 | + // on) so that the ThreadManager is forced to archive and restore | ||
| 6311 | + // the current thread. | ||
| 6312 | + ArchiveRestoreThread child(isolate_, spawn_count_ - 1); | ||
| 6313 | + child.Start(); | ||
| 6314 | + child.Join(); | ||
| 6315 | + | ||
| 6316 | + // The child thread sets itself as the debug delegate, so we need to | ||
| 6317 | + // usurp it after the child finishes, or else future breakpoints | ||
| 6318 | + // will be delegated to a destroyed ArchiveRestoreThread object. | ||
| 6319 | + debug_->SetDebugDelegate(this, false); | ||
| 6320 | + | ||
| 6321 | + // This is the most important check in this test, since | ||
| 6322 | + // child.GetBreakCount() will return 1 if the debugger fails to stop | ||
| 6323 | + // on the `return n + 1` line after the grandchild thread returns. | ||
| 6324 | + CHECK_EQ(child.GetBreakCount(), 2); | ||
| 6325 | + } | ||
| 6326 | + } | ||
| 6327 | + | ||
| 6328 | + int GetBreakCount() { return break_count_; } | ||
| 6329 | + | ||
| 6330 | + private: | ||
| 6331 | + v8::Isolate* isolate_; | ||
| 6332 | + v8::internal::Debug* debug_; | ||
| 6333 | + const int spawn_count_; | ||
| 6334 | + int break_count_; | ||
| 6335 | + }; | ||
| 6336 | + | ||
| 6337 | + TEST(DebugArchiveRestore) { | ||
| 6338 | + v8::Isolate::CreateParams create_params; | ||
| 6339 | + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); | ||
| 6340 | + v8::Isolate* isolate = v8::Isolate::New(create_params); | ||
| 6341 | + | ||
| 6342 | + ArchiveRestoreThread thread(isolate, 5); | ||
| 6343 | + // Instead of calling thread.Start() and thread.Join() here, we call | ||
| 6344 | + // thread.Run() directly, to make sure we exercise archive/restore | ||
| 6345 | + // logic on the *current* thread as well as other threads. | ||
| 6346 | + thread.Run(); | ||
| 6347 | + CHECK_EQ(thread.GetBreakCount(), 2); | ||
| 6348 | + | ||
| 6349 | + isolate->Dispose(); | ||
| 6350 | + } | ||
| 6351 | + | ||
| 6352 | + | ||
| 6224 | 6353 | static void DebugEventExpectNoException( | |
| 6225 | 6354 | const v8::Debug::EventDetails& event_details) { | |
| 6226 | 6355 | v8::DebugEvent event = event_details.GetEvent(); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments