Skip to content

Commit

Permalink
Attempt 2
Browse files Browse the repository at this point in the history
  • Loading branch information
jeroen committed Oct 5, 2024
1 parent e3bfdc3 commit a3e8069
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
10 changes: 10 additions & 0 deletions R/callback.R
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,13 @@ no_jumps <- function(...){
structure("User interruption during R evaluation", class = 'cb_error')
})
}

read_file_string <- function(name, ...){
no_jumps({
path <- normalizePath(name, mustWork = FALSE)
if(!file.exists(path)){
stop(sprintf("File '%s' not found", path))
}
rawToChar(readBin(path, raw(), file.info(path)$size))
})
}
71 changes: 71 additions & 0 deletions src/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,75 @@ static void fatal_cb(const char* location, const char* message){
REprintf("V8 FATAL ERROR in %s: %s", location, message);
}

static v8::Local<v8::Module> compile_module(std::string src, v8::Local<v8::Context> context);

static v8::MaybeLocal<v8::Module> ResolveModuleCallback(v8::Local<v8::Context> context,
v8::Local<v8::String> specifier,
v8::Local<v8::FixedArray> import_attributes,
v8::Local<v8::Module> referrer) {
v8::String::Utf8Value name(isolate, specifier);
Rf_warningcall_immediate(R_NilValue, "Failed to import '%s': (Modules are not yet supported)", ToCString(name));
return compile_module("", context);
}

static v8::MaybeLocal<v8::Promise> ResolveDynamicModuleCallback(
v8::Local<v8::Context> context,
v8::Local<v8::Data> host_defined_options,
v8::Local<v8::Value> resource_name,
v8::Local<v8::String> specifier,
v8::Local<v8::FixedArray> import_assertions) {
v8::Local<v8::Promise::Resolver> resolver = v8::Promise::Resolver::New(context).ToLocalChecked();
v8::MaybeLocal<v8::Promise> promise(resolver->GetPromise());
v8::String::Utf8Value name(context->GetIsolate(), specifier);
Rcpp::Function r_readlines = Rcpp::Environment::namespace_env("V8")["read_file_string"];
Rcpp::CharacterVector out = r_readlines(Rcpp::String(*name));
v8::Local<v8::String> source_text(ToJSString(std::string(out.at(0)).c_str()));
if(out.inherits("cb_error")){
resolver->Reject(context, source_text).FromMaybe(false); //R error reading file
return promise;
}
if(source_text.IsEmpty()){
resolver->Reject(context, ToJSString("Failed to read Module source code.")).FromMaybe(false);
return promise;
}
v8::ScriptOrigin origin(specifier, 0, 0, false, -1, v8::Local<v8::Value>(), false, false, true);
v8::ScriptCompiler::Source source(source_text, origin);
v8::Local<v8::Module> module;
if (!v8::ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)){
resolver->Reject(context, ToJSString("Failure at CompileModule")).FromMaybe(false);
return promise;
}
if(!module->InstantiateModule(context, ResolveModuleCallback).FromMaybe(false)){
resolver->Reject(context, ToJSString("Failure at InstantiateModule")).FromMaybe(false);
return promise;
}
v8::Local<v8::Value> retValue;
if (!module->Evaluate(context).ToLocal(&retValue)) {
resolver->Reject(context, ToJSString("Failure evaluating")).FromMaybe(false);
return promise;
}
resolver->Resolve(context, module->GetModuleNamespace()).FromMaybe(false);
return promise;
}


/* Helper fun that compiles JavaScript source code */
static v8::Local<v8::Module> compile_module(std::string src, v8::Local<v8::Context> context){
v8::Local<v8::String> source_text = ToJSString(src.c_str());
if(source_text.IsEmpty())
throw std::runtime_error("Failed to load JavaScript source. Check memory/stack limits.");
v8::ScriptOrigin origin(ToJSString( "main.mjs"), 0, 0, false, -1,
v8::Local<v8::Value>(), false, false, true);
v8::ScriptCompiler::Source source(source_text, origin);
v8::Local<v8::Module> module;
if (!v8::ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module))
throw std::runtime_error("Failed to run CompileModule() source. Check memory/stack limits.");
if(!module->InstantiateModule(context, ResolveModuleCallback).FromMaybe(false))
throw std::runtime_error("Failed to run InstantiateModule() source. Check memory/stack limits.");
return module;
}


// [[Rcpp::init]]
void start_v8_isolate(void *dll){
#ifdef V8_ICU_DATA_PATH
Expand Down Expand Up @@ -103,6 +172,8 @@ void start_v8_isolate(void *dll){
uintptr_t CurrentStackPosition = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
isolate->SetStackLimit(CurrentStackPosition - kWorkerMaxStackSize);
#endif
// setting this callback enables dynamic imports
isolate->SetHostImportModuleDynamicallyCallback(ResolveDynamicModuleCallback);
}

/* Helper fun that compiles JavaScript source code */
Expand Down

0 comments on commit a3e8069

Please sign in to comment.