blob: 6ef5d691a03105d56f3469c9e10ae7c564ce227e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.debugger.jpda.truffle.frames;
import com.sun.jdi.StringReference;
import java.io.InvalidObjectException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.debugger.jpda.InvalidExpressionException;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.JPDAThread;
import org.netbeans.api.debugger.jpda.ObjectVariable;
import org.netbeans.modules.debugger.jpda.truffle.LanguageName;
import org.netbeans.modules.debugger.jpda.truffle.access.CurrentPCInfo;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.source.Source;
import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
import org.openide.util.Exceptions;
/**
*
* @author Martin
*/
public final class TruffleStackFrame {
private static final Logger LOG = Logger.getLogger(TruffleStackFrame.class.getName());
private final JPDADebugger debugger;
private final JPDAThread thread;
private final int depth;
private final ObjectVariable frameInstance;
private final String methodName;
private final LanguageName language;
private final String sourceLocation;
private final int sourceId;
private final String sourceName;
private final String sourcePath;
private final URI sourceURI;
private final String sourceSection;
private final StringReference codeRef;
private TruffleScope[] scopes;
private final ObjectVariable thisObject;
private final boolean isInternal;
public TruffleStackFrame(JPDADebugger debugger, JPDAThread thread, int depth,
ObjectVariable frameInstance,
String frameDefinition, StringReference codeRef,
TruffleScope[] scopes, ObjectVariable thisObject,
boolean includeInternal) {
if (LOG.isLoggable(Level.FINE)) {
try {
LOG.fine("new TruffleStackFrame("+depth+", "+
frameInstance.getToStringValue()+" of type "+frameInstance.getClassType().getName()+
", "+frameDefinition+", vars = "+Arrays.toString(scopes)+
", "+thisObject+")");
} catch (InvalidExpressionException iex) {
LOG.log(Level.FINE, iex.getMessage(), iex);
}
}
this.debugger = debugger;
this.thread = thread;
this.depth = depth;
this.frameInstance = frameInstance;
boolean internalFrame = includeInternal;
try {
int i1 = 0;
int i2 = frameDefinition.indexOf('\n');
methodName = frameDefinition.substring(i1, i2);
i1 = i2 + 1;
i2 = frameDefinition.indexOf('\n', i1);
language = LanguageName.parse(frameDefinition.substring(i1, i2));
i1 = i2 + 1;
i2 = frameDefinition.indexOf('\n', i1);
sourceLocation = frameDefinition.substring(i1, i2);
i1 = i2 + 1;
i2 = frameDefinition.indexOf('\n', i1);
sourceId = Integer.parseInt(frameDefinition.substring(i1, i2));
i1 = i2 + 1;
i2 = frameDefinition.indexOf('\n', i1);
sourceName = frameDefinition.substring(i1, i2);
i1 = i2 + 1;
i2 = frameDefinition.indexOf('\n', i1);
sourcePath = frameDefinition.substring(i1, i2);
i1 = i2 + 1;
i2 = frameDefinition.indexOf('\n', i1);
try {
sourceURI = new URI(frameDefinition.substring(i1, i2));
} catch (URISyntaxException usex) {
throw new IllegalStateException("Bad URI: "+frameDefinition.substring(i1, i2), usex);
}
i1 = i2 + 1;
if (includeInternal) {
i2 = frameDefinition.indexOf('\n', i1);
sourceSection = frameDefinition.substring(i1, i2);
i1 = i2 + 1;
internalFrame = Boolean.valueOf(frameDefinition.substring(i1));
} else {
sourceSection = frameDefinition.substring(i1);
}
} catch (IndexOutOfBoundsException ioob) {
throw new IllegalStateException("frameDefinition='"+frameDefinition+"'", ioob);
}
this.codeRef = codeRef;
this.scopes = scopes;
this.thisObject = thisObject;
this.isInternal = internalFrame;
}
public final JPDADebugger getDebugger() {
return debugger;
}
public final JPDAThread getThread() {
return thread;
}
public final int getDepth() {
return depth;
}
public String getMethodName() {
return methodName;
}
public LanguageName getLanguage() {
return language;
}
public String getSourceLocation() {
return sourceLocation;
}
public String getDisplayName() {
if (!methodName.isEmpty()) {
return methodName + " ("+sourceLocation+")";
} else {
return sourceLocation;
}
}
public SourcePosition getSourcePosition() {
Source src = Source.getExistingSource(debugger, sourceId);
if (src == null) {
src = Source.getSource(debugger, sourceId, sourceName, sourcePath, sourceURI, codeRef);
}
SourcePosition sp = new SourcePosition(debugger, sourceId, src, sourceSection);
return sp;
}
public ObjectVariable getStackFrameInstance() {
return frameInstance;// also is: (ObjectVariable) stackTrace.getFields(0, Integer.MAX_VALUE)[depth - 1];
}
public TruffleScope[] getScopes() {
if (scopes == null) {
scopes = TruffleAccess.createFrameScopes(debugger, /*suspendedInfo,*/ getStackFrameInstance());
}
return scopes;
}
public void popToHere() {
if (depth > 0) {
boolean unwindScheduled = TruffleAccess.unwind(debugger, thread, depth - 1);
if (unwindScheduled) {
CurrentPCInfo currentPCInfo = TruffleAccess.getCurrentPCInfo(thread);
try {
currentPCInfo.getStepCommandVar().setFromMirrorObject(-1);
thread.resume();
} catch (InvalidObjectException ex) {
Exceptions.printStackTrace(ex);
}
}
}
}
public ObjectVariable getThis() {
return thisObject;
}
public boolean isInternal() {
return isInternal;
}
}