Skip to content

Commit

Permalink
Implement the GC in Rust
Browse files Browse the repository at this point in the history
This implements the current garbage collector in Rust. No changes were
made to the GC design -- it's just ports the one implemented in code
generator to Rust.

The goals are:

- Evaluate Rust for Motoko's RTS implementation
- Make the collector easier to read, understand, modify, and extend.

Current status: the code is complete in the sense that there aren't any
missing features/passes etc., but it's has bugs. I'm not sure how to
debug Wasm yet. There are also lots of TODOs in the code, mostly for
documentation.

Submitting a PR to get early feedback.
  • Loading branch information
osa1 committed Jul 27, 2020
1 parent 6f41ab9 commit cf81ff6
Show file tree
Hide file tree
Showing 16 changed files with 762 additions and 160 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
_out
_output
_build
target

**/*~
/result*
Expand Down
24 changes: 13 additions & 11 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,18 @@ let haskellPackages = nixpkgs.haskellPackages.override {
overrides = import nix/haskell-packages.nix nixpkgs subpath;
}; in
let
llvmBuildInputs = [
rtsBuildInputs = [
nixpkgs.clang_10 # for native/wasm building
nixpkgs.lld_10 # for wasm building
nixpkgs.rustc
nixpkgs.cargo
];

# When compiling natively, we want to use `clang` (which is a nixpkgs
# provided wrapper that sets various include paths etc).
# But for some reason it does not handle building for Wasm well, so
# there we use plain clang-10. There is no stdlib there anyways.
llvmEnv = ''
rtsEnv = ''
# When compiling natively, we want to use `clang` (which is a nixpkgs
# provided wrapper that sets various include paths etc).
# But for some reason it does not handle building for Wasm well, so
# there we use plain clang-10. There is no stdlib there anyways.
export CLANG="${nixpkgs.clang_10}/bin/clang"
export WASM_CLANG="clang-10"
export WASM_LD=wasm-ld
Expand Down Expand Up @@ -122,10 +124,10 @@ rec {
src = subpath ./rts;
nativeBuildInputs = [ nixpkgs.makeWrapper ];

buildInputs = llvmBuildInputs;
buildInputs = rtsBuildInputs;

preBuild = ''
${llvmEnv}
${rtsEnv}
export TOMMATHSRC=${nixpkgs.sources.libtommath}
export MUSLSRC=${nixpkgs.sources.musl-wasi}/libc-top-half/musl
export MUSL_WASI_SYSROOT=${musl-wasi-sysroot}
Expand Down Expand Up @@ -206,11 +208,11 @@ rec {
wasmtime
nixpkgs.sources.esm
] ++
llvmBuildInputs;
rtsBuildInputs;

checkPhase = ''
patchShebangs .
${llvmEnv}
${rtsEnv}
export MOC=moc
export MO_LD=mo-ld
export DIDC=didc
Expand Down Expand Up @@ -486,7 +488,7 @@ rec {
builtins.concatMap (d: d.buildInputs) (builtins.attrValues tests)
));

shellHook = llvmEnv;
shellHook = rtsEnv;
ESM=nixpkgs.sources.esm;
TOMMATHSRC = nixpkgs.sources.libtommath;
MUSLSRC = "${nixpkgs.sources.musl-wasi}/libc-top-half/musl";
Expand Down
11 changes: 11 additions & 0 deletions nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ let
wasmtime = self.callPackage ./wasmtime.nix {};
}
)
# nixpkgs's rustc does not include the wasm32-unknown-unknown target, so
# lets add it here.
(self: super: {
rustc = super.rustc.overrideAttrs (old: {
configureFlags = self.lib.lists.forEach old.configureFlags (flag:
if self.lib.strings.hasPrefix "--target=" flag
then flag + ",wasm32-unknown-unknown,wasm32-unknown-emscripten"
else flag
);
});
})
];
};
in
Expand Down
25 changes: 20 additions & 5 deletions rts/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
SHELL:=bash -O globstar

CLANG ?= clang-10
WASM_CLANG ?= clang-10
WASM_LD ?= wasm-ld-10
Expand Down Expand Up @@ -154,14 +156,28 @@ _build/native/tommath_%.o: %.c rts.h buf.h | _build/native
_build/wasm/musl_%.o: %.c | _build/wasm
$(WASM_CLANG) $(CLANG_FLAGS) $(WASM_FLAGS) $(MUSL_FLAGS) $< --output $@

.PHONY: _build/wasm/motoko_rts.o
_build/wasm/motoko_rts.o: | _build/wasm
cd motoko-rts && \
cargo rustc --target=wasm32-unknown-emscripten --release -v -- -Crelocation-model=pic --emit=obj
cp motoko-rts/target/wasm32-unknown-emscripten/release/deps/motoko_rts*.o $@

.PHONY: _build/native/motoko_rts.o
_build/native/motoko_rts.o: | _build/native
cd motoko-rts && \
cargo rustc --release -v -- -Crelocation-model=pic --emit=obj
cp motoko-rts/target/release/deps/motoko_rts*.o $@

RTS_WASM_O=$(RTSFILES:%=_build/wasm/%.o)
RTS_NATIVE_O=$(RTSFILES:%=_build/native/%.o)
RTS_RUST_WASM_O=_build/wasm/motoko_rts.o
RTS_RUST_NATIVE_O=_build/native/motoko_rts.o

#
# The actual RTS, as we ship it with the compiler
#

mo-rts.wasm: $(RTS_WASM_O) $(TOMMATH_WASM_O) $(MUSL_WASM_O)
mo-rts.wasm: $(RTS_WASM_O) $(RTS_RUST_WASM_O) $(TOMMATH_WASM_O) $(MUSL_WASM_O)
$(WASM_LD) -o $@ \
--import-memory --shared --no-entry --gc-sections \
--export=__wasm_call_ctors \
Expand All @@ -171,12 +187,11 @@ mo-rts.wasm: $(RTS_WASM_O) $(TOMMATH_WASM_O) $(MUSL_WASM_O)
# A simple program to do simple tests of rts.c, using native compilation
#

test_rts: test_rts.c $(RTS_NATIVE_O) $(TOMMATH_NATIVE_O)
test_rts: test_rts.c $(RTS_NATIVE_O) $(RTS_RUST_NATIVE_O) $(TOMMATH_NATIVE_O)
$(CLANG) -o $@ $+

test_leb128: test_leb128.c $(RTS_NATIVE_O) $(TOMMATH_NATIVE_O)
test_leb128: test_leb128.c $(RTS_NATIVE_O) $(RTS_RUST_NATIVE_O) $(TOMMATH_NATIVE_O)
$(CLANG) -o $@ $+

clean:
rm -rf _build mo-rts.wasm test_rts test_leb128

rm -rf _build mo-rts.wasm test_rts test_leb128 motoko-rts/target
3 changes: 3 additions & 0 deletions rts/motoko-rts/.vim/coc-settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"rust-analyzer.cargo.target": "wasm32-unknown-emscripten"
}
5 changes: 5 additions & 0 deletions rts/motoko-rts/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions rts/motoko-rts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "motoko-rts"
version = "0.1.0"
authors = ["Ömer Sinan Ağacan <omeragacan@gmail.com>"]
edition = "2018"

[dependencies]
21 changes: 21 additions & 0 deletions rts/motoko-rts/src/array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use crate::common::rts_trap_with;
use crate::types::{skew, Array, SkewedPtr};

/// Returns address of Nth payload field of an array
#[no_mangle]
pub unsafe extern "C" fn array_field_addr(array: SkewedPtr, idx: u32) -> SkewedPtr {
let array_ptr = array.unskew() as *const Array;

if idx >= (*array_ptr).len {
rts_trap_with("Array index out of bounds\0".as_ptr());
}

let payload_begin = array_ptr.offset(1) as *const u32;
skew(payload_begin.offset(idx as isize) as usize)
}

/// Index an array. Does not check bounds.
pub unsafe fn array_idx_unchecked(array_ptr: *const Array, idx: u32) -> SkewedPtr {
let payload_begin = array_ptr.offset(1) as *const u32;
SkewedPtr(*payload_begin.offset(idx as isize) as usize)
}
3 changes: 3 additions & 0 deletions rts/motoko-rts/src/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
extern "C" {
pub fn rts_trap_with(msg: *const u8) -> !;
}
Loading

0 comments on commit cf81ff6

Please sign in to comment.