diff --git a/documentation/tutorials/debugging/InteropDebugging/JS/main.js b/documentation/tutorials/debugging/InteropDebugging/JS/main.js new file mode 100644 index 0000000000000000000000000000000000000000..a1d81827fbda13ae1b5ee5f906f78c4f8a1ec3b3 --- /dev/null +++ b/documentation/tutorials/debugging/InteropDebugging/JS/main.js @@ -0,0 +1,5 @@ +var greeting = "Ahoy"; +var greet = function (x) { + console.log(x); +} +greet(greeting); \ No newline at end of file diff --git a/documentation/tutorials/debugging/InteropDebugging/R/main.r b/documentation/tutorials/debugging/InteropDebugging/R/main.r new file mode 100644 index 0000000000000000000000000000000000000000..ed13a09c88e2b692fc7bc1415cf885634d954eb1 --- /dev/null +++ b/documentation/tutorials/debugging/InteropDebugging/R/main.r @@ -0,0 +1,40 @@ +# +# 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) + diff --git a/documentation/tutorials/debugging/InteropDebugging/manifest.mf b/documentation/tutorials/debugging/InteropDebugging/manifest.mf new file mode 100644 index 0000000000000000000000000000000000000000..328e8e5bc3b7f1f7bad2bc0751a933e00c801983 --- /dev/null +++ b/documentation/tutorials/debugging/InteropDebugging/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/JavaMessage.java b/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/JavaMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..a6ea29c3593eadf08671ee6bda744263f420bb97 --- /dev/null +++ b/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/JavaMessage.java @@ -0,0 +1,47 @@ +/* + * 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; + } + +} diff --git a/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/Main.java b/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..300a6e6390f598af2856a26f78a8fb2bfab53278 --- /dev/null +++ b/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/Main.java @@ -0,0 +1,57 @@ +/* + * 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(); + } + +} diff --git a/documentation/tutorials/debugging/R/binSearch.r b/documentation/tutorials/debugging/R/binSearch.r new file mode 100644 index 0000000000000000000000000000000000000000..4290216371d9b8f4725d7d2ee94d6cabf7dd1c5c --- /dev/null +++ b/documentation/tutorials/debugging/R/binSearch.r @@ -0,0 +1,37 @@ +# +# 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 + } + } +} diff --git a/documentation/tutorials/debugging/R/dummy.r b/documentation/tutorials/debugging/R/dummy.r new file mode 100644 index 0000000000000000000000000000000000000000..a9904460ee5e673f58340dc3aca3f55eb169eee7 --- /dev/null +++ b/documentation/tutorials/debugging/R/dummy.r @@ -0,0 +1,32 @@ +# +# 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) +} + diff --git a/documentation/tutorials/debugging/R/dump.r b/documentation/tutorials/debugging/R/dump.r new file mode 100644 index 0000000000000000000000000000000000000000..fc8a8b5b3c81dc6c8c6df58681101e4005e347e0 --- /dev/null +++ b/documentation/tutorials/debugging/R/dump.r @@ -0,0 +1,34 @@ +# +# 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) diff --git a/documentation/tutorials/debugging/tutorial.md b/documentation/tutorials/debugging/tutorial.md new file mode 100644 index 0000000000000000000000000000000000000000..4761389e976ca21abd04754b6fdd0a11959df49a --- /dev/null +++ b/documentation/tutorials/debugging/tutorial.md @@ -0,0 +1,133 @@ +# 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. +