Skip to content

Commit e395871

Browse files
authored
Safer passing of R functions to JS (#41)
* Safer passing of R functions to JS * Tidy * Bump version * Fix initialiser
1 parent 78c6c27 commit e395871

File tree

6 files changed

+30
-21
lines changed

6 files changed

+30
-21
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: QuickJSR
22
Title: Interface for the 'QuickJS' Lightweight 'JavaScript' Engine
3-
Version: 1.2.0
3+
Version: 1.2.0.9000
44
Authors@R: c(
55
person(c("Andrew", "R."), "Johnson", , "[email protected]", role = c("aut", "cre"),
66
comment = c(ORCID = "0000-0001-7000-8065")),

NEWS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# QuickJSR 1.2.0
22
- `Rcpp` dependency replaced with vendored `cpp11` headers
33
- `R6` dependency removed
4-
- `R` and `JS` interopability added, removing `jsonlite` dependency
4+
- `R` and `JS` interoperability added, removing `jsonlite` dependency
55
- Fixes for libatomic linking on 32-bit systems
66
- Added `to_json` and `from_json` functions for testing `R`/`JS` interop
77

inst/include/quickjsr.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef QUICKJSR_HPP
22
#define QUICKJSR_HPP
33

4+
#include <quickjsr/JS_SEXP.hpp>
45
#include <quickjsr/SEXP_to_JSValue.hpp>
56
#include <quickjsr/JSValue_to_SEXP.hpp>
67
#include <quickjsr/JSValue_to_JSON.hpp>

inst/include/quickjsr/JS_SEXP.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef QUICKJSR_JS_SEXP_HPP
2+
#define QUICKJSR_JS_SEXP_HPP
3+
4+
#include <quickjs-libc.h>
5+
6+
namespace quickjsr {
7+
JSClassID js_sexp_class_id;
8+
JSClassDef js_sexp_class_def = {
9+
"SEXP",
10+
nullptr // finalized
11+
};
12+
}
13+
14+
#endif

inst/include/quickjsr/SEXP_to_JSValue.hpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,11 @@
33

44
#include <quickjsr/JSValue_Date.hpp>
55
#include <quickjsr/JSValue_to_SEXP.hpp>
6+
#include <quickjsr/JS_SEXP.hpp>
67
#include <cpp11.hpp>
78
#include <quickjs-libc.h>
89

910
namespace quickjsr {
10-
// Global tape to store JSValue objects that are created during conversion but
11-
// but can't be immediately freed because they are needed
12-
std::vector<JSValue> global_tape;
13-
1411
// Forward declaration to allow for recursive calls
1512
inline JSValue SEXP_to_JSValue(JSContext* ctx, const SEXP& x, bool auto_unbox, bool auto_unbox_curr);
1613
inline JSValue SEXP_to_JSValue(JSContext* ctx, const SEXP& x, bool auto_unbox, bool auto_unbox_curr, int index);
@@ -83,9 +80,9 @@ namespace quickjsr {
8380

8481
static JSValue js_fun_static(JSContext* ctx, JSValueConst this_val, int argc,
8582
JSValueConst* argv, int magic, JSValue* data) {
86-
int64_t ptr;
87-
JS_ToBigInt64(ctx, &ptr, *data);
88-
SEXP x = reinterpret_cast<SEXP>(ptr);
83+
JSValue data_val = data[0];
84+
SEXP x = reinterpret_cast<SEXP>(JS_GetOpaque(data_val, js_sexp_class_id));
85+
JS_FreeValue(ctx, data_val);
8986
cpp11::writable::list args(argc);
9087
for (int i = 0; i < argc; i++) {
9188
args[i] = JSValue_to_SEXP(ctx, argv[i]);
@@ -97,11 +94,10 @@ namespace quickjsr {
9794
inline JSValue SEXP_to_JSValue_function(JSContext* ctx, const SEXP& x,
9895
bool auto_unbox_inp = false,
9996
bool auto_unbox = false) {
100-
// Store the SEXP pointer as a 64-bit integer so that it can be
101-
// passed to the JS C function
102-
global_tape.push_back(JS_NewBigInt64(ctx, reinterpret_cast<int64_t>(x)));
97+
JSValue obj = JS_NewObjectClass(ctx, js_sexp_class_id);
98+
JS_SetOpaque(obj, reinterpret_cast<void*>(x));
10399
return JS_NewCFunctionData(ctx, js_fun_static, Rf_length(FORMALS(x)),
104-
JS_CFUNC_generic, 1, &global_tape[global_tape.size() - 1]);
100+
JS_CFUNC_generic, 1, &obj);
105101
}
106102

107103
inline JSValue SEXP_to_JSValue_matrix(JSContext* ctx, const SEXP& x, bool auto_unbox_inp = false, bool auto_unbox = false) {

src/quickjsr.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,13 @@
33
#include <quickjs-libc.h>
44
#include <quickjsr.hpp>
55

6-
void JS_FreeJSContextandTape(JSContext* ctx) {
7-
for (auto&& val : quickjsr::global_tape) {
8-
JS_FreeValue(ctx, val);
9-
}
10-
JS_FreeContext(ctx);
11-
}
12-
136
void JS_FreeRuntimeStdHandlers(JSRuntime* rt) {
147
js_std_free_handlers(rt);
158
JS_FreeRuntime(rt);
169
}
1710

1811
// Register the cpp11 external pointer types with the correct cleanup/finaliser functions
19-
using ContextXPtr = cpp11::external_pointer<JSContext, JS_FreeJSContextandTape>;
12+
using ContextXPtr = cpp11::external_pointer<JSContext, JS_FreeContext>;
2013
using RuntimeXPtr = cpp11::external_pointer<JSRuntime, JS_FreeRuntimeStdHandlers>;
2114

2215
extern "C" SEXP qjs_context_(SEXP stack_size_) {
@@ -29,6 +22,11 @@ extern "C" SEXP qjs_context_(SEXP stack_size_) {
2922
JS_SetMaxStackSize(rt.get(), 0);
3023
}
3124
js_std_init_handlers(rt.get());
25+
26+
// Initialise a class which can be used for passing SEXP objects to JS
27+
// without needing conversion
28+
JS_NewClass(rt.get(), quickjsr::js_sexp_class_id, &quickjsr::js_sexp_class_def);
29+
3230
ContextXPtr ctx(JS_NewContext(rt.get()));
3331
js_std_add_helpers(ctx.get(), 0, (char**)"");
3432

0 commit comments

Comments
 (0)