// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.sdk.internal.v8native.processor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.chromium.sdk.Breakpoint;
import org.chromium.sdk.ExceptionData;
import org.chromium.sdk.internal.protocolparser.JsonProtocolParseException;
import org.chromium.sdk.internal.v8native.BreakpointManager;
import org.chromium.sdk.internal.v8native.ContextBuilder;
import org.chromium.sdk.internal.v8native.DebugSession;
import org.chromium.sdk.internal.v8native.InternalContext;
import org.chromium.sdk.internal.v8native.InternalContext.ContextDismissedCheckedException;
import org.chromium.sdk.internal.v8native.protocol.V8Protocol;
import org.chromium.sdk.internal.v8native.protocol.input.BreakEventBody;
import org.chromium.sdk.internal.v8native.protocol.input.EventNotification;
import org.chromium.sdk.internal.v8native.protocol.input.data.SomeHandle;
import org.chromium.sdk.internal.v8native.protocol.input.data.ValueHandle;
import org.chromium.sdk.internal.v8native.protocol.output.DebuggerMessage;
import org.chromium.sdk.internal.v8native.protocol.output.DebuggerMessageFactory;
import org.chromium.sdk.internal.v8native.value.ExceptionDataImpl;
import org.chromium.sdk.internal.v8native.value.ValueLoaderImpl;
import org.chromium.sdk.internal.v8native.value.ValueMirror;
/**
* Handles the suspension-related V8 command replies and events.
*/
public class BreakpointProcessor extends V8EventProcessor {
/** The name of the "exception" object to report as a variable name. */
private static final String EXCEPTION_NAME = "exception";
public BreakpointProcessor(DebugSession debugSession) {
super(debugSession);
}
@Override
public void messageReceived(EventNotification eventMessage) {
final boolean isEvent = true;
if (isEvent) {
String event = eventMessage.event();
DebugSession debugSession = getDebugSession();
ContextBuilder contextBuilder = debugSession.getContextBuilder();
ContextBuilder.ExpectingBreakEventStep step1 = contextBuilder.buildNewContext();
InternalContext internalContext = step1.getInternalContext();
BreakEventBody breakEventBody;
try {
breakEventBody = eventMessage.body().asBreakEventBody();
} catch (JsonProtocolParseException e) {
throw new RuntimeException(e);
}
ContextBuilder.ExpectingBacktraceStep step2;
if (V8Protocol.EVENT_BREAK.key.equals(event)) {
Collection<Breakpoint> breakpointsHit = getBreakpointsHit(eventMessage, breakEventBody);
step2 = step1.setContextState(breakpointsHit, null);
} else if (V8Protocol.EVENT_EXCEPTION.key.equals(event)) {
ExceptionData exception = createException(eventMessage, breakEventBody,
internalContext);
step2 = step1.setContextState(Collections.<Breakpoint> emptySet(), exception);
} else {
contextBuilder.buildSequenceFailure();
throw new RuntimeException();
}
processNextStep(step2);
}
}
public void processNextStep(ContextBuilder.ExpectingBacktraceStep step2) {
BacktraceProcessor backtraceProcessor = new BacktraceProcessor(step2);
InternalContext internalContext = step2.getInternalContext();
DebuggerMessage message = DebuggerMessageFactory.backtrace(null, null, true);
try {
// Command is not immediate because we are supposed to be suspended.
internalContext.sendV8CommandAsync(message, false, backtraceProcessor, null);
} catch (ContextDismissedCheckedException e) {
// Can't happen -- we are just creating context, it couldn't have become invalid
throw new RuntimeException(e);
}
}
private Collection<Breakpoint> getBreakpointsHit(EventNotification response,
BreakEventBody breakEventBody) {
List<Long> breakpointIdsArray = breakEventBody.breakpoints();
BreakpointManager breakpointManager = getDebugSession().getBreakpointManager();
if (breakpointIdsArray == null) {
// Suspended on step end.
return Collections.<Breakpoint> emptySet();
}
Collection<Breakpoint> breakpointsHit = new ArrayList<Breakpoint>(breakpointIdsArray.size());
for (int i = 0, size = breakpointIdsArray.size(); i < size; ++i) {
Breakpoint existingBp = breakpointManager.getBreakpoint(breakpointIdsArray.get(i));
if (existingBp != null) {
breakpointsHit.add(existingBp);
}
}
return breakpointsHit;
}
private ExceptionData createException(EventNotification response, BreakEventBody body,
InternalContext internalContext) {
List<SomeHandle> refs = response.refs();
ValueHandle exception = body.exception();
ValueLoaderImpl valueLoader = internalContext.getValueLoader();
for (SomeHandle handle : refs) {
valueLoader.addHandleFromRefs(handle);
}
valueLoader.addHandleFromRefs(exception.getSuper());
// source column is not exposed ("sourceColumn" in "body")
String sourceText = body.sourceLineText();
ValueMirror mirror = valueLoader.addDataToMap(exception);
return new ExceptionDataImpl(internalContext,
mirror,
EXCEPTION_NAME,
body.uncaught(),
sourceText,
exception.text());
}
}