Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/moonrun/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ anyhow.workspace = true
clap.workspace = true
serde.workspace = true
serde_json_lenient.workspace = true
moonutil.workspace = true
rand = "0.8.5"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
Expand All @@ -41,6 +40,7 @@ chrono.workspace = true
[dev-dependencies]
snapbox.workspace = true
moon-test-util = { path = "../moon-test-util" }
moonutil.workspace = true

[[bin]]
name = "moonrun"
Expand Down
15 changes: 0 additions & 15 deletions crates/moonrun/src/backtrace_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,13 @@ fn resolve_source_map_path(
ret.set(scope.string(&resolved).into());
}

fn demangle_mangled_function_name(
scope: &mut v8::HandleScope,
args: v8::FunctionCallbackArguments,
mut ret: v8::ReturnValue,
) {
let mangled = args.string_lossy(scope, 0);
let demangled = moonutil::demangle::demangle_mangled_function_name(&mangled);
ret.set(scope.string(&demangled).into());
}

const BACKTRACE_RUNTIME_NAMESPACE: &str = "__moonbit_backtrace_runtime";

pub(crate) fn init(scope: &mut v8::HandleScope) {
let global_proxy = scope.get_current_context().global(scope);
let backtrace_obj = global_proxy.child(scope, BACKTRACE_RUNTIME_NAMESPACE);

backtrace_obj.set_func(scope, "resolve_source_map_path", resolve_source_map_path);
backtrace_obj.set_func(
scope,
"demangle_mangled_function_name",
demangle_mangled_function_name,
);
}

#[cfg(test)]
Expand Down
98 changes: 98 additions & 0 deletions crates/moonrun/src/demangle_js_template.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// moon: The build system and package manager for MoonBit.
// Copyright (C) 2024 International Digital Economy Academy
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For inquiries, you can contact us via e-mail at jichuruanjian@idea.edu.cn.

pub(crate) const DEMANGLE_JS_TEMPLATE: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/template/demangle.js"
));

#[cfg(test)]
mod tests {
use super::DEMANGLE_JS_TEMPLATE;
use std::sync::Once;

const DEMANGLE_FN_NAME: &str = "__moonbit_demangle_mangled_function_name";

fn init_v8_once() {
static INIT: Once = Once::new();
INIT.call_once(|| {
v8::V8::set_flags_from_string("--experimental-wasm-exnref");
v8::V8::set_flags_from_string("--experimental-wasm-imported-strings");
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
});
}

fn run_demangle_in_v8(input: &str) -> String {
init_v8_once();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);

let script = v8::String::new(scope, DEMANGLE_JS_TEMPLATE).unwrap();
let script = v8::Script::compile(scope, script, None).unwrap();
script.run(scope).unwrap();

let global = scope.get_current_context().global(scope);
let func_name = v8::String::new(scope, DEMANGLE_FN_NAME).unwrap();
let func = global.get(scope, func_name.into()).unwrap();
let func: v8::Local<v8::Function> = func.try_into().unwrap();

let arg = v8::String::new(scope, input).unwrap();
let result = func.call(scope, global.into(), &[arg.into()]).unwrap();
result.to_string(scope).unwrap().to_rust_string_lossy(scope)
}

#[test]
fn js_demangler_template_exports_function() {
assert_eq!(run_demangle_in_v8("_M0FP13pkg3foo"), "@pkg.foo".to_string());
}

#[test]
fn js_demangler_template_matches_rust_demangler() {
let samples = [
"_M0FP13pkg3foo",
"_M0MP13pkg4Type3bar",
"_M0IP13pkg4ImplP13pkg5Trait3run",
"_M0EP13pkg4TypeP14util3new",
"_M0TP13pkg4Type",
"_M0L6_2atmpS9127",
"_M0FP15myapp8try__mapGiEHRP15myapp7MyError",
"_M0FP15myapp3runGVWiEsE",
"_M0FP15myapp8try__runGWiEsQRP15myapp7MyErrorE",
"_M0EP311moonbitlang4core7builtin3IntP15myapp6double",
"_M0FPB30output_2eflush__segment_7c4024",
"_M0L61_24username_2fhello_2fmain_2eabort__via__closure_2einner_2efnS271",
"_M0FP13pkg3foo$closure.data",
"_M0FP13pkg3foo@123",
"_M0FP13pkg3foo.",
"$_M0FP13pkg3foo",
"_M0FP15myapp7try_mapGiE",
"_M0FP314d_2dh24moonbit_2dscatter_2dplot14scatter_2dplot28gen__scatter__plot__graphics",
"plain",
];

for sample in samples {
let expected = moonutil::demangle::demangle_mangled_function_name(sample);
let actual = run_demangle_in_v8(sample);
assert_eq!(actual, expected, "sample: {sample}");
}
}
}
13 changes: 11 additions & 2 deletions crates/moonrun/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use std::{cell::Cell, io::Read, path::PathBuf, time::Instant};
use v8::V8::set_flags_from_string;

mod backtrace_api;
mod demangle_js_template;
mod fs_api_temp;
mod sys_api;
mod util;
Expand Down Expand Up @@ -240,9 +241,15 @@ fn read_file_to_bytes(
mut ret: v8::ReturnValue,
) {
let path = PathBuf::from(args.string_lossy(scope, 0));
let bytes = std::fs::read(path).unwrap();
let Ok(bytes) = std::fs::read(path) else {
ret.set_undefined();
return;
};
let buffer = v8::ArrayBuffer::new(scope, bytes.len());
let ab = v8::Uint8Array::new(scope, buffer, 0, bytes.len()).unwrap();
let Some(ab) = v8::Uint8Array::new(scope, buffer, 0, bytes.len()) else {
ret.set_undefined();
return;
};

unsafe {
std::ptr::copy(bytes.as_ptr(), get_array_buffer_ptr(buffer), bytes.len());
Expand Down Expand Up @@ -490,6 +497,8 @@ fn wasm_mode(
}
script.push_str(&format!("const no_stack_trace = {no_stack_trace};"));
script.push_str(&format!("const test_mode = {};", test_args.is_some()));
script.push_str(demangle_js_template::DEMANGLE_JS_TEMPLATE);
script.push('\n');
let js_glue = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/template/js_glue.js"
Expand Down
Loading
Loading