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:
Brian Hackett 2018-07-22 11:58:24 +00:00
Родитель 4f9e9a98ca
Коммит dc539c0008
3 изменённых файлов: 1262 добавлений и 50 удалений

Просмотреть файл

@ -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

Разница между файлами не показана из-за своего большого размера Загрузить разницу