зеркало из https://github.com/mozilla/gecko-dev.git
226 строки
7.6 KiB
C++
226 строки
7.6 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
* 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_JSControl_h
|
|
#define mozilla_recordreplay_JSControl_h
|
|
|
|
#include "jsapi.h"
|
|
|
|
#include "InfallibleVector.h"
|
|
#include "ProcessRewind.h"
|
|
|
|
#include "mozilla/DefineEnum.h"
|
|
|
|
namespace mozilla {
|
|
namespace recordreplay {
|
|
namespace js {
|
|
|
|
// This file manages interactions between the record/replay infrastructure and
|
|
// JS code. This interaction can occur in two ways:
|
|
//
|
|
// - In the middleman process, devtools server code can use the
|
|
// RecordReplayControl object to send requests to the recording/replaying
|
|
// child process and control its behavior.
|
|
//
|
|
// - In the recording/replaying process, a JS sandbox is created before the
|
|
// first checkpoint is reached, which responds to the middleman's requests.
|
|
// The RecordReplayControl object is also provided here, but has a different
|
|
// interface which allows the JS to query the current process.
|
|
|
|
// Identification for a position where a breakpoint can be installed in a child
|
|
// process. Breakpoint positions describe all places between checkpoints where
|
|
// the child process can pause and be inspected by the middleman. A particular
|
|
// BreakpointPosition can be reached any number of times during execution of
|
|
// the process.
|
|
struct BreakpointPosition
|
|
{
|
|
MOZ_DEFINE_ENUM_AT_CLASS_SCOPE(Kind, (
|
|
Invalid,
|
|
|
|
// Break at a script offset. Requires script/offset.
|
|
Break,
|
|
|
|
// Break for an on-step handler within a frame.
|
|
// Requires script/offset/frameIndex.
|
|
OnStep,
|
|
|
|
// Break either when any frame is popped, or when a specific frame is
|
|
// popped. Requires script/frameIndex in the latter case.
|
|
OnPop,
|
|
|
|
// Break when entering any frame.
|
|
EnterFrame,
|
|
|
|
// Break when a new top-level script is created.
|
|
NewScript,
|
|
|
|
// Break when a message is logged to the web console.
|
|
ConsoleMessage,
|
|
|
|
// Break when NewTimeWarpTarget() is called.
|
|
WarpTarget,
|
|
|
|
// Break when the debugger should pause even if no breakpoint has been
|
|
// set: the beginning or end of the replay has been reached, or a time
|
|
// warp has reached its destination.
|
|
ForcedPause
|
|
));
|
|
|
|
Kind mKind;
|
|
|
|
// Optional information associated with the breakpoint.
|
|
uint32_t mScript;
|
|
uint32_t mOffset;
|
|
uint32_t mFrameIndex;
|
|
|
|
static const uint32_t EMPTY_SCRIPT = (uint32_t) -1;
|
|
static const uint32_t EMPTY_OFFSET = (uint32_t) -1;
|
|
static const uint32_t EMPTY_FRAME_INDEX = (uint32_t) -1;
|
|
|
|
BreakpointPosition()
|
|
: mKind(Invalid), mScript(EMPTY_SCRIPT), mOffset(EMPTY_OFFSET), mFrameIndex(EMPTY_FRAME_INDEX)
|
|
{}
|
|
|
|
explicit BreakpointPosition(Kind aKind,
|
|
uint32_t aScript = EMPTY_SCRIPT,
|
|
uint32_t aOffset = EMPTY_OFFSET,
|
|
uint32_t aFrameIndex = EMPTY_FRAME_INDEX)
|
|
: mKind(aKind), mScript(aScript), mOffset(aOffset), mFrameIndex(aFrameIndex)
|
|
{}
|
|
|
|
bool IsValid() const { return mKind != Invalid; }
|
|
|
|
inline bool operator==(const BreakpointPosition& o) const {
|
|
return mKind == o.mKind
|
|
&& mScript == o.mScript
|
|
&& mOffset == o.mOffset
|
|
&& mFrameIndex == o.mFrameIndex;
|
|
}
|
|
|
|
inline bool operator!=(const BreakpointPosition& o) const { return !(*this == o); }
|
|
|
|
// Return whether an execution point matching |o| also matches this.
|
|
inline bool Subsumes(const BreakpointPosition& o) const {
|
|
return (*this == o)
|
|
|| (mKind == OnPop && o.mKind == OnPop && mScript == EMPTY_SCRIPT)
|
|
|| (mKind == Break && o.mKind == OnStep && mScript == o.mScript && mOffset == o.mOffset);
|
|
}
|
|
|
|
static const char* StaticKindString(Kind aKind) {
|
|
switch (aKind) {
|
|
case Invalid: return "Invalid";
|
|
case Break: return "Break";
|
|
case OnStep: return "OnStep";
|
|
case OnPop: return "OnPop";
|
|
case EnterFrame: return "EnterFrame";
|
|
case NewScript: return "NewScript";
|
|
case ConsoleMessage: return "ConsoleMessage";
|
|
case WarpTarget: return "WarpTarget";
|
|
case ForcedPause: return "ForcedPause";
|
|
}
|
|
MOZ_CRASH("Bad BreakpointPosition kind");
|
|
}
|
|
|
|
const char* KindString() const {
|
|
return StaticKindString(mKind);
|
|
}
|
|
|
|
JSObject* Encode(JSContext* aCx) const;
|
|
bool Decode(JSContext* aCx, JS::HandleObject aObject);
|
|
};
|
|
|
|
// Identification for a point in the execution of a child process where it may
|
|
// pause and be inspected by the middleman. A particular execution point will
|
|
// be reached exactly once during the execution of the process.
|
|
struct ExecutionPoint
|
|
{
|
|
// ID of the last normal checkpoint prior to this point.
|
|
size_t mCheckpoint;
|
|
|
|
// How much progress execution has made prior to reaching the point,
|
|
// or zero if the execution point refers to the checkpoint itself.
|
|
//
|
|
// A given BreakpointPosition may not be reached twice without an intervening
|
|
// increment of the global progress counter.
|
|
ProgressCounter mProgress;
|
|
|
|
// The position reached after making the specified amount of progress,
|
|
// invalid if the execution point refers to the checkpoint itself.
|
|
BreakpointPosition mPosition;
|
|
|
|
ExecutionPoint()
|
|
: mCheckpoint(CheckpointId::Invalid)
|
|
, mProgress(0)
|
|
{}
|
|
|
|
explicit ExecutionPoint(size_t aCheckpoint)
|
|
: mCheckpoint(aCheckpoint)
|
|
, mProgress(0)
|
|
{}
|
|
|
|
ExecutionPoint(size_t aCheckpoint, ProgressCounter aProgress,
|
|
const BreakpointPosition& aPosition)
|
|
: mCheckpoint(aCheckpoint), mProgress(aProgress), mPosition(aPosition)
|
|
{
|
|
// ExecutionPoint positions must be as precise as possible, and cannot
|
|
// subsume other positions.
|
|
MOZ_RELEASE_ASSERT(aPosition.IsValid());
|
|
MOZ_RELEASE_ASSERT(aPosition.mKind != BreakpointPosition::OnPop ||
|
|
aPosition.mScript != BreakpointPosition::EMPTY_SCRIPT);
|
|
MOZ_RELEASE_ASSERT(aPosition.mKind != BreakpointPosition::Break);
|
|
}
|
|
|
|
bool HasPosition() const { return mPosition.IsValid(); }
|
|
|
|
inline bool operator==(const ExecutionPoint& o) const {
|
|
return mCheckpoint == o.mCheckpoint
|
|
&& mProgress == o.mProgress
|
|
&& mPosition == o.mPosition;
|
|
}
|
|
|
|
inline bool operator!=(const ExecutionPoint& o) const { return !(*this == o); }
|
|
|
|
JSObject* Encode(JSContext* aCx) const;
|
|
bool Decode(JSContext* aCx, JS::HandleObject aObject);
|
|
};
|
|
|
|
// Buffer type used for encoding object data.
|
|
typedef InfallibleVector<char16_t> CharBuffer;
|
|
|
|
// Called in the middleman when a breakpoint with the specified id has been hit.
|
|
bool HitBreakpoint(JSContext* aCx, size_t id);
|
|
|
|
// Set up the JS sandbox in the current recording/replaying process and load
|
|
// its target script.
|
|
void SetupDevtoolsSandbox();
|
|
|
|
// The following hooks are used in the recording/replaying process to
|
|
// call methods defined by the JS sandbox.
|
|
|
|
// Handle an incoming request from the middleman.
|
|
void ProcessRequest(const char16_t* aRequest, size_t aRequestLength,
|
|
CharBuffer* aResponse);
|
|
|
|
// Ensure there is a handler in place that will call RecordReplayControl.positionHit
|
|
// whenever the specified execution position is reached.
|
|
void EnsurePositionHandler(const BreakpointPosition& aPosition);
|
|
|
|
// Clear all installed position handlers.
|
|
void ClearPositionHandlers();
|
|
|
|
// Clear all state that is kept while execution is paused.
|
|
void ClearPausedState();
|
|
|
|
// Given an execution position inside a script, get an execution position for
|
|
// the entry point of that script, otherwise return nothing.
|
|
Maybe<BreakpointPosition> GetEntryPosition(const BreakpointPosition& aPosition);
|
|
|
|
} // namespace js
|
|
} // namespace recordreplay
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_recordreplay_JSControl_h
|