This is an automated email from the ASF dual-hosted git repository.

skygo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 4243806  NETBEANS-4209: Update Truffle debugging for GraalVM 20.1.0, 
fixed a number of issues including NETBEANS-4208 and small corrections.
     new 5222352  Merge pull request #2100 from 
entlicher/TruffleDebugUpdate2020-04
4243806 is described below

commit 4243806f737510f1909272e49c7cd91710f7d253
Author: Martin Entlicher <martin.entlic...@oracle.com>
AuthorDate: Thu Apr 23 15:18:51 2020 +0200

    NETBEANS-4209: Update Truffle debugging for GraalVM 20.1.0, fixed a number 
of issues including NETBEANS-4208 and small corrections.
---
 .../debugger/jpda/truffle/DebugManagerHandler.java | 55 ++++++++++++-
 .../debugger/jpda/truffle/LanguageName.java        | 73 ++++++++++++++++++
 .../jpda/truffle/access/TruffleAccess.java         | 48 ++++++++----
 .../jpda/truffle/access/TruffleStrataProvider.java |  4 +-
 .../debugger/jpda/truffle/ast/TruffleNode.java     | 34 ++++----
 .../jpda/truffle/ast/model/ASTNodeModel.java       | 10 +--
 .../truffle/ast/model/ASTTreeExpansionModel.java   |  2 +-
 .../breakpoints/TruffleBreakpointsHandler.java     | 11 ++-
 .../jpda/truffle/frames/TruffleStackFrame.java     | 18 +++--
 .../models/DebuggingTruffleActionsProvider.java    |  2 +-
 .../frames/models/DebuggingTruffleTreeModel.java   |  2 +-
 .../jpda/truffle/source/SourcePosition.java        | 36 +++++++--
 .../jpda/truffle/vars/TruffleStackVariable.java    | 35 ++++++++-
 .../jpda/truffle/vars/TruffleVariable.java         |  9 ++-
 .../jpda/truffle/vars/TruffleVariableImpl.java     | 44 ++++++++++-
 .../TruffleVariablesActionsProviderFilter.java     | 50 ++++++------
 .../vars/models/TruffleVariablesTableModel.java    | 90 +++++++++++++++++-----
 .../vars/models/TruffleVariablesTreeModel.java     |  3 +-
 .../modules/debugger/jpda/truffle/DebugSLTest.java |  4 +-
 .../debugger/jpda/truffle/testapps/SLApp.java      |  2 +-
 .../debugger/jpda/backend/truffle/FrameInfo.java   |  8 +-
 .../debugger/jpda/backend/truffle/GuestObject.java | 62 ++++++++-------
 .../jpda/backend/truffle/JPDATruffleAccessor.java  | 47 +++++++----
 .../backend/truffle/JPDATruffleDebugManager.java   | 27 +++----
 .../jpda/backend/truffle/SourcePosition.java       | 19 +++--
 .../debugger/jpda/backend/truffle/TruffleAST.java  | 29 ++++---
 26 files changed, 530 insertions(+), 194 deletions(-)

diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/DebugManagerHandler.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/DebugManagerHandler.java
index a6b2e81..385b411 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/DebugManagerHandler.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/DebugManagerHandler.java
@@ -33,6 +33,8 @@ import com.sun.jdi.ThreadReference;
 import com.sun.jdi.Value;
 import com.sun.jdi.VirtualMachine;
 
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.beans.PropertyVetoException;
 import java.io.IOException;
 import java.util.Arrays;
@@ -64,6 +66,7 @@ import 
org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
 import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
 import static 
org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess.BASIC_CLASS_NAME;
 import 
org.netbeans.modules.debugger.jpda.truffle.breakpoints.TruffleBreakpointsHandler;
+import org.netbeans.modules.debugger.jpda.truffle.options.TruffleOptions;
 import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
 import org.openide.util.Exceptions;
 
