зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1470795 Part 6 - Add navigation logic for managing breakpoints in child process, r=mccr8.
--HG-- extra : rebase_source : 764945decc9eba8fae725e0da279969e0f136792
This commit is contained in:
Родитель
4f9e9a98ca
Коммит
dc539c0008
|
@ -7,7 +7,7 @@
|
|||
// This file has the logic which the replayed process uses to communicate with
|
||||
// the middleman process.
|
||||
|
||||
#include "ChildIPC.h"
|
||||
#include "ChildInternal.h"
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "base/task.h"
|
||||
|
@ -79,8 +79,13 @@ ChannelMessageHandler(Message* aMsg)
|
|||
}
|
||||
case MessageType::CreateCheckpoint: {
|
||||
MOZ_RELEASE_ASSERT(IsRecording());
|
||||
uint8_t data = 0;
|
||||
DirectWrite(gCheckpointWriteFd, &data, 1);
|
||||
|
||||
// Ignore requests to create checkpoints before we have reached the first
|
||||
// paint and finished initializing.
|
||||
if (navigation::IsInitialized()) {
|
||||
uint8_t data = 0;
|
||||
DirectWrite(gCheckpointWriteFd, &data, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MessageType::Terminate: {
|
||||
|
@ -109,38 +114,29 @@ ChannelMessageHandler(Message* aMsg)
|
|||
}
|
||||
case MessageType::DebuggerRequest: {
|
||||
const DebuggerRequestMessage& nmsg = (const DebuggerRequestMessage&) *aMsg;
|
||||
JS::replay::CharBuffer* buf = js_new<JS::replay::CharBuffer>();
|
||||
if (!buf->append(nmsg.Buffer(), nmsg.BufferSize())) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
PauseMainThreadAndInvokeCallback([=]() { JS::replay::hooks.debugRequestReplay(buf); });
|
||||
js::CharBuffer* buf = new js::CharBuffer();
|
||||
buf->append(nmsg.Buffer(), nmsg.BufferSize());
|
||||
PauseMainThreadAndInvokeCallback([=]() { navigation::DebuggerRequest(buf); });
|
||||
break;
|
||||
}
|
||||
case MessageType::SetBreakpoint: {
|
||||
const SetBreakpointMessage& nmsg = (const SetBreakpointMessage&) *aMsg;
|
||||
PauseMainThreadAndInvokeCallback([=]() {
|
||||
JS::replay::hooks.setBreakpointReplay(nmsg.mId, nmsg.mPosition);
|
||||
navigation::SetBreakpoint(nmsg.mId, nmsg.mPosition);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case MessageType::Resume: {
|
||||
const ResumeMessage& nmsg = (const ResumeMessage&) *aMsg;
|
||||
PauseMainThreadAndInvokeCallback([=]() {
|
||||
// Inform the debugger about the request to resume execution. The hooks
|
||||
// will not have been set yet for the primordial resume, in which case
|
||||
// just continue executing forward.
|
||||
if (JS::replay::hooks.resumeReplay) {
|
||||
JS::replay::hooks.resumeReplay(nmsg.mForward);
|
||||
} else {
|
||||
ResumeExecution();
|
||||
}
|
||||
navigation::Resume(nmsg.mForward);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case MessageType::RestoreCheckpoint: {
|
||||
const RestoreCheckpointMessage& nmsg = (const RestoreCheckpointMessage&) *aMsg;
|
||||
PauseMainThreadAndInvokeCallback([=]() {
|
||||
JS::replay::hooks.restoreCheckpointReplay(nmsg.mCheckpoint);
|
||||
navigation::RestoreCheckpoint(nmsg.mCheckpoint);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -158,11 +154,6 @@ PrefsShmemContents(size_t aPrefsLen)
|
|||
return gShmemPrefs;
|
||||
}
|
||||
|
||||
// Initialize hooks used by the replay debugger.
|
||||
static void InitDebuggerHooks();
|
||||
|
||||
static void HitCheckpoint(size_t aId, bool aRecordingEndpoint);
|
||||
|
||||
// Main routine for a thread whose sole purpose is to listen to requests from
|
||||
// the middleman process to create a new checkpoint. This is separate from the
|
||||
// channel thread because this thread is recorded and the latter is not
|
||||
|
@ -222,8 +213,6 @@ InitRecordingOrReplayingProcess(int* aArgc, char*** aArgv)
|
|||
|
||||
Thread::StartThread(ListenForCheckpointThreadMain, nullptr, false);
|
||||
|
||||
InitDebuggerHooks();
|
||||
|
||||
pt.emplace();
|
||||
|
||||
// Setup a mach port to receive the graphics shmem handle over.
|
||||
|
@ -387,7 +376,7 @@ EndIdleTime()
|
|||
gIdleTimeStart = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
HitCheckpoint(size_t aId, bool aRecordingEndpoint)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
@ -407,8 +396,8 @@ HitCheckpoint(size_t aId, bool aRecordingEndpoint)
|
|||
// Debugger Messages
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void
|
||||
DebuggerResponseHook(const JS::replay::CharBuffer& aBuffer)
|
||||
void
|
||||
RespondToRequest(const js::CharBuffer& aBuffer)
|
||||
{
|
||||
DebuggerResponseMessage* msg =
|
||||
DebuggerResponseMessage::New(aBuffer.begin(), aBuffer.length());
|
||||
|
@ -416,7 +405,7 @@ DebuggerResponseHook(const JS::replay::CharBuffer& aBuffer)
|
|||
free(msg);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
HitBreakpoint(bool aRecordingEndpoint, const uint32_t* aBreakpoints, size_t aNumBreakpoints)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
@ -428,27 +417,6 @@ HitBreakpoint(bool aRecordingEndpoint, const uint32_t* aBreakpoints, size_t aNum
|
|||
});
|
||||
}
|
||||
|
||||
static void
|
||||
PauseAfterRecoveringFromDivergence()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
PauseMainThreadAndInvokeCallback([=]() {
|
||||
JS::replay::hooks.respondAfterRecoveringFromDivergence();
|
||||
});
|
||||
}
|
||||
|
||||
static void
|
||||
InitDebuggerHooks()
|
||||
{
|
||||
// Initialize hooks the JS debugger in a recording/replaying process can invoke.
|
||||
JS::replay::hooks.hitBreakpointReplay = HitBreakpoint;
|
||||
JS::replay::hooks.hitCheckpointReplay = HitCheckpoint;
|
||||
JS::replay::hooks.debugResponseReplay = DebuggerResponseHook;
|
||||
JS::replay::hooks.pauseAndRespondAfterRecoveringFromDivergence = PauseAfterRecoveringFromDivergence;
|
||||
JS::replay::hooks.hitCurrentRecordingEndpointReplay = HitRecordingEndpoint;
|
||||
JS::replay::hooks.canRewindReplay = HasSavedCheckpoint;
|
||||
}
|
||||
|
||||
} // namespace child
|
||||
} // namespace recordreplay
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_recordreplay_ChildInternal_h
|
||||
#define mozilla_recordreplay_ChildInternal_h
|
||||
|
||||
#include "ChildIPC.h"
|
||||
#include "JSControl.h"
|
||||
#include "Monitor.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace recordreplay {
|
||||
|
||||
// The navigation namespace has definitions for managing breakpoints and all
|
||||
// other state that persists across rewinds, and for keeping track of the
|
||||
// precise execution position of the child process. The middleman will send the
|
||||
// child process Resume messages to travel forward and backward, but it is up
|
||||
// to the child process to keep track of the rewinding and resuming necessary
|
||||
// to find the next or previous point where a breakpoint or checkpoint is hit.
|
||||
namespace navigation {
|
||||
|
||||
// Navigation state is initialized when the first checkpoint is reached.
|
||||
bool IsInitialized();
|
||||
|
||||
// In a recording process, get the current execution point, aka the endpoint
|
||||
// of the recording.
|
||||
js::ExecutionPoint GetRecordingEndpoint();
|
||||
|
||||
// In a replaying process, set the recording endpoint. |index| is used to
|
||||
// differentiate different endpoints that have been sequentially written to
|
||||
// the recording file as it has been flushed.
|
||||
void SetRecordingEndpoint(size_t aIndex, const js::ExecutionPoint& aEndpoint);
|
||||
|
||||
// Save temporary checkpoints at all opportunities during navigation.
|
||||
void AlwaysSaveTemporaryCheckpoints();
|
||||
|
||||
// Process incoming requests from the middleman.
|
||||
void DebuggerRequest(js::CharBuffer* aBuffer);
|
||||
void SetBreakpoint(size_t aId, const js::BreakpointPosition& aPosition);
|
||||
void Resume(bool aForward);
|
||||
void RestoreCheckpoint(size_t aId);
|
||||
|
||||
// Attempt to diverge from the recording so that new recorded events cause
|
||||
// the process to rewind. Returns false if the divergence failed: either we
|
||||
// can't rewind, or already diverged here and then had an unhandled divergence.
|
||||
bool MaybeDivergeFromRecording();
|
||||
|
||||
// Notify navigation that a position was hit.
|
||||
void PositionHit(const js::BreakpointPosition& aPosition);
|
||||
|
||||
// Called when running forward, immediately before hitting a normal or
|
||||
// temporary checkpoint.
|
||||
void BeforeCheckpoint();
|
||||
|
||||
// Called immediately after hitting a normal or temporary checkpoint, either
|
||||
// when running forward or immediately after rewinding.
|
||||
void AfterCheckpoint(const CheckpointId& aCheckpoint);
|
||||
|
||||
} // namespace navigation
|
||||
|
||||
// IPC activity that can be triggered by navigation.
|
||||
namespace child {
|
||||
|
||||
void RespondToRequest(const js::CharBuffer& aBuffer);
|
||||
|
||||
void HitCheckpoint(size_t aId, bool aRecordingEndpoint);
|
||||
|
||||
void HitBreakpoint(bool aRecordingEndpoint, const uint32_t* aBreakpoints, size_t aNumBreakpoints);
|
||||
|
||||
// Monitor used for various synchronization tasks.
|
||||
extern Monitor* gMonitor;
|
||||
|
||||
} // namespace child
|
||||
|
||||
} // namespace recordreplay
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_recordreplay_ChildInternal_h
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче