wasmtime 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -1
- data/README.md +8 -11
- data/lib/wasmtime/require.rb +5 -2
- data/lib/wasmtime/version.rb +1 -1
- data/src/export.rs +19 -0
- data/src/func.rs +12 -37
- data/src/instance.rs +25 -26
- data/src/lib.rs +3 -0
- data/src/memory.rs +45 -4
- data/src/ruby_type.rs +32 -0
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51b9d23eb473612cd8d79f307021bdcf6ccbce2c1e522996af1bf3c1ebb85c1a
|
4
|
+
data.tar.gz: cde5dc2a81f5cc73a4e8abd70268d1e9322bad3093cf7ce8f1d3d13fa44aafda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5a78a30dd600e7c9618c2c0612b5d657d3002e027e826375522455762756b56f4606b433b94070a0227ceb2319321752744d6c86ce613bda672bc3e067c5423
|
7
|
+
data.tar.gz: 301fbc2e124b4653b957cee6e260408a5cefed5743da6bc7327f7a7d153f29f2ba63ddf331cb93da0fbb16f593cdd7f4b555dfae6b242e7c97bc2067b50ffa88
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.2.0] - 2020-05-19
|
11
|
+
|
12
|
+
- Exported functions now live on `Wasmtime::Instance#exports` instead of `#funcs`.
|
13
|
+
- Exports hash is now keyed by strings instead of symbols.
|
14
|
+
- Added support for `Wasmtime::Memory` exports with `#data_size`, `#size` and `#grow` methods.
|
15
|
+
|
10
16
|
## [0.1.0] - 2020-05-07
|
11
17
|
|
12
18
|
### Added
|
@@ -16,5 +22,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
16
22
|
- Support for 32 and 64-bit integers and floats in arguments and as return values.
|
17
23
|
- Require patch for defining a Ruby module with functions for each export.
|
18
24
|
|
19
|
-
[unreleased]: https://github.com/dtcristo/wasmtime-ruby/compare/v0.
|
25
|
+
[unreleased]: https://github.com/dtcristo/wasmtime-ruby/compare/v0.2.0...HEAD
|
26
|
+
[0.2.0]: https://github.com/dtcristo/wasmtime-ruby/releases/tag/v0.2.0
|
20
27
|
[0.1.0]: https://github.com/dtcristo/wasmtime-ruby/releases/tag/v0.1.0
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
<h1>wasmtime-ruby</h1>
|
3
3
|
<p>
|
4
4
|
<strong>
|
5
|
-
<a href="https://github.com/bytecodealliance/wasmtime">Wasmtime</a
|
5
|
+
Ruby bindings for <a href="https://github.com/bytecodealliance/wasmtime">Wasmtime</a>, a WebAssembly runtime
|
6
6
|
</strong>
|
7
7
|
</p>
|
8
8
|
<p>
|
@@ -17,13 +17,10 @@
|
|
17
17
|
|
18
18
|
## Introduction
|
19
19
|
|
20
|
-
This
|
21
|
-
runtime
|
22
|
-
|
23
|
-
|
24
|
-
technology that allows you to write programs that run at near-native speeds in a
|
25
|
-
safe sandboxed environment. Wasmtime is a runtime for WASM programs. This gem
|
26
|
-
embedds Wasmtime in a native extension so you can now run WASM from Ruby.
|
20
|
+
This project provides Ruby bindings for [Wasmtime](https://github.com/bytecodealliance/wasmtime),
|
21
|
+
a [WebAssembly](https://webassembly.org/) runtime. This allows you to execute
|
22
|
+
WASM modules from within Ruby executing at near-native speeds in a safe
|
23
|
+
sandboxed environment.
|
27
24
|
|
28
25
|
This is pretty experimental and not production ready right now. There are quite
|
29
26
|
a few things that aren't built yet, see [TODO](#todo) section below.
|
@@ -42,7 +39,7 @@ Install the `wasmtime` gem. Pre-compiled binaries are available for
|
|
42
39
|
gem install wasmtime
|
43
40
|
```
|
44
41
|
|
45
|
-
WASM has two formats
|
42
|
+
WASM has two formats `.wasm` (binary) and `.wat` (human-readable text). Both
|
46
43
|
formats are supported. With the following `fibonacci.wat` file in your current
|
47
44
|
directory.
|
48
45
|
|
@@ -65,7 +62,7 @@ directory.
|
|
65
62
|
```
|
66
63
|
|
67
64
|
In a ruby file, `require 'wasmtime/require'` to activate the Wasmtime require
|
68
|
-
patch, allowing you to require any
|
65
|
+
patch, allowing you to require any `.wasm` or `.wat` module as if it were a
|
69
66
|
Ruby file. Doing so will internally create a `Wasmtime::Instance` and define a
|
70
67
|
Ruby module with functions for each export.
|
71
68
|
|
@@ -86,7 +83,7 @@ use this approach too.
|
|
86
83
|
require 'wasmtime'
|
87
84
|
|
88
85
|
instance = Wasmtime::Instance.new('fibonacci.wat')
|
89
|
-
puts instance.
|
86
|
+
puts instance.exports['fib'].call(11) #=> 89
|
90
87
|
```
|
91
88
|
|
92
89
|
## Benchmarks
|
data/lib/wasmtime/require.rb
CHANGED
@@ -60,8 +60,11 @@ module Wasmtime
|
|
60
60
|
end
|
61
61
|
mod = Object.const_set(module_name.camelize, Module.new)
|
62
62
|
instance = Wasmtime::Instance.new(absolute_path)
|
63
|
-
instance.
|
64
|
-
|
63
|
+
instance.exports.each do |name, export|
|
64
|
+
case export
|
65
|
+
when Wasmtime::Func
|
66
|
+
mod.define_singleton_method(name) { |*args| export.call(*args) }
|
67
|
+
end
|
65
68
|
end
|
66
69
|
$LOADED_FEATURES << absolute_path
|
67
70
|
true
|
data/lib/wasmtime/version.rb
CHANGED
data/src/export.rs
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
use rutie::{AnyObject, Object};
|
2
|
+
use wasmtime as w;
|
3
|
+
|
4
|
+
use crate::func::{Func, RubyFunc};
|
5
|
+
use crate::memory::RubyMemory;
|
6
|
+
|
7
|
+
pub enum Export {
|
8
|
+
Func(Func),
|
9
|
+
Memory(w::Memory),
|
10
|
+
}
|
11
|
+
|
12
|
+
impl From<Export> for AnyObject {
|
13
|
+
fn from(export: Export) -> Self {
|
14
|
+
match export {
|
15
|
+
Export::Func(func) => RubyFunc::from(func).value().into(),
|
16
|
+
Export::Memory(memory) => RubyMemory::from(memory).value().into(),
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}
|
data/src/func.rs
CHANGED
@@ -8,7 +8,8 @@ use rutie::{
|
|
8
8
|
use std::mem;
|
9
9
|
use wasmtime as w;
|
10
10
|
|
11
|
-
use crate::
|
11
|
+
use crate::ruby_type::RubyType;
|
12
|
+
use crate::vm::raise;
|
12
13
|
|
13
14
|
pub struct Func {
|
14
15
|
func: w::Func,
|
@@ -23,58 +24,24 @@ impl Func {
|
|
23
24
|
self.func.call(args).expect("failed to call func").to_vec()
|
24
25
|
}
|
25
26
|
|
26
|
-
pub fn into_ruby(self) -> RubyFunc {
|
27
|
-
Module::from_existing("Wasmtime")
|
28
|
-
.get_nested_class("Func")
|
29
|
-
.wrap_data(self, &*FUNC_WRAPPER)
|
30
|
-
}
|
31
|
-
|
32
27
|
fn parse_param_types(&self) -> Vec<RubyType> {
|
33
28
|
self.func
|
34
29
|
.ty()
|
35
30
|
.params()
|
36
31
|
.iter()
|
37
|
-
.map(|val_type|
|
32
|
+
.map(|val_type| val_type.into())
|
38
33
|
.collect()
|
39
34
|
}
|
40
35
|
|
41
36
|
fn parse_result_type(&self) -> RubyType {
|
42
37
|
match self.func.ty().results().len() {
|
43
38
|
0 => RubyType::NilClass,
|
44
|
-
1 =>
|
39
|
+
1 => self.func.ty().results().first().unwrap().into(),
|
45
40
|
_ => raise("StandardError", "multiple return values are not supported"),
|
46
41
|
}
|
47
42
|
}
|
48
43
|
}
|
49
44
|
|
50
|
-
fn val_type_to_ruby_type(val_type: &w::ValType) -> RubyType {
|
51
|
-
match val_type {
|
52
|
-
w::ValType::I32 => RubyType::Integer32,
|
53
|
-
w::ValType::I64 => RubyType::Integer64,
|
54
|
-
w::ValType::F32 => RubyType::Float32,
|
55
|
-
w::ValType::F64 => RubyType::Float64,
|
56
|
-
_ => RubyType::Unsupported,
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
#[derive(Debug, Copy, Clone)]
|
61
|
-
enum RubyType {
|
62
|
-
Integer32,
|
63
|
-
Integer64,
|
64
|
-
Float32,
|
65
|
-
Float64,
|
66
|
-
// String,
|
67
|
-
// Boolean,
|
68
|
-
NilClass,
|
69
|
-
Unsupported,
|
70
|
-
}
|
71
|
-
|
72
|
-
impl Into<AnyObject> for RubyType {
|
73
|
-
fn into(self) -> AnyObject {
|
74
|
-
RString::new_utf8(&format!("{:?}", self)).into()
|
75
|
-
}
|
76
|
-
}
|
77
|
-
|
78
45
|
fn translate_incoming(args: Array, param_types: &[RubyType]) -> Vec<w::Val> {
|
79
46
|
if args.length() != param_types.len() {
|
80
47
|
raise(
|
@@ -141,6 +108,14 @@ fn translate_outgoing(native_results: Vec<w::Val>) -> AnyObject {
|
|
141
108
|
wrappable_struct!(Func, FuncWrapper, FUNC_WRAPPER);
|
142
109
|
class!(RubyFunc);
|
143
110
|
|
111
|
+
impl From<Func> for RubyFunc {
|
112
|
+
fn from(func: Func) -> Self {
|
113
|
+
Module::from_existing("Wasmtime")
|
114
|
+
.get_nested_class("Func")
|
115
|
+
.wrap_data(func, &*FUNC_WRAPPER)
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
144
119
|
#[rustfmt::skip]
|
145
120
|
methods!(
|
146
121
|
RubyFunc,
|
data/src/instance.rs
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
use lazy_static::lazy_static;
|
2
|
-
use rutie::{class, methods, wrappable_struct, Hash, Module, Object, RString
|
2
|
+
use rutie::{class, methods, wrappable_struct, AnyObject, Hash, Module, Object, RString};
|
3
3
|
use std::collections::HashMap;
|
4
4
|
use std::fs;
|
5
5
|
use wasmtime as w;
|
6
6
|
|
7
|
+
use crate::export::Export;
|
7
8
|
use crate::func::Func;
|
8
|
-
use crate::memory::Memory;
|
9
9
|
|
10
10
|
pub struct Instance {
|
11
11
|
instance: w::Instance,
|
@@ -27,58 +27,57 @@ impl Instance {
|
|
27
27
|
Instance { instance }
|
28
28
|
}
|
29
29
|
|
30
|
-
fn exports(&self) ->
|
31
|
-
let mut
|
32
|
-
let mut memories = HashMap::new();
|
30
|
+
fn exports(&self) -> HashMap<String, Export> {
|
31
|
+
let mut exports = HashMap::new();
|
33
32
|
|
34
33
|
for export in self.instance.exports() {
|
35
34
|
match export.ty() {
|
36
35
|
w::ExternType::Func(_) => {
|
37
36
|
let name = export.name().to_string();
|
38
|
-
let func = Func::new(export.into_func().
|
39
|
-
|
37
|
+
let func = Func::new(export.into_func().unwrap());
|
38
|
+
exports.insert(name, Export::Func(func));
|
40
39
|
}
|
41
40
|
w::ExternType::Memory(_) => {
|
42
|
-
let
|
43
|
-
|
41
|
+
let name = export.name().to_string();
|
42
|
+
let memory = export.into_memory().unwrap();
|
43
|
+
exports.insert(name, Export::Memory(memory));
|
44
44
|
}
|
45
45
|
_ => {}
|
46
46
|
}
|
47
47
|
}
|
48
48
|
|
49
|
-
|
49
|
+
exports
|
50
50
|
}
|
51
|
+
}
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
functions
|
55
|
-
}
|
53
|
+
wrappable_struct!(Instance, InstanceWrapper, INSTANCE_WRAPPER);
|
54
|
+
class!(RubyInstance);
|
56
55
|
|
57
|
-
|
56
|
+
impl From<Instance> for RubyInstance {
|
57
|
+
fn from(instance: Instance) -> Self {
|
58
58
|
Module::from_existing("Wasmtime")
|
59
59
|
.get_nested_class("Instance")
|
60
|
-
.wrap_data(
|
60
|
+
.wrap_data(instance, &*INSTANCE_WRAPPER)
|
61
61
|
}
|
62
62
|
}
|
63
63
|
|
64
|
-
wrappable_struct!(Instance, InstanceWrapper, INSTANCE_WRAPPER);
|
65
|
-
class!(RubyInstance);
|
66
|
-
|
67
64
|
#[rustfmt::skip]
|
68
65
|
methods!(
|
69
66
|
RubyInstance,
|
70
67
|
itself,
|
71
68
|
|
72
69
|
fn ruby_instance_new(path: RString) -> RubyInstance {
|
73
|
-
Instance::new(path.expect("failed read path").to_string()).
|
70
|
+
Instance::new(path.expect("failed read path").to_string()).into()
|
74
71
|
}
|
75
72
|
|
76
|
-
fn
|
77
|
-
let mut
|
78
|
-
|
79
|
-
|
73
|
+
fn ruby_instance_exports() -> Hash {
|
74
|
+
let mut exports = Hash::new();
|
75
|
+
|
76
|
+
for (export_name, export) in itself.get_data(&*INSTANCE_WRAPPER).exports().into_iter() {
|
77
|
+
exports.store::<RString, AnyObject>(RString::new_utf8(&export_name), export.into());
|
80
78
|
}
|
81
|
-
|
79
|
+
|
80
|
+
exports
|
82
81
|
}
|
83
82
|
);
|
84
83
|
|
@@ -88,7 +87,7 @@ pub fn ruby_init() {
|
|
88
87
|
.define_nested_class("Instance", None)
|
89
88
|
.define(|class| {
|
90
89
|
class.def_self("new", ruby_instance_new);
|
91
|
-
class.def("
|
90
|
+
class.def("exports", ruby_instance_exports);
|
92
91
|
});
|
93
92
|
});
|
94
93
|
}
|
data/src/lib.rs
CHANGED
data/src/memory.rs
CHANGED
@@ -1,7 +1,48 @@
|
|
1
|
-
|
1
|
+
use lazy_static::lazy_static;
|
2
|
+
use rutie::{class, methods, wrappable_struct, AnyObject, Integer, Module, NilClass, Object};
|
3
|
+
use wasmtime as w;
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
5
|
+
wrappable_struct!(w::Memory, MemoryWrapper, MEMORY_WRAPPER);
|
6
|
+
class!(RubyMemory);
|
7
|
+
|
8
|
+
impl From<w::Memory> for RubyMemory {
|
9
|
+
fn from(memory: w::Memory) -> Self {
|
10
|
+
Module::from_existing("Wasmtime")
|
11
|
+
.get_nested_class("Memory")
|
12
|
+
.wrap_data(memory, &*MEMORY_WRAPPER)
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
#[rustfmt::skip]
|
17
|
+
methods!(
|
18
|
+
RubyMemory,
|
19
|
+
itself,
|
20
|
+
|
21
|
+
fn ruby_instance_data_size() -> Integer {
|
22
|
+
Integer::from(itself.get_data(&*MEMORY_WRAPPER).data_size() as u32)
|
6
23
|
}
|
24
|
+
|
25
|
+
fn ruby_instance_size() -> Integer {
|
26
|
+
Integer::from(itself.get_data(&*MEMORY_WRAPPER).size())
|
27
|
+
}
|
28
|
+
|
29
|
+
fn ruby_instance_grow(delta: Integer) -> AnyObject {
|
30
|
+
let memory = itself.get_data(&*MEMORY_WRAPPER);
|
31
|
+
let delta = delta.unwrap().to_i32();
|
32
|
+
if delta < 0 { return NilClass::new().into() }
|
33
|
+
match memory.grow(delta as u32) {
|
34
|
+
Ok(original) => Integer::from(original).into(),
|
35
|
+
Err(_) => NilClass::new().into()
|
36
|
+
}
|
37
|
+
}
|
38
|
+
);
|
39
|
+
|
40
|
+
pub fn ruby_init() {
|
41
|
+
Module::from_existing("Wasmtime").define(|module| {
|
42
|
+
module.define_nested_class("Memory", None).define(|class| {
|
43
|
+
class.def("data_size", ruby_instance_data_size);
|
44
|
+
class.def("size", ruby_instance_size);
|
45
|
+
class.def("grow", ruby_instance_grow);
|
46
|
+
});
|
47
|
+
});
|
7
48
|
}
|
data/src/ruby_type.rs
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
use rutie::{AnyObject, RString};
|
2
|
+
use wasmtime as w;
|
3
|
+
|
4
|
+
#[derive(Debug, Copy, Clone)]
|
5
|
+
pub enum RubyType {
|
6
|
+
Integer32,
|
7
|
+
Integer64,
|
8
|
+
Float32,
|
9
|
+
Float64,
|
10
|
+
// String,
|
11
|
+
// Boolean,
|
12
|
+
NilClass,
|
13
|
+
Unsupported,
|
14
|
+
}
|
15
|
+
|
16
|
+
impl From<RubyType> for AnyObject {
|
17
|
+
fn from(ruby_type: RubyType) -> AnyObject {
|
18
|
+
RString::new_utf8(&format!("{:?}", ruby_type)).into()
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
impl From<&w::ValType> for RubyType {
|
23
|
+
fn from(val_type: &w::ValType) -> Self {
|
24
|
+
match val_type {
|
25
|
+
w::ValType::I32 => RubyType::Integer32,
|
26
|
+
w::ValType::I64 => RubyType::Integer64,
|
27
|
+
w::ValType::F32 => RubyType::Float32,
|
28
|
+
w::ValType::F64 => RubyType::Float64,
|
29
|
+
_ => RubyType::Unsupported,
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
metadata
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wasmtime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Cristofaro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-05-
|
11
|
+
date: 2020-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
14
|
-
your Ruby project.
|
13
|
+
description:
|
15
14
|
email:
|
16
15
|
- david@dtcristo.com
|
17
16
|
executables: []
|
@@ -33,10 +32,12 @@ files:
|
|
33
32
|
- lib/wasmtime/refinements.rb
|
34
33
|
- lib/wasmtime/require.rb
|
35
34
|
- lib/wasmtime/version.rb
|
35
|
+
- src/export.rs
|
36
36
|
- src/func.rs
|
37
37
|
- src/instance.rs
|
38
38
|
- src/lib.rs
|
39
39
|
- src/memory.rs
|
40
|
+
- src/ruby_type.rs
|
40
41
|
- src/vm.rs
|
41
42
|
homepage: https://github.com/dtcristo/wasmtime-ruby
|
42
43
|
licenses:
|
@@ -62,5 +63,5 @@ requirements: []
|
|
62
63
|
rubygems_version: 3.1.2
|
63
64
|
signing_key:
|
64
65
|
specification_version: 4
|
65
|
-
summary: Wasmtime WebAssembly runtime
|
66
|
+
summary: Ruby bindings for Wasmtime, a WebAssembly runtime
|
66
67
|
test_files: []
|