Skip to content
Snippets Groups Projects
Commit 58f42d6b authored by Florian Angerer's avatar Florian Angerer
Browse files

Added debugging tutorial.

parent e1b4fd3d
No related branches found
No related tags found
No related merge requests found
var greeting = "Ahoy";
var greet = function (x) {
console.log(x);
}
greet(greeting);
\ No newline at end of file
#
# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
print("Hello, World! (from file)")
print("Creating a Java object in FastR")
clazz <- .fastr.java.class("java.util.Date")
obj <- .fastr.interop.new(clazz, .fastr.interop.toLong(as.integer(Sys.time())*1000))
print(obj$toString())
# add classpath entry to be able to use our class
.fastr.java.addClasspathEntry("build/classes")
clazz <- .fastr.java.class("com.oracle.truffle.r.JavaMessage")
obj <- .fastr.interop.new(clazz, "Hi there")
print(obj$getMessage())
JS_MIME_TYPE <- "application/javascript"
.fastr.interop.eval(JS_MIME_TYPE, 'var s = "Hello from Javascript"; print(s)')
.fastr.interop.evalFile("JS/main.js", JS_MIME_TYPE)
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.oracle.truffle.r;
public class JavaMessage {
private String message;
public JavaMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return message;
}
}
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.oracle.truffle.r;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.vm.PolyglotEngine;
import java.io.File;
import java.io.IOException;
public class Main {
private static final String R_MIME_TYPE = "application/x-r";
/**
* @param args the command line arguments
* @throws java.io.IOException
*/
public static void main(String[] args) throws IOException {
PolyglotEngine newVM = PolyglotEngine.newBuilder().config(R_MIME_TYPE, "debugContext", null).build();
newVM.eval(fromString("print('Hello, World! (from string)')"));
newVM.eval(fromFile("R/main.r"));
}
private static Source fromString(String code) {
return Source.newBuilder(code).name("<shell_input>").mimeType(R_MIME_TYPE).interactive().build();
}
private static Source fromFile(String path) throws IOException {
return Source.newBuilder(new File(path)).mimeType(R_MIME_TYPE).build();
}
}
#
# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# Returns the index of the value in the sorted vector.
binSearch <- function(vec, value) {
low <- 1L
high <- length(vec)+1L
while(low < high) {
idx <- as.integer((low + high) / 2L)
if(vec[[idx]] == value) {
return (idx)
} else if(vec[[idx]] < value) {
low <- idx
} else {
high <- idx
}
}
}
#
# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
bar <- function(x) print(x)
fun <- function(x) {
print("Hello")
for(i in seq(3)) print(i)
bar("World")
print(x)
}
#
# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
gen_data <- function() {
res <- list(rep(0, 100))
for(i in seq_along(res)) {
res[[i]] <- i %% 5
}
res
}
library(jsonlite)
jsonStr <- toJSON(gen_data())
cat(jsonStr)
# FastR NetBeans Debugging Tutorial
## Getting started
Read the documentation in "documentation/debugging.md" in FastR's GitHub repository.
In order to suppress annoying stack traces when you (accidentally) enter values in the variables view, start FastR with option `--J @-Dtruffle.nbdebug.supressLangErrs=true`.
Let's start with a simple example.
```R
source("/home/fa/Documents/dbg-tutorial/R/binSearch.r")
binSearch(1:100, 1)
binSearch(1:100, 100)
binSearch(1:100, 50)
binSearch(1:100, 67)
binSearch(1:100, 0)
binSearch(1:100, 101) # why does this not stop
```
Set a line breakpoint in function binSearch, step through the loop iterations and find the problem.
## Advanced Debugging
### Inspecting Promises
Promises are in particular difficult to handle during debugging.
The maxime of debugging is to not modify the program as it could change its behavior and make any debugging difficult.
However, this means that you will often not be able to inspect a promise until it is too late since a promise is evaluated at the time it is used.
FastR allows to inspect promises in the variables view.
Every promise (pointed out as type "promise" in the view) has three fields: `value`, `isEvaluated`, and `isEager`
If `isEager` is `true`, then you will immediately see the value of the promise. An eager promise is a special kind where FastR eagerly evaluated the value for performance reasons.
In this case it is safe to have the value already available without changing the semantics of the program.
If *isEager* is *false*, then *isEvaluated* will initially also be *false* and *value* will be *NULL*.
### Debugging Packages 1
Packages are usually loaded lazily from a binary file containing the serialized code and data of the package.
Therefore, you can usually only install a function breakpoint to package code.
However, FastR keeps the package source such that you can set a line breakpoint in the package's source files.
Determine the path where packages are installed:
```R
.libPaths()
```
To demonstrate this, start FastR in debug mode and attach the NetBeans debugger.
Then enter `.libPaths()` to determine where your R packages are installed.
Go to the installation directory from package *jsonlite* and open the file *jsonlite/R/toJSON.R*.
Set a line breakpoint at line 32 which calls the generic `asJSON` function.
Now, run our script *dump.r* using `source("R/dump.r")`.
As soon as the debugging cursor stops at the line breakpoint, step into the call of function *asJSON* to find out which of the concrete implementations is actually executed.
### Debugging Packages 2
For some reason, it may be that packages do not have source code available.
Then, setting a line breakpoint is not straigt forward.
Therefore, FastR provides a facility to query the source of an R function.
As in GnuR, if the source is not available for the function, the function's body is deparsed and a string representation is generated.
FastR then generates a temporary source file containing the deparsed source code.
This temporary source file can be queried using function `.fastr.srcinfo`.
Example:
```R
source("R/dummy.r")
fun
attributes(fun)
```
Actually, *fun* has just been sourced and we would expect that there is a *srcref* attribute.
Let's have a look what function *source* is actually doing:
```R
> .fastr.srcinfo(source)
[1] "/tmp/deparse/source-58f3b608a4.r#1"
```
This output means that FastR generated a temporary source file "/deparse/source-58f3b608a4.r" and function *source* starts at line 1.
Open the file in NetBeans (File -> Open File ...) and set a breakpoint at line 62.
```R
source("R/dummy.r")
```
Open the __Evaluate Expression__ view under menu Debug -> Evaluate Expression.
Type *isTRUE(keep.source)* and press <ctrl> + <enter>.
The result of the evaluation should be TRUE. So, why there are no source reference attributes?
Continue stepping until line 89 (*.Internal(parse(file, n = -1, NULL, "?", srcfile, encoding))*).
This line calls the internal parse function which we unfortunately cannot step into because internal functions do not have R code.
They are implemented in Java or C.
Now, step over line 89 and evaluate the expression: *attributes(exprs)*
The results shows that the resulting expressions actually have source reference attributes.
Now, keep stepping until line 132 (*ei <- exprs[i]*) which copies one of the elements of the parsed expression.
Now, evaluate expression: *attributes(exprs)*
It turns out that the subexpression does not have any attributes.
The reason is that FastR does not create source reference attributes in the parser because the source information is stored differently.
## GraalVM-featured
FastR is part of the Graal/Truffle world and it is therefore easily possible to write R applications that interact with other programming languages like Java.
FastR has its dedicated Java interoperability API that allows to create and use Java objects.
The NetBeans debugger is also capable of stepping over language boundaries.
To demonstrate this:
1. Download GraalVM from [Oracle Technology Network (OTN)](http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html) and extract the archive.
2. Open NetBeans and add GraalVM as Java Platform:
1. Tools -> Java Platforms
2. Add Platform ...
3. Java Standard Edition -> Next
4. Navigate to the extracted folder of GraalVM and select the __jdk__ subfolder and click *Next*.
5. Specify an appropriate platform name like __GraalVM JDK__ and click finish.
3. Open the NetBeans project *InteropDebugging* and ensure that it uses __GraalVM JDK__ as platform:
1. Right click on the project and select *Properties*.
2. Select *Libraries* and choose __GraalVM JDK__ in the dropdown menu labeled with *Java Platform:*.
File `Main.java` creates a `PolyglotEngine` object that can execute R code. This is basically the FastR engine.
The engine object can now run R code by creating a source object (representing R code) and submitting the source to the engine.
The expression `fromString("print('Hello, World! (from string)')")` creates a source code from a string.
Expression `fromFile("R/main.r")` creates source code from file *R/main.r*.
Now, set a line breakpoint at line 46 (the second eval expression), build the project and run the Java application using GraalVM on the command line:
`graalvm-<version>/bin/graalvm -J:-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -cp build/classes com.oracle.truffe.r.Main`
Attach the NetBeans debugger as described in *documentation/debugging.md* via Debug -> Attach Debugger.
Once the debugger breaks at line 46, you can step into the R application (Debug -> Step Into).
The debugging cursor will next arrive in file *R/main.r*.
File *R/main.r* also uses language interoperability to create a Java object and to run JavaScript code.
We can easily debug the executed Java code by setting a breakpoint in method `java.util.Date.toString`.
During stepping through the R program, you will also step into the Java code.
Next, lines 31 to 35 in *R/main.r* instantiate an object of a class in our NetBeans Java project.
Before we can use our class *JavaMessage*, we need to add this project to the class path for the Java interoperability.
This is done by statement `java.addClasspathEntry("build/classes")`.
You can now also set a breakpoint in the `getMessage()` method and the debugger will halt on this breakpoint if the R expression `obj$getMessage()` is evaluated.
Lines 38 and 39 further evaluate code of a different language, namely JavaScript.
If you have stepped to this call, you will be able to step into the JavaScript program.
You can then continue your debugging activities in the JavaScript program and you will return to the origin.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment