mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-09-11 14:46:37 +03:00
Add stackframe requests to debugger
Summary: Release note: none - move id into DebuggerRequest - create DebuggerResponse types - stackframe request from UI - Prepack compute stack frames and send back Closes https://github.com/facebook/prepack/pull/1126 Differential Revision: D6232933 Pulled By: JWZ2018 fbshipit-source-id: d14d9da82b8b03dc77bc5a41d62faf026594e315
This commit is contained in:
parent
4944f2e939
commit
3334237ab7
@ -25,7 +25,7 @@ export default function(opts: RealmOptions = {}, debugChannel: void | DebugChann
|
||||
let r = new Realm(opts);
|
||||
if (debugChannel) {
|
||||
if (debugChannel.debuggerIsAttached()) {
|
||||
r.debuggerInstance = new DebugServer(debugChannel);
|
||||
r.debuggerInstance = new DebugServer(debugChannel, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,15 +16,17 @@ import invariant from "../invariant.js";
|
||||
import type { DebugChannel } from "./channel/DebugChannel.js";
|
||||
import { DebugMessage } from "./channel/DebugMessage.js";
|
||||
import { DebuggerError } from "./DebuggerError.js";
|
||||
import type { DebuggerRequest } from "./types.js";
|
||||
import type { DebuggerRequest, StackframeArguments, Stackframe } from "./types.js";
|
||||
import type { Realm } from "./../realm.js";
|
||||
|
||||
export class DebugServer {
|
||||
constructor(channel: DebugChannel) {
|
||||
constructor(channel: DebugChannel, realm: Realm) {
|
||||
this._breakpoints = new BreakpointCollection();
|
||||
this._previousExecutedLine = 0;
|
||||
this._previousExecutedCol = 0;
|
||||
this._lastRunRequestID = 0;
|
||||
this._channel = channel;
|
||||
this._realm = realm;
|
||||
this.waitForRun();
|
||||
}
|
||||
// the collection of breakpoints
|
||||
@ -35,6 +37,7 @@ export class DebugServer {
|
||||
// the channel to communicate with the adapter
|
||||
_channel: DebugChannel;
|
||||
_lastRunRequestID: number;
|
||||
_realm: Realm;
|
||||
|
||||
/* Block until adapter says to run
|
||||
/* runCondition: a function that determines whether the adapter has told
|
||||
@ -110,38 +113,76 @@ export class DebugServer {
|
||||
// Process a command from a debugger. Returns whether Prepack should unblock
|
||||
// if it is blocked
|
||||
processDebuggerCommand(request: DebuggerRequest) {
|
||||
let requestID = request.id;
|
||||
let command = request.command;
|
||||
let args = request.arguments;
|
||||
switch (command) {
|
||||
case DebugMessage.BREAKPOINT_ADD_COMMAND:
|
||||
invariant(args.kind === "breakpoint");
|
||||
this._breakpoints.addBreakpoint(args.filePath, args.line, args.column);
|
||||
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, args);
|
||||
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, requestID, args);
|
||||
break;
|
||||
case DebugMessage.BREAKPOINT_REMOVE_COMMAND:
|
||||
invariant(args.kind === "breakpoint");
|
||||
this._breakpoints.removeBreakpoint(args.filePath, args.line, args.column);
|
||||
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_REMOVE_ACKNOWLEDGE, args);
|
||||
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_REMOVE_ACKNOWLEDGE, requestID, args);
|
||||
break;
|
||||
case DebugMessage.BREAKPOINT_ENABLE_COMMAND:
|
||||
invariant(args.kind === "breakpoint");
|
||||
this._breakpoints.enableBreakpoint(args.filePath, args.line, args.column);
|
||||
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_ENABLE_ACKNOWLEDGE, args);
|
||||
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_ENABLE_ACKNOWLEDGE, requestID, args);
|
||||
break;
|
||||
case DebugMessage.BREAKPOINT_DISABLE_COMMAND:
|
||||
invariant(args.kind === "breakpoint");
|
||||
this._breakpoints.disableBreakpoint(args.filePath, args.line, args.column);
|
||||
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_DISABLE_ACKNOWLEDGE, args);
|
||||
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_DISABLE_ACKNOWLEDGE, requestID, args);
|
||||
break;
|
||||
case DebugMessage.PREPACK_RUN_COMMAND:
|
||||
invariant(args.kind === "run");
|
||||
return true;
|
||||
case DebugMessage.STACKFRAMES_COMMAND:
|
||||
invariant(args.kind === "stackframe");
|
||||
this.processStackframesCommand(requestID, args);
|
||||
break;
|
||||
default:
|
||||
throw new DebuggerError("Invalid command", "Invalid command from adapter: " + command);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
processStackframesCommand(requestID: number, args: StackframeArguments) {
|
||||
let frameInfos: Array<Stackframe> = [];
|
||||
let loc = this._realm.currentLocation;
|
||||
|
||||
// the UI displays the current frame as index 0, so we iterate backwards
|
||||
// from the current frame
|
||||
for (let i = this._realm.contextStack.length - 1; i >= 0; i--) {
|
||||
let frame = this._realm.contextStack[i];
|
||||
let functionName = "(anonymous function)";
|
||||
if (frame.function && frame.function.__originalName) {
|
||||
functionName = frame.function.__originalName;
|
||||
}
|
||||
let fileName = "unknown";
|
||||
let line = 0;
|
||||
let column = 0;
|
||||
if (loc && loc.source) {
|
||||
fileName = loc.source;
|
||||
line = loc.start.line;
|
||||
column = loc.start.column;
|
||||
}
|
||||
let frameInfo: Stackframe = {
|
||||
id: this._realm.contextStack.length - 1 - i,
|
||||
functionName: functionName,
|
||||
fileName: fileName,
|
||||
line: line,
|
||||
column: column,
|
||||
};
|
||||
frameInfos.push(frameInfo);
|
||||
loc = frame.loc;
|
||||
}
|
||||
this._channel.sendStackframeResponse(requestID, frameInfos);
|
||||
}
|
||||
|
||||
shutdown() {
|
||||
//let the adapter know Prepack is done running
|
||||
this._channel.sendPrepackFinish();
|
||||
|
@ -24,7 +24,7 @@ import type { DebuggerOptions } from "./../../options.js";
|
||||
import { getDebuggerOptions } from "./../../prepack-options.js";
|
||||
import invariant from "./../../invariant.js";
|
||||
import { DebugMessage } from "./../channel/DebugMessage.js";
|
||||
import type { BreakpointArguments } from "./../types.js";
|
||||
import type { BreakpointArguments, DebuggerResponse } from "./../types.js";
|
||||
import { DebuggerConstants } from "./../DebuggerConstants.js";
|
||||
|
||||
/* An implementation of an debugger adapter adhering to the VSCode Debug protocol
|
||||
@ -132,12 +132,22 @@ class PrepackDebugSession extends LoggingDebugSession {
|
||||
}
|
||||
|
||||
_registerMessageCallbacks() {
|
||||
this._adapterChannel.registerChannelEvent(DebugMessage.PREPACK_READY_RESPONSE, (message: string) => {
|
||||
this._adapterChannel.registerChannelEvent(DebugMessage.PREPACK_READY_RESPONSE, (response: DebuggerResponse) => {
|
||||
this.sendEvent(new StoppedEvent("entry", DebuggerConstants.PREPACK_THREAD_ID));
|
||||
});
|
||||
this._adapterChannel.registerChannelEvent(DebugMessage.BREAKPOINT_STOPPED_RESPONSE, (description: string) => {
|
||||
this.sendEvent(new StoppedEvent("breakpoint " + description, DebuggerConstants.PREPACK_THREAD_ID));
|
||||
});
|
||||
this._adapterChannel.registerChannelEvent(
|
||||
DebugMessage.BREAKPOINT_STOPPED_RESPONSE,
|
||||
(response: DebuggerResponse) => {
|
||||
let result = response.result;
|
||||
invariant(result.kind === "breakpoint-stopped");
|
||||
this.sendEvent(
|
||||
new StoppedEvent(
|
||||
"breakpoint " + `${result.filePath} ${result.line}:${result.column}`,
|
||||
DebuggerConstants.PREPACK_THREAD_ID
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_addRequestCallback(requestID: number, callback: string => void) {
|
||||
@ -166,7 +176,7 @@ class PrepackDebugSession extends LoggingDebugSession {
|
||||
*/
|
||||
continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
|
||||
// send a Run request to Prepack and try to send the next request
|
||||
this._adapterChannel.run(response.request_seq, (message: string) => {
|
||||
this._adapterChannel.run(response.request_seq, (dbgResponse: DebuggerResponse) => {
|
||||
this.sendResponse(response);
|
||||
});
|
||||
}
|
||||
@ -193,7 +203,33 @@ class PrepackDebugSession extends LoggingDebugSession {
|
||||
};
|
||||
breakpointInfos.push(breakpointInfo);
|
||||
}
|
||||
this._adapterChannel.setBreakpoints(response.request_seq, breakpointInfos, (message: string) => {
|
||||
this._adapterChannel.setBreakpoints(response.request_seq, breakpointInfos, (dbgResponse: DebuggerResponse) => {
|
||||
this.sendResponse(response);
|
||||
});
|
||||
}
|
||||
|
||||
stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): void {
|
||||
this._adapterChannel.getStackFrames(response.request_seq, (dbgResponse: DebuggerResponse) => {
|
||||
let result = dbgResponse.result;
|
||||
invariant(result.kind === "stackframe");
|
||||
let frameInfos = result.stackframes;
|
||||
let frames: Array<DebugProtocol.StackFrame> = [];
|
||||
for (const frameInfo of frameInfos) {
|
||||
let source: DebugProtocol.Source = {
|
||||
path: frameInfo.fileName,
|
||||
};
|
||||
let frame: DebugProtocol.StackFrame = {
|
||||
id: frameInfo.id,
|
||||
name: frameInfo.functionName,
|
||||
source: source,
|
||||
line: frameInfo.line,
|
||||
column: frameInfo.column,
|
||||
};
|
||||
frames.push(frame);
|
||||
}
|
||||
response.body = {
|
||||
stackFrames: frames,
|
||||
};
|
||||
this.sendResponse(response);
|
||||
});
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import EventEmitter from "events";
|
||||
import invariant from "./../../invariant.js";
|
||||
import { DebugMessage } from "./DebugMessage.js";
|
||||
import { DebuggerConstants } from "./../DebuggerConstants.js";
|
||||
import type { BreakpointArguments } from "./../types.js";
|
||||
import type { BreakpointArguments, DebuggerResponse } from "./../types.js";
|
||||
|
||||
//Channel used by the debug adapter to communicate with Prepack
|
||||
export class AdapterChannel {
|
||||
@ -32,7 +32,7 @@ export class AdapterChannel {
|
||||
_ioWrapper: FileIOWrapper;
|
||||
_marshaller: MessageMarshaller;
|
||||
_queue: Queue;
|
||||
_pendingRequestCallbacks: { [number]: (string) => void };
|
||||
_pendingRequestCallbacks: { [number]: (DebuggerResponse) => void };
|
||||
_prepackWaiting: boolean;
|
||||
_eventEmitter: EventEmitter;
|
||||
|
||||
@ -46,22 +46,30 @@ export class AdapterChannel {
|
||||
let parts = message.split(" ");
|
||||
let requestID = parseInt(parts[0], 10);
|
||||
invariant(!isNaN(requestID));
|
||||
let prefix = parts[1];
|
||||
if (prefix === DebugMessage.PREPACK_READY_RESPONSE) {
|
||||
let messageType = parts[1];
|
||||
if (messageType === DebugMessage.PREPACK_READY_RESPONSE) {
|
||||
let result = this._marshaller.unmarshallReadyResponse(requestID);
|
||||
this._prepackWaiting = true;
|
||||
this._eventEmitter.emit(DebugMessage.PREPACK_READY_RESPONSE);
|
||||
this._eventEmitter.emit(DebugMessage.PREPACK_READY_RESPONSE, result);
|
||||
this.trySendNextRequest();
|
||||
} else if (prefix === DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE) {
|
||||
this._eventEmitter.emit(DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, requestID, message);
|
||||
} else if (messageType === DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE) {
|
||||
let dbgResponse = this._marshaller.unmarshallBreakpointAddResponse(requestID);
|
||||
this._eventEmitter.emit(DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, requestID, dbgResponse);
|
||||
// Prepack acknowledged adding a breakpoint
|
||||
this._prepackWaiting = true;
|
||||
this._processRequestCallback(requestID, message);
|
||||
this._processRequestCallback(requestID, dbgResponse);
|
||||
this.trySendNextRequest();
|
||||
} else if (prefix === DebugMessage.BREAKPOINT_STOPPED_RESPONSE) {
|
||||
this._eventEmitter.emit(DebugMessage.BREAKPOINT_STOPPED_RESPONSE, parts.slice(2).join(" "));
|
||||
} else if (messageType === DebugMessage.BREAKPOINT_STOPPED_RESPONSE) {
|
||||
let dbgResponse = this._marshaller.unmarshallBreakpointStoppedResponse(requestID, parts.slice(2));
|
||||
this._eventEmitter.emit(DebugMessage.BREAKPOINT_STOPPED_RESPONSE, dbgResponse);
|
||||
// Prepack stopped on a breakpoint
|
||||
this._prepackWaiting = true;
|
||||
this._processRequestCallback(requestID, message);
|
||||
this._processRequestCallback(requestID, dbgResponse);
|
||||
this.trySendNextRequest();
|
||||
} else if (messageType === DebugMessage.STACKFRAMES_RESPONSE) {
|
||||
let dbgResponse = this._marshaller.unmarshallStackframesResponse(requestID, parts.slice(2).join(" "));
|
||||
this._prepackWaiting = true;
|
||||
this._processRequestCallback(requestID, dbgResponse);
|
||||
this.trySendNextRequest();
|
||||
}
|
||||
}
|
||||
@ -79,38 +87,44 @@ export class AdapterChannel {
|
||||
return true;
|
||||
}
|
||||
|
||||
_addRequestCallback(requestID: number, callback: string => void) {
|
||||
_addRequestCallback(requestID: number, callback: DebuggerResponse => void) {
|
||||
invariant(!(requestID in this._pendingRequestCallbacks), "Request ID already exists in pending requests");
|
||||
this._pendingRequestCallbacks[requestID] = callback;
|
||||
}
|
||||
|
||||
_processRequestCallback(requestID: number, message: string) {
|
||||
_processRequestCallback(requestID: number, response: DebuggerResponse) {
|
||||
invariant(
|
||||
requestID in this._pendingRequestCallbacks,
|
||||
"Request ID does not exist in pending requests: " + requestID
|
||||
);
|
||||
let callback = this._pendingRequestCallbacks[requestID];
|
||||
callback(message);
|
||||
callback(response);
|
||||
}
|
||||
|
||||
registerChannelEvent(event: string, listener: (message: string) => void) {
|
||||
registerChannelEvent(event: string, listener: (response: DebuggerResponse) => void) {
|
||||
this._eventEmitter.addListener(event, listener);
|
||||
}
|
||||
|
||||
run(requestID: number, callback: string => void) {
|
||||
run(requestID: number, callback: DebuggerResponse => void) {
|
||||
this._queue.enqueue(this._marshaller.marshallContinueRequest(requestID));
|
||||
this.trySendNextRequest();
|
||||
this._addRequestCallback(requestID, callback);
|
||||
}
|
||||
|
||||
setBreakpoints(requestID: number, breakpoints: Array<BreakpointArguments>, callback: string => void) {
|
||||
setBreakpoints(requestID: number, breakpoints: Array<BreakpointArguments>, callback: DebuggerResponse => void) {
|
||||
for (const breakpoint of breakpoints) {
|
||||
this._queue.enqueue(this._marshaller.marshallSetBreakpointsRequest(breakpoint));
|
||||
this._queue.enqueue(this._marshaller.marshallSetBreakpointsRequest(requestID, breakpoint));
|
||||
}
|
||||
this.trySendNextRequest();
|
||||
this._addRequestCallback(requestID, callback);
|
||||
}
|
||||
|
||||
getStackFrames(requestID: number, callback: DebuggerResponse => void) {
|
||||
this._queue.enqueue(this._marshaller.marshallStackFramesRequest(requestID));
|
||||
this.trySendNextRequest();
|
||||
this._addRequestCallback(requestID, callback);
|
||||
}
|
||||
|
||||
writeOut(contents: string) {
|
||||
this._ioWrapper.writeOutSync(contents);
|
||||
}
|
||||
|
@ -13,7 +13,14 @@ import { FileIOWrapper } from "./FileIOWrapper.js";
|
||||
import { DebugMessage } from "./DebugMessage.js";
|
||||
import { MessageMarshaller } from "./MessageMarshaller.js";
|
||||
import { DebuggerError } from "./../DebuggerError.js";
|
||||
import type { DebuggerRequest, DebuggerRequestArguments, BreakpointArguments, RunArguments } from "./../types.js";
|
||||
import type {
|
||||
DebuggerRequest,
|
||||
DebuggerRequestArguments,
|
||||
BreakpointArguments,
|
||||
RunArguments,
|
||||
StackframeArguments,
|
||||
Stackframe,
|
||||
} from "./../types.js";
|
||||
|
||||
//Channel used by the DebugServer in Prepack to communicate with the debug adapter
|
||||
export class DebugChannel {
|
||||
@ -69,18 +76,24 @@ export class DebugChannel {
|
||||
this._lastRunRequestID = requestID;
|
||||
let runArgs: RunArguments = {
|
||||
kind: "run",
|
||||
requestID: requestID,
|
||||
};
|
||||
args = runArgs;
|
||||
break;
|
||||
case DebugMessage.BREAKPOINT_ADD_COMMAND:
|
||||
args = this._marshaller.unmarshallBreakpointArguments(requestID, parts.slice(2));
|
||||
break;
|
||||
case DebugMessage.STACKFRAMES_COMMAND:
|
||||
let stackFrameArgs: StackframeArguments = {
|
||||
kind: "stackframe",
|
||||
};
|
||||
args = stackFrameArgs;
|
||||
break;
|
||||
default:
|
||||
throw new DebuggerError("Invalid command", "Invalid command from adapter: " + command);
|
||||
}
|
||||
invariant(args !== undefined);
|
||||
let result: DebuggerRequest = {
|
||||
id: requestID,
|
||||
command: command,
|
||||
arguments: args,
|
||||
};
|
||||
@ -95,21 +108,24 @@ export class DebugChannel {
|
||||
this._requestReceived = false;
|
||||
}
|
||||
|
||||
sendBreakpointAcknowledge(prefix: string, args: BreakpointArguments): void {
|
||||
sendBreakpointAcknowledge(messageType: string, requestID: number, args: BreakpointArguments): void {
|
||||
this.writeOut(
|
||||
this._marshaller.marshallBreakpointAcknowledge(args.requestID, prefix, args.filePath, args.line, args.column)
|
||||
this._marshaller.marshallBreakpointAcknowledge(requestID, messageType, args.filePath, args.line, args.column)
|
||||
);
|
||||
}
|
||||
|
||||
sendBreakpointStopped(filePath: string, line: number, column: number): void {
|
||||
let breakpointInfo: BreakpointArguments = {
|
||||
requestID: this._lastRunRequestID,
|
||||
kind: "breakpoint",
|
||||
filePath: filePath,
|
||||
line: line,
|
||||
column: column,
|
||||
};
|
||||
this.writeOut(this._marshaller.marshallBreakpointStopped(breakpointInfo));
|
||||
this.writeOut(this._marshaller.marshallBreakpointStopped(this._lastRunRequestID, breakpointInfo));
|
||||
}
|
||||
|
||||
sendStackframeResponse(requestID: number, stackframes: Array<Stackframe>): void {
|
||||
this.writeOut(this._marshaller.marshallStackFramesResponse(requestID, stackframes));
|
||||
}
|
||||
|
||||
sendPrepackFinish(): void {
|
||||
|
@ -24,14 +24,20 @@ export class DebugMessage {
|
||||
static BREAKPOINT_ENABLE_COMMAND: string = "Breakpoint-enable-command";
|
||||
// Command to disable a breakpoint
|
||||
static BREAKPOINT_DISABLE_COMMAND: string = "Breakpoint-disable-command";
|
||||
// Command to fetch stack frames
|
||||
static STACKFRAMES_COMMAND: string = "Stackframes-command";
|
||||
|
||||
/* Messages from Prepack to adapter */
|
||||
/* Messages from Prepack to adapter with requested information */
|
||||
// Respond to the adapter that Prepack is ready
|
||||
static PREPACK_READY_RESPONSE: string = "PrepackReady";
|
||||
// Respond to the adapter that Prepack is finished
|
||||
static PREPACK_FINISH_RESPONSE: string = "PrepackFinish";
|
||||
// Respond to the adapter that Prepack has stopped on a breakpoint
|
||||
static BREAKPOINT_STOPPED_RESPONSE: string = "Breakpoint-stopped";
|
||||
static BREAKPOINT_STOPPED_RESPONSE: string = "Breakpoint-stopped-response";
|
||||
// Respond to the adapter with the request stackframes
|
||||
static STACKFRAMES_RESPONSE: string = "Stackframes-response";
|
||||
|
||||
/* Messages from Prepack to adapter to acknowledge having received the request */
|
||||
// Acknowledgement for setting a breakpoint
|
||||
static BREAKPOINT_ADD_ACKNOWLEDGE: string = "Breakpoint-add-acknowledge";
|
||||
// Acknowledgement for removing a breakpoint
|
||||
|
@ -9,8 +9,17 @@
|
||||
|
||||
/* @flow */
|
||||
import { DebugMessage } from "./DebugMessage.js";
|
||||
import type { BreakpointArguments } from "./../types.js";
|
||||
import type {
|
||||
BreakpointArguments,
|
||||
Stackframe,
|
||||
DebuggerResponse,
|
||||
StackframeResult,
|
||||
BreakpointAddResult,
|
||||
BreakpointStoppedResult,
|
||||
ReadyResult,
|
||||
} from "./../types.js";
|
||||
import invariant from "./../../invariant.js";
|
||||
import { DebuggerError } from "./../DebuggerError.js";
|
||||
|
||||
export class MessageMarshaller {
|
||||
marshallBreakpointAcknowledge(
|
||||
@ -23,8 +32,8 @@ export class MessageMarshaller {
|
||||
return `${requestID} ${prefix} ${filePath} ${line} ${column}`;
|
||||
}
|
||||
|
||||
marshallBreakpointStopped(args: BreakpointArguments): string {
|
||||
return `${args.requestID} ${DebugMessage.BREAKPOINT_STOPPED_RESPONSE} ${args.filePath} ${args.line}:${args.column}`;
|
||||
marshallBreakpointStopped(requestID: number, args: BreakpointArguments): string {
|
||||
return `${requestID} ${DebugMessage.BREAKPOINT_STOPPED_RESPONSE} ${args.filePath} ${args.line} ${args.column}`;
|
||||
}
|
||||
|
||||
marshallPrepackFinish(requestID: number): string {
|
||||
@ -39,8 +48,16 @@ export class MessageMarshaller {
|
||||
return `${requestID} ${DebugMessage.PREPACK_RUN_COMMAND}`;
|
||||
}
|
||||
|
||||
marshallSetBreakpointsRequest(args: BreakpointArguments): string {
|
||||
return `${args.requestID} ${DebugMessage.BREAKPOINT_ADD_COMMAND} ${args.filePath} ${args.line} ${args.column}`;
|
||||
marshallSetBreakpointsRequest(requestID: number, args: BreakpointArguments): string {
|
||||
return `${requestID} ${DebugMessage.BREAKPOINT_ADD_COMMAND} ${args.filePath} ${args.line} ${args.column}`;
|
||||
}
|
||||
|
||||
marshallStackFramesRequest(requestID: number): string {
|
||||
return `${requestID} ${DebugMessage.STACKFRAMES_COMMAND}`;
|
||||
}
|
||||
|
||||
marshallStackFramesResponse(requestID: number, stackframes: Array<Stackframe>) {
|
||||
return `${requestID} ${DebugMessage.STACKFRAMES_RESPONSE} ${JSON.stringify(stackframes)}`;
|
||||
}
|
||||
|
||||
unmarshallBreakpointArguments(requestID: number, parts: Array<string>): BreakpointArguments {
|
||||
@ -55,7 +72,6 @@ export class MessageMarshaller {
|
||||
}
|
||||
|
||||
let result: BreakpointArguments = {
|
||||
requestID: requestID,
|
||||
kind: "breakpoint",
|
||||
filePath: filePath,
|
||||
line: lineNum,
|
||||
@ -63,4 +79,71 @@ export class MessageMarshaller {
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
unmarshallStackframesResponse(requestID: number, responseBody: string): DebuggerResponse {
|
||||
try {
|
||||
let frames = JSON.parse(responseBody);
|
||||
invariant(Array.isArray(frames), "Stack frames is not an array");
|
||||
for (const frame of frames) {
|
||||
invariant(frame.hasOwnProperty("id"), "Stack frame is missing id");
|
||||
invariant(frame.hasOwnProperty("fileName"), "Stack frame is missing filename");
|
||||
invariant(frame.hasOwnProperty("line"), "Stack frame is missing line number");
|
||||
invariant(frame.hasOwnProperty("column"), "Stack frame is missing column number");
|
||||
invariant(frame.hasOwnProperty("functionName"), "Stack frame is missing function name");
|
||||
}
|
||||
let result: StackframeResult = {
|
||||
kind: "stackframe",
|
||||
stackframes: frames,
|
||||
};
|
||||
let dbgResponse: DebuggerResponse = {
|
||||
id: requestID,
|
||||
result: result,
|
||||
};
|
||||
return dbgResponse;
|
||||
} catch (e) {
|
||||
throw new DebuggerError("Invalid response", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
unmarshallBreakpointAddResponse(requestID: number): DebuggerResponse {
|
||||
let result: BreakpointAddResult = {
|
||||
kind: "breakpoint-add",
|
||||
};
|
||||
let dbgResponse: DebuggerResponse = {
|
||||
id: requestID,
|
||||
result: result,
|
||||
};
|
||||
return dbgResponse;
|
||||
}
|
||||
|
||||
unmarshallBreakpointStoppedResponse(requestID: number, parts: Array<string>): DebuggerResponse {
|
||||
invariant(parts.length === 3, "Incorrect number of arguments in breakpoint stopped response");
|
||||
let filePath = parts[0];
|
||||
let line = parseInt(parts[1], 10);
|
||||
invariant(!isNaN(line), "Invalid line number");
|
||||
let column = parseInt(parts[2], 10);
|
||||
invariant(!isNaN(column), "Invalid column number");
|
||||
let result: BreakpointStoppedResult = {
|
||||
kind: "breakpoint-stopped",
|
||||
filePath: filePath,
|
||||
line: line,
|
||||
column: column,
|
||||
};
|
||||
let dbgResponse: DebuggerResponse = {
|
||||
id: requestID,
|
||||
result: result,
|
||||
};
|
||||
return dbgResponse;
|
||||
}
|
||||
|
||||
unmarshallReadyResponse(requestID: number): DebuggerResponse {
|
||||
let result: ReadyResult = {
|
||||
kind: "ready",
|
||||
};
|
||||
let dbgResponse: DebuggerResponse = {
|
||||
id: requestID,
|
||||
result: result,
|
||||
};
|
||||
return dbgResponse;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import readline from "readline";
|
||||
import child_process from "child_process";
|
||||
import * as DebugProtocol from "vscode-debugprotocol";
|
||||
import { DataHandler } from "./DataHandler.js";
|
||||
import { DebuggerConstants } from "./../DebuggerConstants";
|
||||
|
||||
//separator for messages according to the protocol
|
||||
const TWO_CRLF = "\r\n\r\n";
|
||||
@ -131,6 +132,20 @@ export class UISession {
|
||||
_processResponse(response: DebugProtocol.Response) {
|
||||
if (response.command === "threads") {
|
||||
this._processThreadsResponse(((response: any): DebugProtocol.ThreadsResponse));
|
||||
} else if (response.command === "stackTrace") {
|
||||
//flow doesn't have type refinement for interfaces, so must do a cast here
|
||||
this._processStackTraceResponse(((response: any): DebugProtocol.StackTraceResponse));
|
||||
}
|
||||
}
|
||||
|
||||
_processStackTraceResponse(response: DebugProtocol.StackTraceResponse) {
|
||||
let frames = response.body.stackFrames;
|
||||
for (const frame of frames) {
|
||||
if (frame.source && frame.source.path) {
|
||||
this._uiOutput(`${frame.id}: ${frame.name} ${frame.source.path} ${frame.line}:${frame.column}`);
|
||||
} else {
|
||||
this._uiOutput(`${frame.id}: ${frame.name} unknown source`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +170,7 @@ export class UISession {
|
||||
if (parts.length !== 1) return false;
|
||||
let continueArgs: DebugProtocol.ContinueArguments = {
|
||||
// Prepack will only have 1 thread, this argument will be ignored
|
||||
threadId: 1,
|
||||
threadId: DebuggerConstants.PREPACK_THREAD_ID,
|
||||
};
|
||||
this._sendContinueRequest(continueArgs);
|
||||
break;
|
||||
@ -174,6 +189,14 @@ export class UISession {
|
||||
this._sendBreakpointRequest(filePath, line, column);
|
||||
}
|
||||
break;
|
||||
case "stackframes":
|
||||
// format: stackFrames
|
||||
let stackFrameArgs: DebugProtocol.StackTraceArguments = {
|
||||
// Prepack will only have 1 thread, this argument will be ignored
|
||||
threadId: DebuggerConstants.PREPACK_THREAD_ID,
|
||||
};
|
||||
this._sendStackFramesRequest(stackFrameArgs);
|
||||
break;
|
||||
case "threads":
|
||||
if (parts.length !== 1) return false;
|
||||
this._sendThreadsRequest();
|
||||
@ -267,6 +290,17 @@ export class UISession {
|
||||
this._packageAndSend(json);
|
||||
}
|
||||
|
||||
_sendStackFramesRequest(args: DebugProtocol.StackTraceArguments) {
|
||||
let message = {
|
||||
type: "request",
|
||||
seq: this._sequenceNum,
|
||||
command: "stackTrace",
|
||||
arguments: args,
|
||||
};
|
||||
let json = JSON.stringify(message);
|
||||
this._packageAndSend(json);
|
||||
}
|
||||
|
||||
_sendThreadsRequest() {
|
||||
let message = {
|
||||
type: "request",
|
||||
|
@ -10,14 +10,14 @@
|
||||
/* @flow */
|
||||
|
||||
export type DebuggerRequest = {
|
||||
id: number,
|
||||
command: string,
|
||||
arguments: DebuggerRequestArguments,
|
||||
};
|
||||
|
||||
export type DebuggerRequestArguments = BreakpointArguments | RunArguments;
|
||||
export type DebuggerRequestArguments = BreakpointArguments | RunArguments | StackframeArguments;
|
||||
|
||||
export type BreakpointArguments = {
|
||||
requestID: number,
|
||||
kind: "breakpoint",
|
||||
filePath: string,
|
||||
line: number,
|
||||
@ -25,6 +25,44 @@ export type BreakpointArguments = {
|
||||
};
|
||||
|
||||
export type RunArguments = {
|
||||
requestID: number,
|
||||
kind: "run",
|
||||
};
|
||||
|
||||
export type StackframeArguments = {
|
||||
kind: "stackframe",
|
||||
};
|
||||
|
||||
export type Stackframe = {
|
||||
id: number,
|
||||
fileName: string,
|
||||
line: number,
|
||||
column: number,
|
||||
functionName: string,
|
||||
};
|
||||
|
||||
export type DebuggerResponse = {
|
||||
id: number,
|
||||
result: DebuggerResponseResult,
|
||||
};
|
||||
|
||||
export type DebuggerResponseResult = ReadyResult | StackframeResult | BreakpointAddResult | BreakpointStoppedResult;
|
||||
|
||||
export type ReadyResult = {
|
||||
kind: "ready",
|
||||
};
|
||||
|
||||
export type StackframeResult = {
|
||||
kind: "stackframe",
|
||||
stackframes: Array<Stackframe>,
|
||||
};
|
||||
|
||||
export type BreakpointAddResult = {
|
||||
kind: "breakpoint-add",
|
||||
};
|
||||
|
||||
export type BreakpointStoppedResult = {
|
||||
kind: "breakpoint-stopped",
|
||||
filePath: string,
|
||||
line: number,
|
||||
column: number,
|
||||
};
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
/* @flow */
|
||||
|
||||
import type { Intrinsics, PropertyBinding, Descriptor } from "./types.js";
|
||||
import type { Intrinsics, PropertyBinding, Descriptor, DebugServerType } from "./types.js";
|
||||
import { CompilerDiagnostic, type ErrorHandlerResult, type ErrorHandler, FatalError } from "./errors.js";
|
||||
import {
|
||||
AbstractObjectValue,
|
||||
@ -44,7 +44,6 @@ import seedrandom from "seedrandom";
|
||||
import { Generator, PreludeGenerator } from "./utils/generator.js";
|
||||
import type { BabelNode, BabelNodeSourceLocation, BabelNodeLVal, BabelNodeStatement } from "babel-types";
|
||||
import * as t from "babel-types";
|
||||
import { DebugServer } from "./debugger/Debugger.js";
|
||||
|
||||
export type Bindings = Map<Binding, void | Value>;
|
||||
export type EvaluationResult = Completion | Reference | Value;
|
||||
@ -267,7 +266,7 @@ export class Realm {
|
||||
|
||||
globalSymbolRegistry: Array<{ $Key: string, $Symbol: SymbolValue }>;
|
||||
|
||||
debuggerInstance: DebugServer | void;
|
||||
debuggerInstance: DebugServerType | void;
|
||||
|
||||
// to force flow to type the annotations
|
||||
isCompatibleWith(compatibility: Compatibility): boolean {
|
||||
|
@ -24,6 +24,7 @@ import type {
|
||||
AbstractObjectValue,
|
||||
} from "./values/index.js";
|
||||
import { ObjectValue } from "./values/index.js";
|
||||
import { BabelNode } from "babel-types";
|
||||
|
||||
export const ElementSize = {
|
||||
Float32: 4,
|
||||
@ -283,3 +284,8 @@ export type ObjectKind =
|
||||
| TypedArrayKind
|
||||
| "ReactElement";
|
||||
// TODO #26 #712: Promises. All kinds of iterators. Generators.
|
||||
|
||||
export type DebugServerType = {
|
||||
checkForActions: BabelNode => void,
|
||||
shutdown: () => void,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user