Skip to content

Commit

Permalink
Provide all scopes with correct receiver information.
Browse files Browse the repository at this point in the history
  • Loading branch information
entlicher committed Apr 30, 2021
1 parent 18d98e8 commit f75348c
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 197 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -510,30 +510,18 @@ private static TruffleScope[] createScopes(JPDADebugger debugger, ObjectVariable
List<TruffleScope> scopes = new LinkedList<>();
int n = varsArr.length;
int i = 0;
if (i < n) {
while (i < n) {
String scopeName = (String) varsArr[i++].createMirrorObject();
boolean scopeFunction = (Boolean) varsArr[i++].createMirrorObject();
int numArgs = (Integer) varsArr[i++].createMirrorObject();
boolean hasReceiver = (Boolean) varsArr[i++].createMirrorObject();
int numVars = (Integer) varsArr[i++].createMirrorObject();
TruffleVariable[] arguments = new TruffleVariable[numArgs];
i = fillVars(debugger, arguments, varsArr, i);
TruffleVariable[] variables = new TruffleVariable[numVars];
i = fillVars(debugger, variables, varsArr, i);
scopes.add(new TruffleScope(scopeName, scopeFunction, arguments, variables));
}
while (i < n) {
// There are further scopes, retrieved lazily
String scopeName = (String) varsArr[i++].createMirrorObject();
boolean scopeFunction = (Boolean) varsArr[i++].createMirrorObject();
boolean hasArgs = (Boolean) varsArr[i++].createMirrorObject();
boolean hasVars = (Boolean) varsArr[i++].createMirrorObject();
ObjectVariable scope = (ObjectVariable) varsArr[i++];
scopes.add(new TruffleScope(scopeName, scopeFunction, hasArgs, hasVars, debugger, scope));
i = fillVars(debugger, variables, varsArr, hasReceiver, i);
scopes.add(new TruffleScope(scopeName, variables));
}
return scopes.toArray(new TruffleScope[scopes.size()]);
}

private static int fillVars(JPDADebugger debugger, TruffleVariable[] vars, Field[] varsArr, int i) {
private static int fillVars(JPDADebugger debugger, TruffleVariable[] vars, Field[] varsArr, boolean hasReceiver, int i) {
for (int vi = 0; vi < vars.length; vi++) {
String name = (String) varsArr[i++].createMirrorObject();
LanguageName language = LanguageName.parse((String) varsArr[i++].createMirrorObject());
Expand All @@ -556,35 +544,12 @@ private static int fillVars(JPDADebugger debugger, TruffleVariable[] vars, Field
valueSourceDef.getUniqueID() != 0L,
valueSource,
typeSourceDef.getUniqueID() != 0L,
typeSource, value);
typeSource, hasReceiver, value);
hasReceiver = false;
}
return i;
}

public static TruffleVariable[][] getScopeArgsAndVars(JPDADebugger debugger, ObjectVariable debugScope) {
JPDAClassType debugAccessor = TruffleDebugManager.getDebugAccessorJPDAClass(debugger);
try {
Variable scopeVars = debugAccessor.invokeMethod(METHOD_GET_SCOPE_VARIABLES,
METHOD_GET_SCOPE_VARIABLES_SGN,
new Variable[] { debugScope });
Field[] varsArr = ((ObjectVariable) scopeVars).getFields(0, Integer.MAX_VALUE);
int n = varsArr.length;
int i = 0;
if (i < n) {
int numArgs = (Integer) varsArr[i++].createMirrorObject();
int numVars = (Integer) varsArr[i++].createMirrorObject();
TruffleVariable[] arguments = new TruffleVariable[numArgs];
i = fillVars(debugger, arguments, varsArr, i);
TruffleVariable[] variables = new TruffleVariable[numVars];
i = fillVars(debugger, variables, varsArr, i);
return new TruffleVariable[][] { arguments, variables };
}
} catch (InvalidExpressionException | NoSuchMethodException ex) {
Exceptions.printStackTrace(ex);
}
return new TruffleVariable[][] { new TruffleVariable[] {}, new TruffleVariable[] {} };
}

private static Supplier<SourcePosition> parseSourceLazy(JPDADebugger debugger, Variable sourceDefVar, JDIVariable codeRefVar) {
return () -> parseSource(debugger,
(String) sourceDefVar.createMirrorObject(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ public interface TruffleVariable {

ObjectVariable setValue(JPDADebugger debugger, String newExpression);

default boolean isReceiver() {
return false;
}

public static TruffleVariable get(Variable var) {
return TruffleVariableImpl.get(var);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,71 +19,26 @@

package org.netbeans.modules.debugger.jpda.truffle.vars.impl;

import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.ObjectVariable;
import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;

/**
* Representation of DebugScope.
*/
public final class TruffleScope {

private final JPDADebugger debugger;
private final String name;
private final boolean function;
private final ObjectVariable debugScope;
private TruffleVariable[] arguments;
private TruffleVariable[] variables;

public TruffleScope(String name, boolean function, TruffleVariable[] arguments, TruffleVariable[] variables) {
public TruffleScope(String name, TruffleVariable[] variables) {
this.name = name;
this.function = function;
this.arguments = arguments;
this.variables = variables;
this.debugger = null;
this.debugScope = null;
}

public TruffleScope(String name, boolean function, boolean hasArgs, boolean hasVars, JPDADebugger debugger, ObjectVariable debugScope) {
this.name = name;
this.function = function;
if (!hasArgs) {
arguments = new TruffleVariable[] {};
}
if (!hasVars) {
variables = new TruffleVariable[] {};
}
this.debugger = debugger;
this.debugScope = debugScope;
}

public String getName() {
return name;
}

public boolean isFunction() {
return function;
}

public synchronized TruffleVariable[] getArguments() {
if (arguments == null) {
loadArgsAndVars();
}
return arguments;
}

public synchronized TruffleVariable[] getVariables() {
if (variables == null) {
loadArgsAndVars();
}
return variables;
}

private void loadArgsAndVars() {
assert Thread.holdsLock(this);
TruffleVariable[][] argsAndVars = TruffleAccess.getScopeArgsAndVars(debugger, debugScope);
arguments = argsAndVars[0];
variables = argsAndVars[1];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ public class TruffleStackVariable implements TruffleVariable {
private SourcePosition valueSource;
private SourcePosition typeSource;
private ObjectVariable guestObj;
private final boolean isReceiver;
private boolean leaf;

public TruffleStackVariable(JPDADebugger debugger, String name, LanguageName language,
String type, boolean readable, boolean writable, boolean internal,
String valueStr, boolean hasValueSource, Supplier<SourcePosition> valueSource,
boolean hasTypeSource, Supplier<SourcePosition> typeSource,
ObjectVariable truffleObj) {
boolean isReceiver, ObjectVariable truffleObj) {
this.debugger = debugger;
this.name = name;
this.language = language;
Expand All @@ -63,6 +64,7 @@ public TruffleStackVariable(JPDADebugger debugger, String name, LanguageName lan
this.valueSourceSupp = valueSource;
this.typeSourceSupp = typeSource;
this.guestObj = truffleObj;
this.isReceiver = isReceiver;
this.leaf = TruffleVariableImpl.isLeaf(truffleObj);
}

Expand Down Expand Up @@ -162,4 +164,9 @@ public boolean isLeaf() {
public Object[] getChildren() {
return TruffleVariableImpl.getChildren(guestObj);
}

@Override
public boolean isReceiver() {
return isReceiver;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
})
public class TruffleVariablesNodeModel implements ExtendedNodeModelFilter {

private static final String SCOPE_ICON = "org/netbeans/modules/debugger/resources/threadsView/call_stack_16.png";

@Override
public boolean canRename(ExtendedNodeModel original, Object node) throws UnknownTypeException {
return original.canRename(node);
Expand Down Expand Up @@ -88,12 +90,14 @@ public void setName(ExtendedNodeModel original, Object node, String name) throws
@Override
public String getIconBaseWithExtension(ExtendedNodeModel original, Object node) throws UnknownTypeException {
if (node instanceof TruffleVariable) {
String name = ((TruffleVariable) node).getName();
if ("this".equals(name)) {
TruffleVariable var = (TruffleVariable) node;
if (var.isReceiver()) {
return original.getIconBaseWithExtension(EmptyThis.INSTANCE);
} else {
return original.getIconBaseWithExtension(EmptyVar.INSTANCE);
}
} else if (node instanceof TruffleScope) {
return SCOPE_ICON;
}
return original.getIconBaseWithExtension(node);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,73 +342,46 @@ static boolean setUnwind(int depth) {
}

// An array of scopes and their variables:
// <scope name>, <is functional>, <num args>, <num vars>, [(num args)+(num vars) variables]
// Variable: 11 elements: <name>, <type>, <readable>, <writable>, <internal>, <String value>,
// <var source>, <VS code>, <type source>, <TS code>, <DebugValue>
// Parent scopes: <scope name>, <is functional>, <has args>, <has vars>, <DebugScope>
// <scope name>, <has receiver>, <num vars (including receiver, if any)>, [receiver + variables]
// See addValueElement() for the variable format
static Object[] getVariables(DebugStackFrame sf) {
List<Object> elements = new ArrayList<>();
try {
DebugScope scope = sf.getScope();
while (scope != null) {
Iterable<DebugValue> argsIt = scope.getArguments();
Iterator<DebugValue> args;
if (argsIt != null) {
args = argsIt.iterator();
} else {
args = null;
DebugScope receiverScope = null;
for (DebugScope scope = sf.getScope(); scope != null; scope = scope.getParent()) {
DebugValue receiver = scope.getReceiver();
boolean hasReceiver = receiver != null;
List<DebugValue> variables = new ArrayList<>();
if (hasReceiver) {
variables.add(receiver);
if (receiverScope == null) {
receiverScope = scope;
}
}
Iterable<DebugValue> varsIt = scope.getDeclaredValues();
Iterator<DebugValue> vars = varsIt.iterator();
DebugValue receiver = scope.isFunctionScope() ? scope.getReceiver() : null;
if ((args == null || !args.hasNext()) && !vars.hasNext() && receiver == null) {
// An empty scope, skip it
scope = scope.getParent();
if (!vars.hasNext()) {
continue;
}
elements.add(scope.getName());
elements.add(scope.isFunctionScope());
List<DebugValue> arguments = null;
if (args != null && args.hasNext()) {
arguments = new ArrayList<>();
while (args.hasNext()) {
arguments.add(args.next());
}
elements.add(arguments.size());
} else {
elements.add(0);
}
List<DebugValue> variables = new ArrayList<>();
while (vars.hasNext()) {
variables.add(vars.next());
}
if (receiver != null) {
variables.add(receiver);
if (variables.isEmpty()) {
continue;
}
elements.add(scope.getName());
elements.add(hasReceiver);
elements.add(variables.size());
if (arguments != null) {
for (DebugValue v : arguments) {
addValueElement(v, elements);
}
}
for (DebugValue v : variables) {
addValueElement(v, elements);
}
// We've filled the first scope in.
break;
}

if (scope != null) {
while ((scope = scope.getParent()) != null) {
elements.add(scope.getName());
elements.add(scope.isFunctionScope());
Iterable<DebugValue> args = scope.getArguments();
boolean hasArgs = (args != null && args.iterator().hasNext());
elements.add(hasArgs);
boolean hasVars = scope.getDeclaredValues().iterator().hasNext();
elements.add(hasVars);
elements.add(scope);
}
if (elements.isEmpty() && receiverScope != null) {
// No variables, provide the receiver, at least:
elements.add(receiverScope.getName());
elements.add(true);
elements.add(1);
addValueElement(receiverScope.getReceiver(), elements);
}
} catch (ThreadDeath td) {
throw td;
Expand All @@ -421,62 +394,6 @@ static Object[] getVariables(DebugStackFrame sf) {
return variables;
}

// An array of scope's arguments and variables:
// <num args>, <num vars>, [(num args)+(num vars) variables]
// Variable: 11 elements: <name>, <type>, <readable>, <writable>, <internal>, <String value>,
// <var source>, <VS code>, <type source>, <TS code>, <DebugValue>
static Object[] getScopeVariables(DebugScope scope) {
List<Object> elements = new ArrayList<>();
try {
Iterable<DebugValue> argsIt = scope.getArguments();
Iterator<DebugValue> args;
if (argsIt != null) {
args = argsIt.iterator();
} else {
args = null;
}
Iterable<DebugValue> varsIt = scope.getDeclaredValues();
Iterator<DebugValue> vars = varsIt.iterator();
List<DebugValue> arguments = null;
if (args != null && args.hasNext()) {
arguments = new ArrayList<>();
while (args.hasNext()) {
arguments.add(args.next());
}
elements.add(arguments.size());
} else {
elements.add(0);
}
List<DebugValue> variables = new ArrayList<>();
while (vars.hasNext()) {
variables.add(vars.next());
}
if (scope.isFunctionScope()) {
DebugValue receiver = scope.getReceiver();
if (receiver != null) {
variables.add(receiver);
}
}
elements.add(variables.size());
if (arguments != null) {
for (DebugValue v : arguments) {
addValueElement(v, elements);
}
}
for (DebugValue v : variables) {
addValueElement(v, elements);
}
} catch (ThreadDeath td) {
throw td;
} catch (Throwable t) {
LangErrors.exception("An error when accessing scope "+scope, t);
}
Object[] variables = elements.toArray();
Set<Object> varCache = threadVariablesCache.get();
varCache.add(variables);
return variables;
}

// Store 12 elements: <name>, <language>, <type>, <readable>, <writable>, <internal>, <String value>,
// <var source>, <VS code>, <type source>, <TS code>, <DebugValue>
static void addValueElement(DebugValue value, List<Object> elements) {
Expand Down

0 comments on commit f75348c

Please sign in to comment.