@@ -78,8 +81,10 @@ final class DebugManagerHandler {
     private static final String ACCESSOR_LOOP_RUNNING_FIELD = 
"accessLoopRunning";  // NOI18N
     private static final String ACCESSOR_SET_UP_DEBUG_MANAGER_FOR = 
"setUpDebugManagerFor"; // NOI18N
     private static final String ACCESSOR_SET_UP_DEBUG_MANAGER_FOR_SGN =
-            "(L"+Object.class.getName().replace('.', '/')+";Z)"+               
 // NOI18N
+            "(L"+Object.class.getName().replace('.', '/')+";ZZ)"+              
  // NOI18N
             
"Lorg/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleDebugManager;"; 
// NOI18N
+    private static final String ACCESSOR_SET_INCLUDE_INTERNAL = 
"setIncludeInternal"; // NOI18N
+    private static final String ACCESSOR_SET_INCLUDE_INTERNAL_SGN = "(Z)V"; // 
NOI18N
     
     private static final Map<JPDADebugger, Boolean> dbgStepInto = 
Collections.synchronizedMap(new WeakHashMap<JPDADebugger, Boolean>());
 
@@ -90,10 +95,12 @@ final class DebugManagerHandler {
     private final Object accessorClassLock = new Object();
     //private ObjectReference debugManager;
     private final TruffleBreakpointsHandler breakpointsHandler;
+    private final PropertyChangeListener optionsChangeListener = new 
OptionsChangeListener();
     
     public DebugManagerHandler(JPDADebugger debugger) {
         this.debugger = debugger;
         this.breakpointsHandler = new TruffleBreakpointsHandler(debugger);
+        TruffleOptions.onLanguageDeveloperModeChange(optionsChangeListener);
     }
     
     static void execStepInto(JPDADebugger debugger, boolean doStepInto) {
@@ -127,13 +134,14 @@ final class DebugManagerHandler {
             if (vm == null) {
                 return ;
             }
+            BooleanValue includeInternal = 
vm.mirrorOf(TruffleOptions.isLanguageDeveloperMode());
             BooleanValue doStepInto = vm.mirrorOf(isStepInto());
             Method debugManagerMethod = ClassTypeWrapper.concreteMethodByName(
                     accessorClass,
                     ACCESSOR_SET_UP_DEBUG_MANAGER_FOR,
                     ACCESSOR_SET_UP_DEBUG_MANAGER_FOR_SGN);
             ThreadReference tr = thread.getThreadReference();
-            List<Value> dmArgs = Arrays.asList(engine, doStepInto);
+            List<Value> dmArgs = Arrays.asList(engine, includeInternal, 
doStepInto);
             LOG.log(Level.FINE, "Setting engine and step into = {0}", 
isStepInto());
             Object ret = ClassTypeWrapper.invokeMethod(accessorClass, tr, 
debugManagerMethod, dmArgs, ObjectReference.INVOKE_SINGLE_THREADED);
             if (ret instanceof ObjectReference) {   // Can be null when an 
existing debug manager is reused.
@@ -286,4 +294,47 @@ final class DebugManagerHandler {
     void breakpointRemoved(JSLineBreakpoint jsLineBreakpoint) {
         breakpointsHandler.breakpointRemoved(jsLineBreakpoint);
     }
+
+    private final class OptionsChangeListener implements 
PropertyChangeListener {
+
+        @Override
+        public void propertyChange(PropertyChangeEvent evt) {
+            if (accessorClass == null) {
+                // No accessor
+                return ;
+            }
+            if 
(TruffleOptions.PROPERTY_LANG_DEV_MODE.equals(evt.getPropertyName())) {
+                JPDADebuggerImpl debuggerImpl = (JPDADebuggerImpl) debugger;
+                debuggerImpl.getRequestProcessor().post(() -> {
+                    VirtualMachine vm = debuggerImpl.getVirtualMachine();
+                    if (vm == null) {
+                        return ;
+                    }
+                    BooleanValue includeInternal = 
vm.mirrorOf(TruffleOptions.isLanguageDeveloperMode());
+                    try {
+                        Method debugManagerMethod = 
ClassTypeWrapper.concreteMethodByName(
+                                accessorClass,
+                                ACCESSOR_SET_INCLUDE_INTERNAL,
+                                ACCESSOR_SET_INCLUDE_INTERNAL_SGN);
+                        TruffleAccess.methodCallingAccess(debugger, new 
TruffleAccess.MethodCallsAccess() {
+                            @Override
+                            public void callMethods(JPDAThread thread) throws 
InvocationException {
+                                ThreadReference tr = ((JPDAThreadImpl) 
thread).getThreadReference();
+                                List<Value> dmArgs = 
Arrays.asList(includeInternal);
+                                LOG.log(Level.FINE, "Setting includeInternal 
to {0}", includeInternal.value());
+                                try {
+                                    
ClassTypeWrapper.invokeMethod(accessorClass, tr, debugManagerMethod, dmArgs, 
ObjectReference.INVOKE_SINGLE_THREADED);
+                                } catch (Exception ex) {
+                                    Exceptions.printStackTrace(ex);
+                                }
+                            }
+                        });
+                    } catch (ClassNotPreparedExceptionWrapper | 
InternalExceptionWrapper | VMDisconnectedExceptionWrapper ex) {
+                        Exceptions.printStackTrace(ex);
+                    }
+                });
+            }
+        }
+        
+    }
 }
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/LanguageName.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/LanguageName.java
new file mode 100644
index 0000000..889a2d5
--- /dev/null
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/LanguageName.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import java.util.Objects;
+
+/**
+ *
+ * @author Martin
+ */
+public final class LanguageName {
+
+    public static final LanguageName NONE = new LanguageName("", "");
+
+    private final String id;
+    private final String name;
+
+    private LanguageName(String id, String name) {
+        this.id = id;
+        this.name = name;
+    }
+
+    public static LanguageName parse(String string) {
+        string = string.trim();
+        if (string.isEmpty()) {
+            return NONE;
+        }
+        int i = string.indexOf(" ");
+        assert i > 0 : string;
+        return new LanguageName(string.substring(0, i), string.substring(i + 
1));
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.id);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final LanguageName other = (LanguageName) obj;
+        return this.id.equals(other.id);
+    }
+
+}
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleAccess.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleAccess.java
index 386d565..7450372 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleAccess.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleAccess.java
@@ -57,6 +57,7 @@ import 
org.netbeans.modules.debugger.jpda.expr.InvocationExceptionTranslated;
 import org.netbeans.modules.debugger.jpda.expr.JDIVariable;
 import org.netbeans.modules.debugger.jpda.models.JPDAClassTypeImpl;
 import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
+import org.netbeans.modules.debugger.jpda.truffle.LanguageName;
 import org.netbeans.modules.debugger.jpda.truffle.RemoteServices;
 import org.netbeans.modules.debugger.jpda.truffle.TruffleDebugManager;
 import org.netbeans.modules.debugger.jpda.truffle.actions.StepActionProvider;
@@ -90,7 +91,7 @@ public class TruffleAccess implements JPDABreakpointListener {
     private static final String VAR_SRC_URI = "uri";                           
 // NOI18N
     private static final String VAR_SRC_NAME = "name";                         
 // NOI18N
     private static final String VAR_SRC_PATH = "path";                         
 // NOI18N
-    private static final String VAR_SRC_LINE = "line";                         
 // NOI18N
+    private static final String VAR_SRC_SOURCESECTION = "sourceSection";       
 // NOI18N
     private static final String VAR_SRC_CODE = "code";
     private static final String VAR_STACK_TRACE = "stackTrace";
     private static final String VAR_TOP_FRAME = "topFrame";                    
 // NOI18N
@@ -231,7 +232,7 @@ public class TruffleAccess implements 
JPDABreakpointListener {
             TruffleStackFrame topFrame = new TruffleStackFrame(debugger, 
thread, 0, frame, topFrameDescription, null/*code*/, scopes, thisObject, true);
             TruffleStackInfo stack = new TruffleStackInfo(debugger, thread, 
stackTrace);
             return new CurrentPCInfo(haltedInfo.stepCmd, thread, sp, scopes, 
topFrame, stack, depth -> {
-                return getTruffleAST(debugger, (JPDAThreadImpl) thread, depth, 
sp.getLine(), stack);
+                return getTruffleAST(debugger, (JPDAThreadImpl) thread, depth, 
sp, stack);
             });
         } catch (AbsentInformationException | IllegalStateException ex) {
             Exceptions.printStackTrace(ex);
@@ -239,7 +240,7 @@ public class TruffleAccess implements 
JPDABreakpointListener {
         }
     }
 
-    private static TruffleNode getTruffleAST(JPDADebugger debugger, 
JPDAThreadImpl thread, int depth, int topLine, TruffleStackInfo stack) {
+    private static TruffleNode getTruffleAST(JPDADebugger debugger, 
JPDAThreadImpl thread, int depth, SourcePosition topPosition, TruffleStackInfo 
stack) {
         JPDAClassType debugAccessor = 
TruffleDebugManager.getDebugAccessorJPDAClass(debugger);
         Lock lock = thread.accessLock.writeLock();
         lock.lock();
@@ -273,8 +274,17 @@ public class TruffleAccess implements 
JPDABreakpointListener {
                                                       METHOD_GET_AST_SGN,
                                                       new Variable[] { 
debugger.createMirrorVar(depth, true) });
             Variable[] astInfo = ((ObjectVariable) ast).getFields(0, 
Integer.MAX_VALUE);
-            int line = (depth == 0) ? topLine : 
stack.getStackFrames(true)[depth].getSourcePosition().getLine();
-            return TruffleNode.newBuilder().nodes((String) 
astInfo[0].createMirrorObject()).currentLine(line).build();
+            SourcePosition position;
+            if (depth == 0) {
+                position = topPosition;
+            } else {
+                TruffleStackFrame[] stackFrames = stack.getStackFrames(true);
+                if (depth >= stackFrames.length) {
+                    return null;
+                }
+                position = stackFrames[depth].getSourcePosition();
+            }
+            return TruffleNode.newBuilder().nodes((String) 
astInfo[0].createMirrorObject()).currentPosition(position).build();
         } catch (InvalidExpressionException | InvalidObjectException | 
NoSuchMethodException ex) {
             Exceptions.printStackTrace(ex);
             return null;
@@ -292,7 +302,7 @@ public class TruffleAccess implements 
JPDABreakpointListener {
             return null;
         }
         long id = (Long) varSrcId.createMirrorObject();
-        int line = (Integer) 
sourcePositionVar.getField(VAR_SRC_LINE).createMirrorObject();
+        String sourceSection = (String) 
sourcePositionVar.getField(VAR_SRC_SOURCESECTION).createMirrorObject();
         Source src = Source.getExistingSource(debugger, id);
         if (src == null) {
             String name = (String) 
sourcePositionVar.getField(VAR_SRC_NAME).createMirrorObject();
@@ -301,7 +311,7 @@ public class TruffleAccess implements 
JPDABreakpointListener {
             StringReference codeRef = (StringReference) ((JDIVariable) 
sourcePositionVar.getField(VAR_SRC_CODE)).getJDIValue();
             src = Source.getSource(debugger, id, name, path, uri, codeRef);
         }
-        return new SourcePosition(debugger, id, src, line);
+        return new SourcePosition(debugger, id, src, sourceSection);
     }
     
     private static TruffleScope[] createScopes(JPDADebugger debugger, 
ObjectVariable varsArrVar) {
@@ -335,21 +345,27 @@ public class TruffleAccess implements 
JPDABreakpointListener {
     private static int fillVars(JPDADebugger debugger, TruffleVariable[] vars, 
Field[] varsArr, int i) {
         for (int vi = 0; vi < vars.length; vi++) {
             String name = (String) varsArr[i++].createMirrorObject();
+            LanguageName language = LanguageName.parse((String) 
varsArr[i++].createMirrorObject());
             String type = (String) varsArr[i++].createMirrorObject();
             boolean readable = (Boolean) varsArr[i++].createMirrorObject();
             boolean writable = (Boolean) varsArr[i++].createMirrorObject();
             boolean internal = (Boolean) varsArr[i++].createMirrorObject();
             String valueStr = (String) varsArr[i++].createMirrorObject();
+            ObjectVariable valueSourceDef = (ObjectVariable) varsArr[i++];
             Supplier<SourcePosition> valueSource = parseSourceLazy(debugger,
-                                                                   
varsArr[i++],
+                                                                   
valueSourceDef,
                                                                    
(JDIVariable) varsArr[i++]);
+            ObjectVariable typeSourceDef = (ObjectVariable) varsArr[i++];
             Supplier<SourcePosition> typeSource = parseSourceLazy(debugger,
-                                                                  varsArr[i++],
+                                                                  
typeSourceDef,
                                                                   
(JDIVariable) varsArr[i++]);
             ObjectVariable value = (ObjectVariable) varsArr[i++];
-            vars[vi] = new TruffleStackVariable(debugger, name, type, readable,
+            vars[vi] = new TruffleStackVariable(debugger, name, language, 
type, readable,
                                                 writable, internal, valueStr,
-                                                valueSource, typeSource, 
value);
+                                                valueSourceDef.getUniqueID() 
!= 0L,
+                                                valueSource,
+                                                typeSourceDef.getUniqueID() != 
0L,
+                                                typeSource, value);
         }
         return i;
     }
@@ -392,7 +408,7 @@ public class TruffleAccess implements 
JPDABreakpointListener {
         String sourceName;
         String sourcePath;
         URI sourceURI;
-        int sourceLine;
+        String sourceSection;
         try {
             int i1 = 0;
             int i2 = sourceDef.indexOf('\n', i1);
@@ -411,12 +427,16 @@ public class TruffleAccess implements 
JPDABreakpointListener {
                 throw new IllegalStateException("Bad URI: 
"+sourceDef.substring(i1, i2), usex);
             }
             i1 = i2 + 1;
-            sourceLine = Integer.parseInt(sourceDef.substring(i1));
+            i2 = sourceDef.indexOf('\n', i1);
+            if (i2 < 0) {
+                i2 = sourceDef.length();
+            }
+            sourceSection = sourceDef.substring(i1, i2);
         } catch (IndexOutOfBoundsException ioob) {
             throw new IllegalStateException("var source 
definition='"+sourceDef+"'", ioob);
         }
         Source src = Source.getSource(debugger, sourceId, sourceName, 
sourcePath, sourceURI, codeRef);
-        return new SourcePosition(debugger, sourceId, src, sourceLine);
+        return new SourcePosition(debugger, sourceId, src, sourceSection);
     }
     
     public static TruffleScope[] createFrameScopes(final JPDADebugger debugger,
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleStrataProvider.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleStrataProvider.java
index a50f8bb..8a50fed 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleStrataProvider.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/access/TruffleStrataProvider.java
@@ -60,10 +60,10 @@ public class TruffleStrataProvider implements 
StrataProvider {
 
     @Override
     public int getStrataLineNumber(CallStackFrameImpl csf, String stratum) {
-        if (TRUFFLE_STRATUM.equals(stratum)) {
+        if (TRUFFLE_STRATUM.equals(stratum) && isInTruffleAccessPoint(csf)) {
             CurrentPCInfo currentPCInfo = 
TruffleAccess.getCurrentPCInfo(csf.getThread());
             if (currentPCInfo != null) {
-                return currentPCInfo.getSourcePosition().getLine();
+                return currentPCInfo.getSourcePosition().getStartLine();
             }
         }
         return csf.getLineNumber(stratum);
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/TruffleNode.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/TruffleNode.java
index 0eaeea1..134534a 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/TruffleNode.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/TruffleNode.java
@@ -19,6 +19,8 @@
 
 package org.netbeans.modules.debugger.jpda.truffle.ast;
 
+import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
+
 /**
  * A representation of Truffle Node class.
  */
@@ -34,6 +36,7 @@ public final class TruffleNode {
     private final String tags;
     private final TruffleNode[] ch;
     private boolean current;
+    private boolean currentEncapsulating;
 
     public TruffleNode(String className, String description, String sourceURI, 
int l1, int c1, int l2, int c2, String tags, int numCh) {
         this.className = className;
@@ -101,6 +104,10 @@ public final class TruffleNode {
         return current;
     }
 
+    public boolean isCurrentEncapsulating() {
+        return currentEncapsulating;
+    }
+
     public static Builder newBuilder() {
         return new Builder();
     }
@@ -108,7 +115,7 @@ public final class TruffleNode {
     public static class Builder {
 
         private TruffleNode node;
-        private int currentLine;
+        private SourcePosition currentPosition;
 
         private Builder() {}
 
@@ -119,29 +126,26 @@ public final class TruffleNode {
         }
 
         public TruffleNode build() {
-            if (currentLine > 0) {
-                markCurrent(node, currentLine);
+            if (currentPosition != null) {
+                markCurrent(node, currentPosition);
             }
             return node;
         }
 
         /** Mark all node paths which are currently being executed as current. 
*/
-        private boolean markCurrent(TruffleNode node, int currentLine) {
-            if (node.getChildren().length == 0) {
-                if (node.getStartLine() <= currentLine && currentLine <= 
node.getEndLine()) {
-                    node.current = true;
-                    return true;
-                } else {
-                    return false;
-                }
+        private static boolean markCurrent(TruffleNode node, SourcePosition 
currentPosition) {
+            if (node.getStartLine() == currentPosition.getStartLine() && 
node.getEndLine() == currentPosition.getEndLine() &&
+                    node.getStartColumn() == currentPosition.getStartColumn() 
&& node.getEndColumn() == currentPosition.getEndColumn()) {
+                node.current = true;
+                return true;
             } else {
                 boolean isSomeCurrent = false;
                 for (TruffleNode ch : node.getChildren()) {
-                    if (markCurrent(ch, currentLine)) {
+                    if (markCurrent(ch, currentPosition)) {
                         isSomeCurrent = true;
                     }
                 }
-                node.current = isSomeCurrent;
+                node.currentEncapsulating = isSomeCurrent;
                 return isSomeCurrent;
             }
         }
@@ -180,8 +184,8 @@ public final class TruffleNode {
             return node;
         }
 
-        public Builder currentLine(int line) {
-            this.currentLine = line;
+        public Builder currentPosition(SourcePosition position) {
+            this.currentPosition = position;
             return this;
         }
 
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/model/ASTNodeModel.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/model/ASTNodeModel.java
index 87a4317..5596c1f 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/model/ASTNodeModel.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/model/ASTNodeModel.java
@@ -46,19 +46,17 @@ public class ASTNodeModel implements NodeModel {
             String label = ast.getClassSimpleName();
             String tags = ast.getTags();
             if (!tags.isEmpty()) {
-                label = '[' + tags + "] " + label;
+                label = '(' + tags + ") " + label;
             }
             int l1 = ast.getStartLine();
             if (l1 >= 0) {
                 int c1 = ast.getStartColumn();
                 int l2 = ast.getEndLine();
                 int c2 = ast.getEndColumn();
-                label += " <"+l1+":"+c1+"-"+l2+":"+c2+">";
+                label += " ["+l1+":"+c1+"-"+l2+":"+c2+"]";
             }
-            if (ast.getChildren().length == 0) {
-                if (ast.isCurrent()) {
-                    label = "<html><b>" + label + "</b></html>";
-                }
+            if (ast.isCurrent()) {
+                label = "<html><b>" + label + "</b></html>";
             }
             return label;
         } else {
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/model/ASTTreeExpansionModel.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/model/ASTTreeExpansionModel.java
index 85792b5..8dc3f20 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/model/ASTTreeExpansionModel.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/ast/model/ASTTreeExpansionModel.java
@@ -42,7 +42,7 @@ public class ASTTreeExpansionModel implements 
TreeExpansionModel {
     public boolean isExpanded(Object node) throws UnknownTypeException {
         if (node instanceof TruffleNode) {
             TruffleNode ast = (TruffleNode) node;
-            return ast.isCurrent();
+            return ast.isCurrentEncapsulating() || ast.isCurrent();
         } else {
             return false;
         }
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointsHandler.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointsHandler.java
index d9df0bb..f658577 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointsHandler.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/TruffleBreakpointsHandler.java
@@ -245,11 +245,14 @@ public class TruffleBreakpointsHandler {
             }
         }
         bp.addPropertyChangeListener(breakpointsChangeListener);
-        List<Value> values = bpRef[0].getValues();
         Set<ObjectReference> breakpoints = new HashSet<>();
-        for (Value v : values) {
-            if (v instanceof ObjectReference) {
-                breakpoints.add((ObjectReference) v);
+        ArrayReference bpArray = bpRef[0];
+        if (bpArray != null) {
+            List<Value> values = bpArray.getValues();
+            for (Value v : values) {
+                if (v instanceof ObjectReference) {
+                    breakpoints.add((ObjectReference) v);
+                }
             }
         }
         if (!breakpoints.isEmpty()) {
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/TruffleStackFrame.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/TruffleStackFrame.java
index d3e6c44..6ef5d69 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/TruffleStackFrame.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/TruffleStackFrame.java
@@ -30,9 +30,9 @@ 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.actions.StepActionProvider;
 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;
@@ -51,13 +51,14 @@ public final class TruffleStackFrame {
     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 int    sourceLine;
+    private final String sourceSection;
     private final StringReference codeRef;
     private TruffleScope[] scopes;
     private final ObjectVariable thisObject;
@@ -89,6 +90,9 @@ public final class TruffleStackFrame {
             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);
@@ -109,11 +113,11 @@ public final class TruffleStackFrame {
             i1 = i2 + 1;
             if (includeInternal) {
                 i2 = frameDefinition.indexOf('\n', i1);
-                sourceLine = Integer.parseInt(frameDefinition.substring(i1, 
i2));
+                sourceSection = frameDefinition.substring(i1, i2);
                 i1 = i2 + 1;
                 internalFrame = Boolean.valueOf(frameDefinition.substring(i1));
             } else {
-                sourceLine = Integer.parseInt(frameDefinition.substring(i1));
+                sourceSection = frameDefinition.substring(i1);
             }
         } catch (IndexOutOfBoundsException ioob) {
             throw new 
IllegalStateException("frameDefinition='"+frameDefinition+"'", ioob);
@@ -140,6 +144,10 @@ public final class TruffleStackFrame {
         return methodName;
     }
 
+    public LanguageName getLanguage() {
+        return language;
+    }
+
     public String getSourceLocation() {
         return sourceLocation;
     }
@@ -157,7 +165,7 @@ public final class TruffleStackFrame {
         if (src == null) {
             src = Source.getSource(debugger, sourceId, sourceName, sourcePath, 
sourceURI, codeRef);
         }
-        SourcePosition sp = new SourcePosition(debugger, sourceId, src, 
sourceLine);
+        SourcePosition sp = new SourcePosition(debugger, sourceId, src, 
sourceSection);
         return sp;
     }
     
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/models/DebuggingTruffleActionsProvider.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/models/DebuggingTruffleActionsProvider.java
index 18a80fb..dc0acf1 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/models/DebuggingTruffleActionsProvider.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/models/DebuggingTruffleActionsProvider.java
@@ -107,7 +107,7 @@ public class DebuggingTruffleActionsProvider implements 
NodeActionsProviderFilte
             public void run () {
                 EditorContextBridge.getContext().showSource (
                     sourcePosition.getSource().getUrl().toExternalForm(),
-                    sourcePosition.getLine(),
+                    sourcePosition.getStartLine(),
                     f.getDebugger()
                 );
             }
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/models/DebuggingTruffleTreeModel.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/models/DebuggingTruffleTreeModel.java
index 2a62257..d5451fa 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/models/DebuggingTruffleTreeModel.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/frames/models/DebuggingTruffleTreeModel.java
@@ -47,7 +47,7 @@ import org.netbeans.spi.viewmodel.UnknownTypeException;
                              types={ TreeModelFilter.class })
 public class DebuggingTruffleTreeModel implements TreeModelFilter {
     
-    private static final Predicate<String> PREDICATE1 = 
Pattern.compile("^((com|org)\\.\\p{Alpha}*\\.truffle|(com|org)\\.graalvm)\\..*$").asPredicate();
+    private static final Predicate<String> PREDICATE1 = 
Pattern.compile("^((com|org)\\.\\p{Alpha}*\\.truffle|(com|org)(\\.graalvm|\\.truffleruby))\\..*$").asPredicate();
     private static final String FILTER1 = "com.[A-z]*.truffle.";               
      // NOI18N
     private static final String FILTER2 = "com.oracle.graal.";                 
 // NOI18N
     private static final String FILTER3 = 
"org.netbeans.modules.debugger.jpda.backend.";    // NOI18N
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/SourcePosition.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/SourcePosition.java
index 8a553a0..4e702a0 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/SourcePosition.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/source/SourcePosition.java
@@ -28,20 +28,44 @@ public class SourcePosition {
 
     private final long id;
     private final Source src;
-    private final int line;
+    private final int startLine;
+    private final int startColumn;
+    private final int endLine;
+    private final int endColumn;
     
-    public SourcePosition(JPDADebugger debugger, long id, Source src, int 
line) {
+    public SourcePosition(JPDADebugger debugger, long id, Source src, String 
sourceSection) {
         this.id = id;
         this.src = src;
-        this.line = line;
+        int i1 = 0, i2 = sourceSection.indexOf(',');
+        this.startLine = Integer.parseInt(sourceSection.substring(i1, i2));
+        i1 = i2 + 1;
+        i2 = sourceSection.indexOf(',', i1);
+        this.startColumn = Integer.parseInt(sourceSection.substring(i1, i2));
+        i1 = i2 + 1;
+        i2 = sourceSection.indexOf(',', i1);
+        this.endLine = Integer.parseInt(sourceSection.substring(i1, i2));
+        i1 = i2 + 1;
+        this.endColumn = Integer.parseInt(sourceSection.substring(i1));
     }
 
     public Source getSource() {
         return src;
     }
-    
-    public int getLine() {
-        return line;
+
+    public int getStartLine() {
+        return startLine;
+    }
+
+    public int getStartColumn() {
+        return startColumn;
     }
 
+    public int getEndLine() {
+        return endLine;
+    }
+
+    public int getEndColumn() {
+        return endColumn;
+    }
+    
 }
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleStackVariable.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleStackVariable.java
index ce5e8fd..62903ba 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleStackVariable.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleStackVariable.java
@@ -22,17 +22,21 @@ package org.netbeans.modules.debugger.jpda.truffle.vars;
 import java.util.function.Supplier;
 import org.netbeans.api.debugger.jpda.JPDADebugger;
 import org.netbeans.api.debugger.jpda.ObjectVariable;
+import org.netbeans.modules.debugger.jpda.truffle.LanguageName;
 import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
 
 public class TruffleStackVariable implements TruffleVariable {
     
     private final JPDADebugger debugger;
     private final String name;
+    private final LanguageName language;
     private String type;
     private final boolean readable;
     private final boolean writable;
     private final boolean internal;
     private String valueStr;
+    private boolean hasValueSource;
+    private boolean hasTypeSource;
     private Supplier<SourcePosition> valueSourceSupp;
     private Supplier<SourcePosition> typeSourceSupp;
     private SourcePosition valueSource;
@@ -40,18 +44,21 @@ public class TruffleStackVariable implements 
TruffleVariable {
     private ObjectVariable guestObj;
     private boolean leaf;
     
-    public TruffleStackVariable(JPDADebugger debugger, String name, String 
type,
-                                boolean readable, boolean writable, boolean 
internal,
-                                 String valueStr, Supplier<SourcePosition> 
valueSource,
-                                Supplier<SourcePosition> typeSource,
+    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) {
         this.debugger = debugger;
         this.name = name;
+        this.language = language;
         this.type = type;
         this.readable = readable;
         this.writable = writable;
         this.internal = internal;
         this.valueStr = valueStr;
+        this.hasValueSource = hasValueSource;
+        this.hasTypeSource = hasTypeSource;
         this.valueSourceSupp = valueSource;
         this.typeSourceSupp = typeSource;
         this.guestObj = truffleObj;
@@ -64,6 +71,11 @@ public class TruffleStackVariable implements TruffleVariable 
{
     }
 
     @Override
+    public LanguageName getLanguage() {
+        return language;
+    }
+
+    @Override
     public String getType() {
         return type;
     }
@@ -90,6 +102,9 @@ public class TruffleStackVariable implements TruffleVariable 
{
 
     @Override
     public ObjectVariable setValue(JPDADebugger debugger, String 
newExpression) {
+        if (this.valueStr.equals(newExpression)) {
+            return null;
+        }
         ObjectVariable newGuestObject = TruffleVariableImpl.setValue(debugger, 
guestObj, newExpression);
         if (newGuestObject != null) {
             this.guestObj = newGuestObject;
@@ -97,6 +112,8 @@ public class TruffleStackVariable implements TruffleVariable 
{
             this.type = newVar.getType();
             this.valueStr = newVar.getValue().toString();
             this.valueSource = this.typeSource = null;
+            this.hasValueSource = newVar.hasValueSource();
+            this.hasTypeSource = newVar.hasTypeSource();
             this.valueSourceSupp = () -> newVar.getValueSource();
             this.typeSourceSupp = () -> newVar.getTypeSource();
             this.leaf = TruffleVariableImpl.isLeaf(guestObj);
@@ -105,6 +122,11 @@ public class TruffleStackVariable implements 
TruffleVariable {
     }
 
     @Override
+    public boolean hasValueSource() {
+        return hasValueSource;
+    }
+
+    @Override
     public synchronized SourcePosition getValueSource() {
         if (valueSource == null) {
             valueSource = valueSourceSupp.get();
@@ -113,6 +135,11 @@ public class TruffleStackVariable implements 
TruffleVariable {
     }
 
     @Override
+    public boolean hasTypeSource() {
+        return hasTypeSource;
+    }
+
+    @Override
     public synchronized SourcePosition getTypeSource() {
         if (typeSource == null) {
             typeSource = typeSourceSupp.get();
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariable.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariable.java
index 9b58279..3674c42 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariable.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariable.java
@@ -21,6 +21,7 @@ package org.netbeans.modules.debugger.jpda.truffle.vars;
 
 import org.netbeans.api.debugger.jpda.JPDADebugger;
 import org.netbeans.api.debugger.jpda.ObjectVariable;
+import org.netbeans.modules.debugger.jpda.truffle.LanguageName;
 import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
 
 /**
@@ -29,7 +30,9 @@ import 
org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
 public interface TruffleVariable {
     
     String getName();
-    
+
+    LanguageName getLanguage();
+
     String getType();
 
     boolean isReadable();
@@ -40,8 +43,12 @@ public interface TruffleVariable {
     
     Object getValue();
     
+    boolean hasValueSource();
+    
     SourcePosition getValueSource();
     
+    boolean hasTypeSource();
+    
     SourcePosition getTypeSource();
     
     boolean isLeaf();
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariableImpl.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariableImpl.java
index f9a45de..3ec8ad4 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariableImpl.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/TruffleVariableImpl.java
@@ -26,6 +26,7 @@ import org.netbeans.api.debugger.jpda.JPDADebugger;
 import org.netbeans.api.debugger.jpda.ObjectVariable;
 import org.netbeans.api.debugger.jpda.Variable;
 import org.netbeans.modules.debugger.jpda.models.AbstractVariable;
+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.SourcePosition;
@@ -35,6 +36,7 @@ public class TruffleVariableImpl implements TruffleVariable {
     
     private static final String GUEST_OBJECT_TYPE = 
"org.netbeans.modules.debugger.jpda.backend.truffle.GuestObject";   // NOI18N
     private static final String FIELD_NAME = "name";                           
 // NOI18N
+    private static final String FIELD_LANGUAGE = "language";                   
 // NOI18N
     private static final String FIELD_TYPE = "type";                           
 // NOI18N
     private static final String FIELD_READABLE = "readable";                   
 // NOI18N
     private static final String FIELD_WRITABLE = "writable";                   
 // NOI18N
@@ -50,29 +52,36 @@ public class TruffleVariableImpl implements TruffleVariable 
{
     
     private final ObjectVariable guestObject;
     private final String name;
+    private final LanguageName language;
     private final String type;
     private final String displayValue;
     private final boolean readable;
     private final boolean writable;
     private final boolean internal;
     private final boolean leaf;
+    private final boolean hasValueSource;
+    private final boolean hasTypeSource;
     private SourcePosition valueSource;
     private SourcePosition typeSource;
     
     private TruffleVariableImpl(ObjectVariable guestObject, String name,
-                                String type, String displayValue,
+                                LanguageName language, String type, String 
displayValue,
                                 boolean readable, boolean writable, boolean 
internal,
+                                boolean hasValueSource, boolean hasTypeSource,
                                 boolean leaf) {
         this.guestObject = guestObject;
         this.name = name;
+        this.language = language;
         this.type = type;
         this.displayValue = displayValue;
         this.readable = readable;
         this.writable = writable;
         this.internal = internal;
+        this.hasValueSource = hasValueSource;
+        this.hasTypeSource = hasTypeSource;
         this.leaf = leaf;
     }
-    
+
     public static TruffleVariableImpl get(Variable var) {
         if (GUEST_OBJECT_TYPE.equals(var.getType())) {
             ObjectVariable truffleObj = (ObjectVariable) var;
@@ -84,6 +93,12 @@ public class TruffleVariableImpl implements TruffleVariable {
             }
             String name = (String) f.createMirrorObject();
 
+            f = truffleObj.getField(FIELD_LANGUAGE);
+            if (f == null) {
+                return null;
+            }
+            LanguageName language = LanguageName.parse((String) 
f.createMirrorObject());
+
             f = truffleObj.getField(FIELD_TYPE);
             if (f == null) {
                 return null;
@@ -120,8 +135,13 @@ public class TruffleVariableImpl implements 
TruffleVariable {
                 internal = (Boolean) f.createMirrorObject();
             }
 
+            f = truffleObj.getField(FIELD_VALUE_SOURCE);
+            boolean hasValueSource = ((ObjectVariable) f).getUniqueID() != 0L;
+            f = truffleObj.getField(FIELD_TYPE_SOURCE);
+            boolean hasTypeSource = ((ObjectVariable) f).getUniqueID() != 0L;
+
             boolean leaf = isLeaf(truffleObj);
-            return new TruffleVariableImpl(truffleObj, name, type, dispVal, 
readable, writable, internal, leaf);
+            return new TruffleVariableImpl(truffleObj, name, language, type, 
dispVal, readable, writable, internal, hasValueSource, hasTypeSource, leaf);
         } else {
             return null;
         }
@@ -145,6 +165,11 @@ public class TruffleVariableImpl implements 
TruffleVariable {
     }
 
     @Override
+    public LanguageName getLanguage() {
+        return language;
+    }
+
+    @Override
     public String getType() {
         return type;
     }
@@ -175,6 +200,9 @@ public class TruffleVariableImpl implements TruffleVariable 
{
 
     @Override
     public ObjectVariable setValue(JPDADebugger debugger, String 
newExpression) {
+        if (this.displayValue.equals(newExpression)) {
+            return null;
+        }
         return setValue(debugger, guestObject, newExpression);
     }
 
@@ -196,6 +224,11 @@ public class TruffleVariableImpl implements 
TruffleVariable {
     }
 
     @Override
+    public boolean hasValueSource() {
+        return hasValueSource;
+    }
+
+    @Override
     public synchronized SourcePosition getValueSource() {
         if (valueSource == null) {
             Field f = getFieldChecked(FIELD_VALUE_SOURCE, guestObject);
@@ -205,6 +238,11 @@ public class TruffleVariableImpl implements 
TruffleVariable {
     }
 
     @Override
+    public boolean hasTypeSource() {
+        return hasTypeSource;
+    }
+
+    @Override
     public synchronized SourcePosition getTypeSource() {
         if (typeSource == null) {
             Field f = getFieldChecked(FIELD_TYPE_SOURCE, guestObject);
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesActionsProviderFilter.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesActionsProviderFilter.java
index 0abf393..ab37af7 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesActionsProviderFilter.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesActionsProviderFilter.java
@@ -23,7 +23,9 @@ import java.net.URL;
 import javax.swing.Action;
 import javax.swing.SwingUtilities;
 
+import org.netbeans.api.debugger.jpda.JPDADebugger;
 import org.netbeans.modules.debugger.jpda.EditorContextBridge;
+import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
 import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
 import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
 import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
@@ -37,6 +39,7 @@ import org.netbeans.spi.viewmodel.UnknownTypeException;
 import org.openide.DialogDisplayer;
 import org.openide.NotifyDescriptor;
 import org.openide.util.NbBundle;
+import org.openide.util.RequestProcessor;
 
 @DebuggerServiceRegistrations({
     
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/LocalsView",
  types=NodeActionsProviderFilter.class),
@@ -45,9 +48,11 @@ import org.openide.util.NbBundle;
     
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/WatchesView",
 types=NodeActionsProviderFilter.class),
 })
 public class TruffleVariablesActionsProviderFilter implements 
NodeActionsProviderFilter {
-    
+
+    private final RequestProcessor rp;
+
     public TruffleVariablesActionsProviderFilter(ContextProvider 
contextProvider) {
-        System.err.println("new TruffleVariablesActionsProviderFilter()");
+        this.rp = ((JPDADebuggerImpl) contextProvider.lookupFirst(null, 
JPDADebugger.class)).getRequestProcessor();
     }
 
     @NbBundle.Messages("CTL_GoToSource=Go to source")
@@ -61,7 +66,7 @@ public class TruffleVariablesActionsProviderFilter implements 
NodeActionsProvide
             @Override
             public void perform (final Object[] nodes) {
                 TruffleVariable var = (TruffleVariable) nodes[0];
-                showSource(var.getValueSource());
+                rp.post(() -> showSource(var.getValueSource()));
             }
         },
         Models.MULTISELECTION_TYPE_EXACTLY_ONE
@@ -78,7 +83,7 @@ public class TruffleVariablesActionsProviderFilter implements 
NodeActionsProvide
             @Override
             public void perform (final Object[] nodes) {
                 TruffleVariable var = (TruffleVariable) nodes[0];
-                showSource(var.getTypeSource());
+                rp.post(() -> showSource(var.getTypeSource()));
             }
         },
         Models.MULTISELECTION_TYPE_EXACTLY_ONE
@@ -86,19 +91,18 @@ public class TruffleVariablesActionsProviderFilter 
implements NodeActionsProvide
 
     @Override
     public void performDefaultAction(NodeActionsProvider original, Object 
node) throws UnknownTypeException {
-        boolean shown = false;
         if (node instanceof TruffleVariable) {
             TruffleVariable var = (TruffleVariable) node;
-            SourcePosition source = var.getValueSource();
-            if (source == null) {
-                source = var.getTypeSource();
-            }
-            if (source != null) {
-                showSource(source);
-                shown = true;
-            }
-        }
-        if (!shown) {
+            rp.post(() -> {
+                SourcePosition source = var.getValueSource();
+                if (source == null) {
+                    source = var.getTypeSource();
+                }
+                if (source != null) {
+                    showSource(source);
+                }
+            });
+        } else {
             original.performDefaultAction(node);
         }
     }
@@ -115,23 +119,23 @@ public class TruffleVariablesActionsProviderFilter 
implements NodeActionsProvide
         }
         if (node instanceof TruffleVariable) {
             TruffleVariable var = (TruffleVariable) node;
-            SourcePosition valueSource = var.getValueSource();
-            SourcePosition typeSource = var.getTypeSource();
-            if (valueSource != null || typeSource != null) {
+            boolean hasValueSource = var.hasValueSource();
+            boolean hasTypeSource = var.hasTypeSource();
+            if (hasValueSource || hasTypeSource) {
                 int l = actions.length;
-                if (valueSource != null) {
+                if (hasValueSource) {
                     l++;
                 }
-                if (typeSource != null) {
+                if (hasTypeSource) {
                     l++;
                 }
                 Action[] newActions = new Action[l];
                 System.arraycopy(actions, 0, newActions, 0, actions.length);
                 l = actions.length;
-                if (valueSource != null) {
+                if (hasValueSource) {
                     newActions[l++] = GO_TO_VALUE_SOURCE_ACTION;
                 }
-                if (typeSource != null) {
+                if (hasTypeSource) {
                     newActions[l++] = GO_TO_TYPE_SOURCE_ACTION;
                 }
                 actions = newActions;
@@ -145,7 +149,7 @@ public class TruffleVariablesActionsProviderFilter 
implements NodeActionsProvide
     @NbBundle.Messages({"# {0} - The file path", "MSG_NoSourceFile=Cannot find 
source file {0}."})
     private void showSource(SourcePosition source) {
         URL url = source.getSource().getUrl();
-        int lineNumber = source.getLine();
+        int lineNumber = source.getStartLine();
         SwingUtilities.invokeLater (() -> {
             boolean success = 
EditorContextBridge.getContext().showSource(url.toExternalForm(), lineNumber, 
null);
             if (!success) {
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTableModel.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTableModel.java
index 69b2bad..edb8f61 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTableModel.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTableModel.java
@@ -19,13 +19,19 @@
 
 package org.netbeans.modules.debugger.jpda.truffle.vars.models;
 
+import java.awt.Color;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
+import javax.swing.JTable;
+import javax.swing.UIManager;
 
 import org.netbeans.api.debugger.jpda.JPDADebugger;
-import org.netbeans.api.debugger.jpda.JPDAWatch;
 import org.netbeans.api.debugger.jpda.Variable;
+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.access.TruffleStrataProvider;
+import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
 import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
 import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
 import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariableImpl;
@@ -47,10 +53,10 @@ import org.netbeans.spi.viewmodel.TableModelFilter;
 import org.netbeans.spi.viewmodel.UnknownTypeException;
 
 @DebuggerServiceRegistrations({
-    
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/LocalsView",
  types = TableModelFilter.class),
-    
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/ResultsView",
 types = TableModelFilter.class),
-    
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/ToolTipView",
 types = TableModelFilter.class),
-    
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/WatchesView",
 types = TableModelFilter.class)
+    
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/LocalsView",
  types = {TableModelFilter.class, TableHTMLModelFilter.class}),
+    
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/ResultsView",
 types = {TableModelFilter.class, TableHTMLModelFilter.class}),
+    
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/ToolTipView",
 types = {TableModelFilter.class, TableHTMLModelFilter.class}),
+    
@DebuggerServiceRegistration(path="netbeans-JPDASession/"+TruffleStrataProvider.TRUFFLE_STRATUM+"/WatchesView",
 types = {TableModelFilter.class, TableHTMLModelFilter.class})
 })
 public class TruffleVariablesTableModel implements TableModelFilter, 
TableHTMLModelFilter {
     
@@ -61,23 +67,22 @@ public class TruffleVariablesTableModel implements 
TableModelFilter, TableHTMLMo
         debugger = contextProvider.lookupFirst(null, JPDADebugger.class);
     }
 
+    private static TruffleVariable getTruffleVariable(Object node) {
+        if (node instanceof Variable) {
+            return TruffleVariableImpl.get((Variable) node);
+        } else if (node instanceof TruffleVariable) {
+            return (TruffleVariable) node;
+        } else {
+            return null;
+        }
+    }
+
     @Override
     public Object getValueAt(TableModel original, Object node, String 
columnID) throws UnknownTypeException {
         if (node instanceof TruffleScope) {
             return "";
         }
-        TruffleVariable tv = null;
-        if (node instanceof JPDAWatch) {// && !isEnabled((JPDAWatch) node)) {
-            Object orig = original.getValueAt(node, columnID); // Call in any 
case because of error displaying
-            if (node instanceof Variable) {
-                tv = TruffleVariableImpl.get((Variable) node);
-            }
-            if (tv == null) {
-                return orig;
-            }
-        } else if (node instanceof TruffleVariable) {
-            tv = (TruffleVariable) node;
-        }
+        TruffleVariable tv = getTruffleVariable(node);
         if (tv != null) {
             switch (columnID) {
                 case LOCALS_TYPE_COLUMN_ID:
@@ -128,13 +133,34 @@ public class TruffleVariablesTableModel implements 
TableModelFilter, TableHTMLMo
     @Override
     public boolean hasHTMLValueAt(TableHTMLModel original, Object node, String 
columnID) throws UnknownTypeException {
         if (node instanceof TruffleVariable) {
-            return false;
+            switch (columnID) {
+                case LOCALS_TYPE_COLUMN_ID:
+                case WATCH_TYPE_COLUMN_ID:
+                    return true;
+            }
         }
         return original.hasHTMLValueAt(node, columnID);
     }
 
     @Override
     public String getHTMLValueAt(TableHTMLModel original, Object node, String 
columnID) throws UnknownTypeException {
+            switch (columnID) {
+                case LOCALS_TYPE_COLUMN_ID:
+                case WATCH_TYPE_COLUMN_ID:
+                    TruffleVariable tv = getTruffleVariable(node);
+                    if (tv != null) {
+                        LanguageName frameLanguage = LanguageName.NONE;
+                        CurrentPCInfo currentPCInfo = 
TruffleAccess.getCurrentPCInfo(debugger.getCurrentThread());
+                        if (currentPCInfo != null) {
+                            TruffleStackFrame selectedStackFrame = 
currentPCInfo.getSelectedStackFrame();
+                            frameLanguage = selectedStackFrame.getLanguage();
+                        }
+                        LanguageName valueLanguage = tv.getLanguage();
+                        if (!LanguageName.NONE.equals(valueLanguage) && 
!frameLanguage.equals(valueLanguage)) {
+                            return toHTML(valueLanguage.getName(), 
tv.getType());
+                        }
+                    }
+        }
         return original.getHTMLValueAt(node, columnID);
     }
 
@@ -148,4 +174,32 @@ public class TruffleVariablesTableModel implements 
TableModelFilter, TableHTMLMo
         listeners.remove(l);
     }
 
+    public static String toHTML(String id, String text) {
+        if (text == null) return null;
+        StringBuilder sb = new StringBuilder ();
+        sb.append("<html>");
+        Color color = UIManager.getColor("Table.foreground");
+        if (color == null) {
+            color = new JTable().getForeground();
+        }
+        sb.append("<font color=\"#");
+        String hexColor = Integer.toHexString ((color.getRGB () & 0xffffff));
+        for (int i = hexColor.length(); i < 6; i++) {
+            sb.append("0"); // Prepend zeros to length of 6
+        }
+        sb.append(hexColor);
+        sb.append("\">");
+        
+        sb.append("<font color=\"#808080\">[");
+        sb.append(id);
+        sb.append("]</font> ");
+        
+        text = text.replaceAll("&", "&amp;");
+        text = text.replaceAll("<", "&lt;");
+        text = text.replaceAll(">", "&gt;");
+        sb.append(text);
+        sb.append("</font>");
+        sb.append("</html>");
+        return sb.toString ();
+    }
 }
diff --git 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTreeModel.java
 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTreeModel.java
index cf9f119..66c135c 100644
--- 
a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTreeModel.java
+++ 
b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/vars/models/TruffleVariablesTreeModel.java
@@ -23,7 +23,6 @@ import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.netbeans.api.debugger.jpda.JPDADebugger;
-import org.netbeans.api.debugger.jpda.JPDAWatch;
 import org.netbeans.api.debugger.jpda.Variable;
 import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
 import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleScope;
@@ -62,7 +61,7 @@ public class TruffleVariablesTreeModel implements 
TreeModelFilter {
 
     @Override
     public Object[] getChildren(TreeModel original, Object parent, int from, 
int to) throws UnknownTypeException {
-        if (parent instanceof JPDAWatch) {
+        if (parent instanceof Variable) {
             TruffleVariable tv = TruffleVariableImpl.get((Variable) parent);
             if (tv != null) {
                 parent = tv;
diff --git 
a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugSLTest.java
 
b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugSLTest.java
index dc3ab84..94e0f43 100644
--- 
a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugSLTest.java
+++ 
b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugSLTest.java
@@ -130,7 +130,7 @@ public class DebugSLTest extends NbTestCase {
             assertNotNull("No top frame", topFrame);
             SourcePosition sourcePosition = topFrame.getSourcePosition();
             assertEquals("Bad source", "Meaning of world.sl", 
sourcePosition.getSource().getName());
-            assertEquals("Bad line", lineNo, sourcePosition.getLine());
+            assertEquals("Bad line", lineNo, sourcePosition.getStartLine());
             assertEquals("Bad method name", methodName, 
topFrame.getMethodName());
             
             support.doContinue();
@@ -178,7 +178,7 @@ public class DebugSLTest extends NbTestCase {
             assertNotNull("No top frame", topFrame);
             SourcePosition sourcePosition = topFrame.getSourcePosition();
             assertEquals("Bad source", "TestApp.sl", 
sourcePosition.getSource().getName());
-            assertEquals("Bad line", lb.getLineNumber(), 
sourcePosition.getLine());
+            assertEquals("Bad line", lb.getLineNumber(), 
sourcePosition.getStartLine());
             assertEquals("Bad method name", "main", topFrame.getMethodName());
             
             support.doContinue();
diff --git 
a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLApp.java
 
b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLApp.java
index 15cabd4..4d1e9f6 100644
--- 
a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLApp.java
+++ 
b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLApp.java
@@ -44,7 +44,7 @@ public class SLApp {
             "}\n",
             "Meaning of world.sl").build();
         
-        Context context = Context.newBuilder().out(os).build();
+        Context context = 
Context.newBuilder().allowAllAccess(true).out(os).build();
         Value result = context.eval(src);                           // 
LBREAKPOINT
 
         assertEquals("Expected result", 42L, result.asLong());
diff --git 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/FrameInfo.java
 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/FrameInfo.java
index 7e53dea..61c7167 100644
--- 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/FrameInfo.java
+++ 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/FrameInfo.java
@@ -20,6 +20,7 @@
 package org.netbeans.modules.debugger.jpda.backend.truffle;
 
 import com.oracle.truffle.api.debug.DebugStackFrame;
+import com.oracle.truffle.api.nodes.LanguageInfo;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.SourceSection;
 import java.lang.reflect.InvocationTargetException;
@@ -40,7 +41,7 @@ final class FrameInfo {
 
     FrameInfo(DebugStackFrame topStackFrame, Iterable<DebugStackFrame> 
stackFrames) {
         SourceSection topSS = topStackFrame.getSourceSection();
-        SourcePosition position = JPDATruffleDebugManager.getPosition(topSS);
+        SourcePosition position = new SourcePosition(topSS);
         ArrayList<DebugStackFrame> stackFramesArray = new ArrayList<>();
         for (DebugStackFrame sf : stackFrames) {
             if (sf == topStackFrame) {
@@ -55,10 +56,13 @@ final class FrameInfo {
         }
         frame = topStackFrame;
         stackTrace = stackFramesArray.toArray(new 
DebugStackFrame[stackFramesArray.size()]);
+        LanguageInfo sfLang = topStackFrame.getLanguage();
         topFrame = topStackFrame.getName() + "\n" +
+                   ((sfLang != null) ? sfLang.getId() + " " + sfLang.getName() 
: "") + "\n" +
                    DebuggerVisualizer.getSourceLocation(topSS) + "\n" +
                    position.id + "\n" + position.name + "\n" + position.path + 
"\n" +
-                   position.uri.toString() + "\n" + position.line + "\n" + 
isInternal(topStackFrame);
+                   position.uri.toString() + "\n" + position.sourceSection +/* 
"," + position.startColumn + "," +
+                   position.endLine + "," + position.endColumn +*/ "\n" + 
isInternal(topStackFrame);
         topVariables = JPDATruffleAccessor.getVariables(topStackFrame);
     }
     
diff --git 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/GuestObject.java
 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/GuestObject.java
index 6d3f6a5..8b159a1 100644
--- 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/GuestObject.java
+++ 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/GuestObject.java
@@ -21,12 +21,11 @@ package org.netbeans.modules.debugger.jpda.backend.truffle;
 
 import com.oracle.truffle.api.debug.DebugStackFrame;
 import com.oracle.truffle.api.debug.DebugValue;
+import com.oracle.truffle.api.nodes.LanguageInfo;
 import com.oracle.truffle.api.source.SourceSection;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+
 import java.util.Collection;
 import java.util.List;
-import java.util.Objects;
 
 /**
  * A guest language object.
@@ -37,6 +36,7 @@ public final class GuestObject {
 
     final DebugValue value;
     final String name;
+    final String language;
     final String type;
     final String displayValue;
     final boolean readable;
@@ -50,6 +50,14 @@ public final class GuestObject {
     final SourcePosition typeSourcePosition;
 
     GuestObject(DebugValue value) {
+        LanguageInfo originalLanguage = value.getOriginalLanguage();
+        // Setup the object with a language-specific value
+        if (originalLanguage != null) {
+            value = value.asInLanguage(originalLanguage);
+            this.language = originalLanguage.getId() + " " + 
originalLanguage.getName();
+        } else {
+            this.language = "";
+        }
         this.value = value;
         this.name = value.getName();
         //System.err.println("new GuestObject("+name+")");
@@ -62,36 +70,34 @@ public final class GuestObject {
             LangErrors.exception("Value "+name+" .getMetaObject()", ex);
         }
         String typeStr = "";
-        if (metaObject != null) {
-            try {
-                typeStr = metaObject.as(String.class);
-            } catch (ThreadDeath td) {
-                throw td;
-            } catch (Throwable ex) {
-                LangErrors.exception("Meta object of "+name+" 
.as(String.class)", ex);
+        try {
+            // New in GraalVM 20.1.0
+            typeStr = (String) 
DebugValue.class.getMethod("getMetaSimpleName").invoke(value);
+        } catch (ReflectiveOperationException | IllegalArgumentException | 
SecurityException exc) {
+            if (metaObject != null) {
+                try {
+                    typeStr = metaObject.as(String.class);
+                } catch (ThreadDeath td) {
+                    throw td;
+                } catch (Throwable ex) {
+                    LangErrors.exception("Meta object of "+name+" 
.as(String.class)", ex);
+                }
             }
         }
         this.type = typeStr;
         //this.object = value;
         String valueStr = null;
         try {
-            valueStr = value.as(String.class);
+            try {
+                // New in GraalVM 20.1.0
+                valueStr = (String) 
DebugValue.class.getMethod("toDisplayString").invoke(value);
+            } catch (ReflectiveOperationException | IllegalArgumentException | 
SecurityException exc) {
+                valueStr = value.as(String.class);
+            }
         } catch (ThreadDeath td) {
             throw td;
         } catch (Throwable ex) {
-            LangErrors.exception("Value "+name+" .as(String.class)", ex);
-        }
-        if (valueStr == null) {
-            // Hack for R:
-            try {
-                Method getMethod = DebugValue.class.getDeclaredMethod("get");
-                getMethod.setAccessible(true);
-                Object realValue = getMethod.invoke(value);
-                valueStr = Objects.toString(realValue);
-            } catch (IllegalAccessException | IllegalArgumentException | 
InvocationTargetException |
-                     NoSuchMethodException | SecurityException ex) {
-                LangErrors.exception("Value "+name+" get() invocation", ex);
-            }
+            LangErrors.exception("Value "+name+" .toDisplayString", ex);
         }
         this.displayValue = valueStr;
         //System.err.println("  have display value "+valueStr);
@@ -138,8 +144,8 @@ public final class GuestObject {
         try {
             SourceSection sourceLocation = value.getSourceLocation();
             //System.err.println("\nSOURCE of "+value.getName()+" is: 
"+sourceLocation);
-            if (sourceLocation != null) {
-                sp = JPDATruffleDebugManager.getPosition(sourceLocation);
+            if (sourceLocation != null && sourceLocation.isAvailable()) {
+                sp = new SourcePosition(sourceLocation);
             }
         } catch (ThreadDeath td) {
             throw td;
@@ -152,8 +158,8 @@ public final class GuestObject {
             try {
                 SourceSection sourceLocation = metaObject.getSourceLocation();
                 //System.err.println("\nSOURCE of metaobject "+metaObject+" 
is: "+sourceLocation);
-                if (sourceLocation != null) {
-                    sp = JPDATruffleDebugManager.getPosition(sourceLocation);
+                if (sourceLocation != null && sourceLocation.isAvailable()) {
+                    sp = new SourcePosition(sourceLocation);
                 }
             } catch (ThreadDeath td) {
                 throw td;
diff --git 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
index 26f624a..af6d364 100644
--- 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
+++ 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
@@ -26,7 +26,8 @@ import com.oracle.truffle.api.debug.DebugValue;
 import com.oracle.truffle.api.debug.Debugger;
 import com.oracle.truffle.api.debug.DebuggerSession;
 import com.oracle.truffle.api.debug.SuspendedEvent;
-//import com.oracle.truffle.api.vm.PolyglotEngine;
+import com.oracle.truffle.api.nodes.LanguageInfo;
+
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -111,7 +112,7 @@ public class JPDATruffleAccessor extends Object {
         }
     }
     
-    static JPDATruffleDebugManager setUpDebugManagerFor(/*Engine*/Object 
engineObj, boolean doStepInto) {
+    static JPDATruffleDebugManager setUpDebugManagerFor(/*Engine*/Object 
engineObj, boolean includeInternal, boolean doStepInto) {
         trace("setUpDebugManagerFor("+engineObj+", "+doStepInto+")");
         Engine engine = (Engine) engineObj;
         Debugger debugger;
@@ -126,13 +127,24 @@ public class JPDATruffleAccessor extends Object {
                 return null;
             }
         }
-        JPDATruffleDebugManager tdm = new JPDATruffleDebugManager(debugger, 
doStepInto);
+        JPDATruffleDebugManager tdm = new JPDATruffleDebugManager(debugger, 
includeInternal, doStepInto);
         synchronized (debugManagers) {
             debugManagers.put(debugger, tdm);
         }
         return tdm;
     }
     
+    static void setIncludeInternal(boolean includeInternal) {
+        synchronized (debugManagers) {
+            for (JPDATruffleDebugManager tdm : debugManagers.values()) {
+                DebuggerSession debuggerSession = tdm.getDebuggerSession();
+                if (debuggerSession != null) {
+                    
debuggerSession.setSteppingFilter(JPDATruffleDebugManager.createSteppingFilter(includeInternal));
+                }
+            }
+        }
+    }
+
     static int executionHalted(JPDATruffleDebugManager tdm,
                                SourcePosition position,
                                boolean haltedBefore,
@@ -200,6 +212,10 @@ public class JPDATruffleAccessor extends Object {
             }
             frameInfos.append(sfName);
             frameInfos.append('\n');
+            LanguageInfo sfLang = sf.getLanguage();
+            String sfLangId = (sfLang != null) ? sfLang.getId() + " " + 
sfLang.getName() : "";
+            frameInfos.append(sfLangId);
+            frameInfos.append('\n');
             
frameInfos.append(DebuggerVisualizer.getSourceLocation(sf.getSourceSection()));
             frameInfos.append('\n');
             /*if (fi.getCallNode() == null) {
@@ -210,7 +226,7 @@ public class JPDATruffleAccessor extends Object {
                 System.err.println("frameInfos = "+frameInfos);
                 *//*
             }*/
-            SourcePosition position = 
JPDATruffleDebugManager.getPosition(sf.getSourceSection());
+            SourcePosition position = new 
SourcePosition(sf.getSourceSection());
             frameInfos.append(createPositionIdentificationString(position));
             if (includeInternal) {
                 frameInfos.append('\n');
@@ -220,12 +236,6 @@ public class JPDATruffleAccessor extends Object {
             frameInfos.append("\n\n");
             
             codes[j] = position.code;
-            /*
-             TODO Find "this"
-            Frame f = fi.getFrame(FrameInstance.FrameAccess.READ_ONLY, false);
-            if (f instanceof VirtualFrame) {
-                thiss[i] = JSFrameUtil.getThisObj((VirtualFrame) f);
-            }*/
             j++;
         }
         if (j < n) {
@@ -246,7 +256,7 @@ public class JPDATruffleAccessor extends Object {
         str.append('\n');
         str.append(position.uri.toString());
         str.append('\n');
-        str.append(position.line);
+        str.append(position.sourceSection);
         return str.toString();
     }
 
@@ -293,7 +303,8 @@ public class JPDATruffleAccessor extends Object {
                 }
                 Iterable<DebugValue> varsIt = scope.getDeclaredValues();
                 Iterator<DebugValue> vars = varsIt.iterator();
-                if ((args == null || !args.hasNext()) && !vars.hasNext()) {
+                DebugValue receiver = scope.isFunctionScope() ? 
scope.getReceiver() : null;
+                if ((args == null || !args.hasNext()) && !vars.hasNext() && 
receiver == null) {
                     // An empty scope, skip it
                     scope = scope.getParent();
                     continue;
@@ -314,6 +325,9 @@ public class JPDATruffleAccessor extends Object {
                 while (vars.hasNext()) {
                     variables.add(vars.next());
                 }
+                if (receiver != null) {
+                    variables.add(receiver);
+                }
                 elements.add(variables.size());
                 if (arguments != null) {
                     for (DebugValue v : arguments) {
@@ -377,6 +391,12 @@ public class JPDATruffleAccessor extends Object {
             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) {
@@ -394,11 +414,12 @@ public class JPDATruffleAccessor extends Object {
         return elements.toArray();
     }
 
-    // Store 11 elements: <name>, <type>, <readable>, <writable>, <internal>, 
<String value>,
+    // 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) {
         GuestObject tobj = new GuestObject(value);
         elements.add(tobj.name);
+        elements.add(tobj.language);
         elements.add(tobj.type);
         elements.add(tobj.readable);
         elements.add(tobj.writable);
diff --git 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleDebugManager.java
 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleDebugManager.java
index 98ecfa7..f3fd297 100644
--- 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleDebugManager.java
+++ 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleDebugManager.java
@@ -26,8 +26,7 @@ import com.oracle.truffle.api.debug.SuspendAnchor;
 import com.oracle.truffle.api.debug.SuspendedCallback;
 import com.oracle.truffle.api.debug.SuspendedEvent;
 import com.oracle.truffle.api.debug.SuspensionFilter;
-import com.oracle.truffle.api.source.Source;
-import com.oracle.truffle.api.source.SourceSection;
+
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 
@@ -41,16 +40,20 @@ class JPDATruffleDebugManager implements SuspendedCallback {
     private final Reference<DebuggerSession> session;
     private final ThreadLocal<SuspendedEvent> suspendedEvents = new 
ThreadLocal<>();
 
-    public JPDATruffleDebugManager(Debugger debugger, boolean doStepInto) {
+    public JPDATruffleDebugManager(Debugger debugger, boolean includeInternal, 
boolean doStepInto) {
         this.debugger = new WeakReference<>(debugger);
         DebuggerSession debuggerSession = debugger.startSession(this);
-        
debuggerSession.setSteppingFilter(SuspensionFilter.newBuilder().ignoreLanguageContextInitialization(true).build());
+        
debuggerSession.setSteppingFilter(createSteppingFilter(includeInternal));
         if (doStepInto) {
             debuggerSession.suspendNextExecution();
         }
         this.session = new WeakReference<>(debuggerSession);
     }
-    
+
+    static SuspensionFilter createSteppingFilter(boolean includeInternal) {
+        return 
SuspensionFilter.newBuilder().ignoreLanguageContextInitialization(true).includeInternal(includeInternal).build();
+    }
+
     Debugger getDebugger() {
         return debugger.get();
     }
@@ -63,18 +66,6 @@ class JPDATruffleDebugManager implements SuspendedCallback {
         return suspendedEvents.get();
     }
     
-    static SourcePosition getPosition(SourceSection sourceSection) {
-        int line = sourceSection.getStartLine();
-        Source source = sourceSection.getSource();
-        String name = source.getName();
-        String path = source.getPath();
-        if (path == null) {
-            path = name;
-        }
-        String code = source.getCharacters().toString();
-        return new SourcePosition(source, name, path, line, code);
-    }
-
     void dispose() {
         DebuggerSession ds = session.get();
         if (ds != null) {
@@ -116,7 +107,7 @@ class JPDATruffleDebugManager implements SuspendedCallback {
         }
         suspendedEvents.set(event);
         try {
-            SourcePosition position = getPosition(event.getSourceSection());
+            SourcePosition position = new 
SourcePosition(event.getSourceSection());
             int stepCmd = JPDATruffleAccessor.executionHalted(
                     this, position,
                     event.getSuspendAnchor() == SuspendAnchor.BEFORE,
diff --git 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/SourcePosition.java
 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/SourcePosition.java
index 5552ba6..d4321b0 100644
--- 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/SourcePosition.java
+++ 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/SourcePosition.java
@@ -20,6 +20,8 @@
 package org.netbeans.modules.debugger.jpda.backend.truffle;
 
 import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.source.SourceSection;
+
 import java.net.URI;
 import java.util.Map;
 import java.util.WeakHashMap;
@@ -36,16 +38,21 @@ final class SourcePosition {
     final long id;
     final String name;
     final String path;
-    final int line;
+    final String sourceSection;
     final String code;
     final URI uri;
 
-    public SourcePosition(Source source, String name, String path, int line, 
String code) {
+    public SourcePosition(SourceSection sourceSection) {
+        Source source = sourceSection.getSource();
         this.id = getId(source);
-        this.name = name;
-        this.path = path;
-        this.line = line;
-        this.code = code;
+        this.name = source.getName();
+        String sourcePath = source.getPath();
+        if (sourcePath == null) {
+            sourcePath = name;
+        }
+        this.path = sourcePath;
+        this.sourceSection = sourceSection.getStartLine() + "," + 
sourceSection.getStartColumn() + "," + sourceSection.getEndLine() + "," + 
sourceSection.getEndColumn();
+        this.code = source.getCharacters().toString();
         this.uri = source.getURI();
     }
 
diff --git 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/TruffleAST.java
 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/TruffleAST.java
index 997e64f..64131f9 100644
--- 
a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/TruffleAST.java
+++ 
b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/TruffleAST.java
@@ -26,12 +26,13 @@ import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameInstance;
 import com.oracle.truffle.api.frame.FrameInstanceVisitor;
 import com.oracle.truffle.api.frame.FrameSlot;
+import com.oracle.truffle.api.instrumentation.InstrumentableNode;
 import com.oracle.truffle.api.instrumentation.StandardTags;
+import com.oracle.truffle.api.instrumentation.Tag;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeUtil;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.SourceSection;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -132,23 +133,19 @@ public class TruffleAST {
         }
         // TAGS:
         try {
-            java.lang.reflect.Method isTaggedWithMethod = 
Node.class.getDeclaredMethod("isTaggedWith", Class.class);
-            isTaggedWithMethod.setAccessible(true);
             StringBuilder tags = new StringBuilder();
-            if ((Boolean) isTaggedWithMethod.invoke(node, 
StandardTags.RootTag.class)) {
-                tags.append("Root");
-            }
-            if ((Boolean) isTaggedWithMethod.invoke(node, 
StandardTags.CallTag.class)) {
-                if (tags.length() > 0) {
-                    tags.append(' ');
-                }
-                tags.append("Call");
-            }
-            if ((Boolean) isTaggedWithMethod.invoke(node, 
StandardTags.StatementTag.class)) {
-                if (tags.length() > 0) {
-                    tags.append(' ');
+            if (node instanceof InstrumentableNode) {
+                InstrumentableNode inode = (InstrumentableNode) node;
+                for (Class<?> tag : StandardTags.class.getDeclaredClasses()) {
+                    if (Tag.class.isAssignableFrom(tag)) {
+                        if (inode.hasTag(tag.asSubclass(Tag.class))) {
+                            if (tags.length() > 0) {
+                                tags.append(',');
+                            }
+                            tags.append(tag.getSimpleName());
+                        }
+                    }
                 }
-                tags.append("Statement");
             }
             nodes.append(tags);
         } catch (Throwable t) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to