wasmtime 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|