wasmer 0.1.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.cargo/config +1 -1
- data/.github/workflows/documentation.yml +50 -0
- data/.github/workflows/test.yml +73 -0
- data/.gitignore +3 -1
- data/CHANGELOG.md +225 -0
- data/Cargo.lock +747 -708
- data/Cargo.toml +7 -21
- data/Gemfile +2 -3
- data/LICENSE +21 -0
- data/README.md +1 -0
- data/Rakefile +4 -3
- data/bors.toml +6 -0
- data/crates/rutie-derive-macros/Cargo.toml +19 -0
- data/crates/rutie-derive-macros/README.md +4 -0
- data/crates/rutie-derive-macros/src/class.rs +156 -0
- data/crates/rutie-derive-macros/src/function.rs +178 -0
- data/crates/rutie-derive-macros/src/lib.rs +27 -0
- data/crates/rutie-derive-macros/src/methods.rs +282 -0
- data/crates/rutie-derive/Cargo.toml +14 -0
- data/crates/rutie-derive/README.md +97 -0
- data/crates/rutie-derive/src/lib.rs +4 -0
- data/crates/rutie-derive/src/upcast.rs +47 -0
- data/crates/rutie-test/Cargo.toml +10 -0
- data/crates/rutie-test/src/lib.rs +38 -0
- data/crates/wasmer/Cargo.toml +27 -0
- data/crates/wasmer/README.md +229 -0
- data/crates/wasmer/src/doc.rs +1512 -0
- data/crates/wasmer/src/error.rs +55 -0
- data/crates/wasmer/src/exports.rs +107 -0
- data/crates/wasmer/src/externals/function.rs +159 -0
- data/crates/wasmer/src/externals/global.rs +62 -0
- data/crates/wasmer/src/externals/memory.rs +117 -0
- data/crates/wasmer/src/externals/mod.rs +9 -0
- data/crates/wasmer/src/externals/table.rs +41 -0
- data/crates/wasmer/src/import_object.rs +78 -0
- data/crates/wasmer/src/instance.rs +45 -0
- data/crates/wasmer/src/lib.rs +307 -0
- data/crates/wasmer/src/memory/mod.rs +1 -0
- data/crates/wasmer/src/memory/views.rs +112 -0
- data/crates/wasmer/src/module.rs +106 -0
- data/crates/wasmer/src/prelude.rs +3 -0
- data/crates/wasmer/src/store.rs +22 -0
- data/crates/wasmer/src/types.rs +396 -0
- data/crates/wasmer/src/values.rs +84 -0
- data/crates/wasmer/src/wasi.rs +226 -0
- data/crates/wasmer/src/wat.rs +20 -0
- data/justfile +20 -2
- data/lib/wasmer.rb +29 -3
- data/wasmer.gemspec +8 -12
- metadata +53 -49
- data/.circleci/config.yml +0 -70
- data/README.md +0 -279
- data/lib/wasmer/version.rb +0 -3
- data/src/instance.rs +0 -282
- data/src/lib.rs +0 -98
- data/src/memory/mod.rs +0 -120
- data/src/memory/view.rs +0 -127
- data/src/module.rs +0 -28
data/.circleci/config.yml
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
version: 2.1
|
2
|
-
|
3
|
-
# List of all jobs.
|
4
|
-
jobs:
|
5
|
-
# Build and test the project the project.
|
6
|
-
build_and_test:
|
7
|
-
docker:
|
8
|
-
- image: circleci/ruby:latest
|
9
|
-
steps:
|
10
|
-
# Update the project.
|
11
|
-
- checkout
|
12
|
-
|
13
|
-
# If the cache exists, loads it.
|
14
|
-
- restore_cache:
|
15
|
-
keys:
|
16
|
-
- v1-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
17
|
-
- v1-linux-{{ arch }}
|
18
|
-
|
19
|
-
# Install Rust.
|
20
|
-
- run:
|
21
|
-
name: Install Rust
|
22
|
-
command: |
|
23
|
-
test -d /usr/local/cargo || curl https://sh.rustup.rs -sSf | sh -s -- -y
|
24
|
-
|
25
|
-
# Install `just` used to manage the project.
|
26
|
-
- run:
|
27
|
-
name: Install just
|
28
|
-
command: |
|
29
|
-
export PATH="$HOME/.cargo/bin:$PATH"
|
30
|
-
test -f $HOME/.cargo/bin/just || cargo install just
|
31
|
-
|
32
|
-
# Compile the Ruby extension.
|
33
|
-
- run:
|
34
|
-
name: Compile the Ruby extension
|
35
|
-
command: |
|
36
|
-
export PATH="$HOME/.cargo/bin:$PATH"
|
37
|
-
just build
|
38
|
-
|
39
|
-
# Save everything in the cache (except the `just` binary).
|
40
|
-
- save_cache:
|
41
|
-
paths:
|
42
|
-
- /usr/local/cargo/registry
|
43
|
-
- target/release/.fingerprint
|
44
|
-
- target/release/build
|
45
|
-
- target/release/deps
|
46
|
-
key: v1-linux-{{ arch }}-{{ checksum "Cargo.lock" }}
|
47
|
-
|
48
|
-
# Run the extension test suites.
|
49
|
-
- run:
|
50
|
-
name: Test the extension
|
51
|
-
command: |
|
52
|
-
export PATH="$HOME/.cargo/bin:$PATH"
|
53
|
-
gem install bundler
|
54
|
-
just test
|
55
|
-
|
56
|
-
|
57
|
-
# List of workflows.
|
58
|
-
workflows:
|
59
|
-
version: 2
|
60
|
-
|
61
|
-
# The build workflow.
|
62
|
-
build:
|
63
|
-
jobs:
|
64
|
-
# Run the `build_and_test` job for all branches and all tags.
|
65
|
-
- build_and_test:
|
66
|
-
filters:
|
67
|
-
branches:
|
68
|
-
only: /.*/
|
69
|
-
tags:
|
70
|
-
only: /.*/
|
data/README.md
DELETED
@@ -1,279 +0,0 @@
|
|
1
|
-
<p align="center">
|
2
|
-
<a href="https://wasmer.io" target="_blank" rel="noopener noreferrer">
|
3
|
-
<img width="400" src="https://raw.githubusercontent.com/wasmerio/wasmer/master/logo.png" alt="Wasmer logo">
|
4
|
-
</a>
|
5
|
-
</p>
|
6
|
-
|
7
|
-
<p align="center">
|
8
|
-
<a href="https://spectrum.chat/wasmer">
|
9
|
-
<img src="https://withspectrum.github.io/badge/badge.svg" alt="Join the Wasmer Community"></a>
|
10
|
-
<a href="https://github.com/wasmerio/wasmer/blob/master/LICENSE">
|
11
|
-
<img src="https://img.shields.io/github/license/wasmerio/wasmer.svg" alt="License"></a>
|
12
|
-
</p>
|
13
|
-
|
14
|
-
# The Ruby extension to run WebAssembly
|
15
|
-
|
16
|
-
The goal of the project is to be able to run WebAssembly binaries from
|
17
|
-
Ruby directly. So much fun coming!
|
18
|
-
|
19
|
-
_Under Development, don't use it in product yet_.
|
20
|
-
|
21
|
-
## What is WebAssembly?
|
22
|
-
|
23
|
-
Quoting [the WebAssembly site](https://webassembly.org/):
|
24
|
-
|
25
|
-
> WebAssembly (abbreviated Wasm) is a binary instruction format for a
|
26
|
-
> stack-based virtual machine. Wasm is designed as a portable target
|
27
|
-
> for compilation of high-level languages like C/C++/Rust, enabling
|
28
|
-
> deployment on the web for client and server applications.
|
29
|
-
|
30
|
-
About speed:
|
31
|
-
|
32
|
-
> WebAssembly aims to execute at native speed by taking advantage of
|
33
|
-
> [common hardware
|
34
|
-
> capabilities](https://webassembly.org/docs/portability/#assumptions-for-efficient-execution)
|
35
|
-
> available on a wide range of platforms.
|
36
|
-
|
37
|
-
About safety:
|
38
|
-
|
39
|
-
> WebAssembly describes a memory-safe, sandboxed [execution
|
40
|
-
> environment](https://webassembly.org/docs/semantics/#linear-memory) […].
|
41
|
-
|
42
|
-
## Example
|
43
|
-
|
44
|
-
There is a toy program in `examples/simple.rs`, written in Rust (or
|
45
|
-
any other language that compiles to Wasm):
|
46
|
-
|
47
|
-
```rust
|
48
|
-
#[no_mangle]
|
49
|
-
pub extern fn sum(x: i32, y: i32) -> i32 {
|
50
|
-
x + y
|
51
|
-
}
|
52
|
-
```
|
53
|
-
|
54
|
-
Once this program compiled to WebAssembly, we end up with a
|
55
|
-
`examples/simple.wasm` binary file.
|
56
|
-
|
57
|
-
Then, we can execute it in Ruby (!) with the `examples/simple.rb` file:
|
58
|
-
|
59
|
-
```rb
|
60
|
-
require "wasmer"
|
61
|
-
|
62
|
-
bytes = IO.read "simple.wasm", mode: "rb"
|
63
|
-
instance = Instance.new bytes
|
64
|
-
puts instance.exports.sum 1, 2
|
65
|
-
```
|
66
|
-
|
67
|
-
And then, finally, enjoy by running:
|
68
|
-
|
69
|
-
```sh
|
70
|
-
$ ruby simple.rb
|
71
|
-
3
|
72
|
-
```
|
73
|
-
|
74
|
-
## API documentation
|
75
|
-
|
76
|
-
### The `Instance` class
|
77
|
-
|
78
|
-
Instantiates a WebAssembly module represented by bytes, and calls exported functions on it:
|
79
|
-
|
80
|
-
```ruby
|
81
|
-
require "wasmer"
|
82
|
-
|
83
|
-
# Get the Wasm module as bytes.
|
84
|
-
wasm_bytes = IO.read "my_program.wasm", mode: "rb"
|
85
|
-
|
86
|
-
# Instantiates the Wasm module.
|
87
|
-
instance = Instance.new wasm_bytes
|
88
|
-
|
89
|
-
# Call a function on it.
|
90
|
-
result = instance.exports.sum 1, 2
|
91
|
-
|
92
|
-
puts result # 3
|
93
|
-
```
|
94
|
-
|
95
|
-
All exported functions are accessible on the `exports`
|
96
|
-
getter. Arguments of these functions are automatically casted to
|
97
|
-
WebAssembly values.
|
98
|
-
|
99
|
-
The `memory` getter exposes the `Memory` class representing the memory
|
100
|
-
of that particular instance, e.g.:
|
101
|
-
|
102
|
-
```ruby
|
103
|
-
view = instance.memory.uint8_view
|
104
|
-
```
|
105
|
-
|
106
|
-
See below for more information.
|
107
|
-
|
108
|
-
### The `Memory` class
|
109
|
-
|
110
|
-
A WebAssembly instance has its own memory, represented by the `Memory`
|
111
|
-
class. It is accessible by the `Instance.memory` getter.
|
112
|
-
|
113
|
-
The `Memory` class offers methods to create views of the memory
|
114
|
-
internal buffer, e.g. `uint8_view`, `int8_view`, `uint16_view`
|
115
|
-
etc. All these methods accept one optional argument: `offset`, to
|
116
|
-
subset the memory buffer at a particular offset. These methods return
|
117
|
-
respectively a `*Array` object, i.e. `uint8_view` returns a
|
118
|
-
`Uint8Array` object etc.
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
offset = 7
|
122
|
-
view = instance.memory.uint8_view offset
|
123
|
-
|
124
|
-
puts view[0]
|
125
|
-
```
|
126
|
-
|
127
|
-
#### The `*Array` classes
|
128
|
-
|
129
|
-
These classes represent views over a memory buffer of an instance.
|
130
|
-
|
131
|
-
| Class | View buffer as a sequence of… | Bytes per element |
|
132
|
-
|-|-|-|
|
133
|
-
| `Int8Array` | `int8` | 1 |
|
134
|
-
| `Uint8Array` | `uint8` | 1 |
|
135
|
-
| `Int16Array` | `int16` | 2 |
|
136
|
-
| `Uint16Array` | `uint16` | 2 |
|
137
|
-
| `Int32Array` | `int32` | 4 |
|
138
|
-
| `Uint32Array` | `uint32` | 4 |
|
139
|
-
|
140
|
-
All these classes share the same implementation. Taking the example of
|
141
|
-
`Uint8Array`, the class looks like this:
|
142
|
-
|
143
|
-
```ruby
|
144
|
-
class Uint8Array
|
145
|
-
def bytes_per_element
|
146
|
-
def length
|
147
|
-
def [](index)
|
148
|
-
def []=(index, value)
|
149
|
-
end
|
150
|
-
```
|
151
|
-
|
152
|
-
Let's see it in action:
|
153
|
-
|
154
|
-
```ruby
|
155
|
-
require "wasmer"
|
156
|
-
|
157
|
-
# Get the Wasm module as bytes.
|
158
|
-
wasm_bytes = IO.read "my_program.wasm", mode: "rb"
|
159
|
-
|
160
|
-
# Instantiates the Wasm module.
|
161
|
-
instance = Instance.new wasm_bytes
|
162
|
-
|
163
|
-
# Call a function that returns a pointer to a string for instance.
|
164
|
-
pointer = instance.exports.return_string
|
165
|
-
|
166
|
-
# Get the memory view, with the offset set to `pointer` (default is 0).
|
167
|
-
memory = instance.memory.uint8_view pointer
|
168
|
-
|
169
|
-
# Read the string pointed by the pointer.
|
170
|
-
nth = 0
|
171
|
-
string = ""
|
172
|
-
|
173
|
-
while true
|
174
|
-
char = memory[nth]
|
175
|
-
|
176
|
-
if 0 == char
|
177
|
-
break
|
178
|
-
end
|
179
|
-
|
180
|
-
string += char.chr
|
181
|
-
nth += 1
|
182
|
-
end
|
183
|
-
|
184
|
-
puts string # Hello, World!
|
185
|
-
```
|
186
|
-
|
187
|
-
Notice that `*Array` treat bytes in little-endian, as required by the
|
188
|
-
WebAssembly specification, [Chapter Structure, Section Instructions,
|
189
|
-
Sub-Section Memory
|
190
|
-
Instructions](https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions):
|
191
|
-
|
192
|
-
> All values are read and written in [little
|
193
|
-
> endian](https://en.wikipedia.org/wiki/Endianness#Little-endian) byte
|
194
|
-
> order.
|
195
|
-
|
196
|
-
Each view shares the same memory buffer internally. Let's have some fun:
|
197
|
-
|
198
|
-
```ruby
|
199
|
-
int8 = instance.memory.int8_view
|
200
|
-
int16 = instance.memory.int16_view
|
201
|
-
int32 = instance.memory.int32_view
|
202
|
-
|
203
|
-
b₁
|
204
|
-
┌┬┬┬┬┬┬┐
|
205
|
-
int8[0] = 0b00000001
|
206
|
-
b₂
|
207
|
-
┌┬┬┬┬┬┬┐
|
208
|
-
int8[1] = 0b00000100
|
209
|
-
b₃
|
210
|
-
┌┬┬┬┬┬┬┐
|
211
|
-
int8[2] = 0b00010000
|
212
|
-
b₄
|
213
|
-
┌┬┬┬┬┬┬┐
|
214
|
-
int8[3] = 0b01000000
|
215
|
-
|
216
|
-
// No surprise with the following assertions.
|
217
|
-
b₁
|
218
|
-
┌┬┬┬┬┬┬┐
|
219
|
-
assert_equal 0b00000001, int8[0]
|
220
|
-
b₂
|
221
|
-
┌┬┬┬┬┬┬┐
|
222
|
-
assert_equal 0b00000100, int8[1]
|
223
|
-
b₃
|
224
|
-
┌┬┬┬┬┬┬┐
|
225
|
-
assert_equal 0b00010000, int8[2]
|
226
|
-
b₄
|
227
|
-
┌┬┬┬┬┬┬┐
|
228
|
-
assert_equal 0b01000000, int8[3]
|
229
|
-
|
230
|
-
// The `int16` view reads 2 bytes.
|
231
|
-
b₂ b₁
|
232
|
-
┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐
|
233
|
-
assert_equal 0b00000100_00000001, int16[0]
|
234
|
-
b₄ b₃
|
235
|
-
┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐
|
236
|
-
assert_equal 0b01000000_00010000, int16[1]
|
237
|
-
|
238
|
-
// The `int32` view reads 4 bytes.
|
239
|
-
b₄ b₃ b₂ b₁
|
240
|
-
┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐
|
241
|
-
assert_equal 0b01000000_00010000_00000100_00000001, int32[0]
|
242
|
-
```
|
243
|
-
|
244
|
-
### The `Module` class
|
245
|
-
|
246
|
-
The `Module` class contains one static method `validate`, that checks
|
247
|
-
whether the given bytes represent valid WebAssembly bytes:
|
248
|
-
|
249
|
-
```ruby
|
250
|
-
require "wasmer"
|
251
|
-
|
252
|
-
wasm_bytes = IO.read "my_program.wasm", mode: "rb"
|
253
|
-
|
254
|
-
if not Module.validate wasm_bytes
|
255
|
-
puts "The program seems corrupted."
|
256
|
-
end
|
257
|
-
```
|
258
|
-
|
259
|
-
This function returns a boolean.
|
260
|
-
|
261
|
-
## Install and Testing
|
262
|
-
|
263
|
-
To compile the entire project, run the following commands:
|
264
|
-
|
265
|
-
```sh
|
266
|
-
$ just build
|
267
|
-
$ just test
|
268
|
-
$ ruby examples/simple.rb
|
269
|
-
```
|
270
|
-
|
271
|
-
(Yes, you need [`just`](https://github.com/casey/just/)).
|
272
|
-
|
273
|
-
## License
|
274
|
-
|
275
|
-
The entire project is under the BSD-3-Clause license. Please read [the
|
276
|
-
`LICENSE` file][license].
|
277
|
-
|
278
|
-
|
279
|
-
[license]: https://github.com/wasmerio/wasmer/blob/master/LICENSE
|
data/lib/wasmer/version.rb
DELETED
data/src/instance.rs
DELETED
@@ -1,282 +0,0 @@
|
|
1
|
-
//! The `Instance` WebAssembly class.
|
2
|
-
|
3
|
-
use crate::memory::{Memory, RubyMemory, MEMORY_WRAPPER};
|
4
|
-
use lazy_static::lazy_static;
|
5
|
-
use rutie::{
|
6
|
-
class, methods,
|
7
|
-
rubysys::{class, value::ValueType},
|
8
|
-
types::{Argc, Value},
|
9
|
-
util::str_to_cstring,
|
10
|
-
wrappable_struct, AnyException, AnyObject, Array, Class, Exception, Fixnum, Float, Object,
|
11
|
-
RString, Symbol, VM,
|
12
|
-
};
|
13
|
-
use std::{mem, rc::Rc};
|
14
|
-
use wasmer_runtime::{self as runtime, imports, Export};
|
15
|
-
use wasmer_runtime_core::types::Type;
|
16
|
-
|
17
|
-
/// The `ExportedFunctions` Ruby class.
|
18
|
-
pub struct ExportedFunctions {
|
19
|
-
/// The WebAssembly runtime.
|
20
|
-
instance: Rc<runtime::Instance>,
|
21
|
-
}
|
22
|
-
|
23
|
-
impl ExportedFunctions {
|
24
|
-
/// Create a new instance of the `ExportedFunctions` Ruby class.
|
25
|
-
pub fn new(instance: Rc<runtime::Instance>) -> Self {
|
26
|
-
Self { instance }
|
27
|
-
}
|
28
|
-
|
29
|
-
/// Call an exported function on the given WebAssembly instance.
|
30
|
-
pub fn method_missing(&self, method_name: &str, arguments: Array) -> AnyObject {
|
31
|
-
let function = self
|
32
|
-
.instance
|
33
|
-
.dyn_func(method_name)
|
34
|
-
.map_err(|_| {
|
35
|
-
VM::raise_ex(AnyException::new(
|
36
|
-
"RuntimeError",
|
37
|
-
Some(&format!("Function `{}` does not exist.", method_name)),
|
38
|
-
))
|
39
|
-
})
|
40
|
-
.unwrap();
|
41
|
-
let signature = function.signature();
|
42
|
-
let parameters = signature.params();
|
43
|
-
let number_of_parameters = parameters.len() as isize;
|
44
|
-
let number_of_arguments = arguments.length() as isize;
|
45
|
-
let diff: isize = number_of_parameters - number_of_arguments;
|
46
|
-
|
47
|
-
if diff > 0 {
|
48
|
-
VM::raise_ex(AnyException::new(
|
49
|
-
"ArgumentError",
|
50
|
-
Some(&format!(
|
51
|
-
"Missing {} argument(s) when calling `{}`: Expect {} argument(s), given {}.",
|
52
|
-
diff, method_name, number_of_parameters, number_of_arguments
|
53
|
-
)),
|
54
|
-
));
|
55
|
-
unreachable!();
|
56
|
-
} else if diff < 0 {
|
57
|
-
VM::raise_ex(AnyException::new(
|
58
|
-
"ArgumentError",
|
59
|
-
Some(&format!(
|
60
|
-
"Given {} extra argument(s) when calling `{}`: Expect {} argument(s), given {}.",
|
61
|
-
diff.abs(), method_name, number_of_parameters, number_of_arguments
|
62
|
-
)),
|
63
|
-
));
|
64
|
-
unreachable!();
|
65
|
-
}
|
66
|
-
|
67
|
-
let mut function_arguments =
|
68
|
-
Vec::<runtime::Value>::with_capacity(number_of_parameters as usize);
|
69
|
-
|
70
|
-
for (nth, (parameter, argument)) in parameters.iter().zip(arguments.into_iter()).enumerate()
|
71
|
-
{
|
72
|
-
let value = match (parameter, argument.ty()) {
|
73
|
-
(Type::I32, ValueType::Fixnum) => runtime::Value::I32(
|
74
|
-
argument
|
75
|
-
.try_convert_to::<Fixnum>()
|
76
|
-
.map_err(|_| {
|
77
|
-
VM::raise_ex(AnyException::new(
|
78
|
-
"TypeError",
|
79
|
-
Some(&format!(
|
80
|
-
"Cannot convert argument #{} to a WebAssembly i32 value.",
|
81
|
-
nth + 1
|
82
|
-
)),
|
83
|
-
))
|
84
|
-
})
|
85
|
-
.unwrap()
|
86
|
-
.to_i32(),
|
87
|
-
),
|
88
|
-
(Type::I64, ValueType::Fixnum) => runtime::Value::I64(
|
89
|
-
argument
|
90
|
-
.try_convert_to::<Fixnum>()
|
91
|
-
.map_err(|_| {
|
92
|
-
VM::raise_ex(AnyException::new(
|
93
|
-
"TypeError",
|
94
|
-
Some(&format!(
|
95
|
-
"Cannot convert argument #{} to a WebAssembly i64 value.",
|
96
|
-
nth + 1
|
97
|
-
)),
|
98
|
-
))
|
99
|
-
})
|
100
|
-
.unwrap()
|
101
|
-
.to_i64(),
|
102
|
-
),
|
103
|
-
(Type::F32, ValueType::Float) => runtime::Value::F32(
|
104
|
-
argument
|
105
|
-
.try_convert_to::<Float>()
|
106
|
-
.map_err(|_| {
|
107
|
-
VM::raise_ex(AnyException::new(
|
108
|
-
"TypeError",
|
109
|
-
Some(&format!(
|
110
|
-
"Cannot convert argument #{} to a WebAssembly f32 value.",
|
111
|
-
nth + 1
|
112
|
-
)),
|
113
|
-
))
|
114
|
-
})
|
115
|
-
.unwrap()
|
116
|
-
.to_f64() as f32,
|
117
|
-
),
|
118
|
-
(Type::F64, ValueType::Float) => runtime::Value::F64(
|
119
|
-
argument
|
120
|
-
.try_convert_to::<Float>()
|
121
|
-
.map_err(|_| {
|
122
|
-
VM::raise_ex(AnyException::new(
|
123
|
-
"TypeError",
|
124
|
-
Some(&format!(
|
125
|
-
"Cannot convert argument #{} to a WebAssembly f64 value.",
|
126
|
-
nth + 1
|
127
|
-
)),
|
128
|
-
))
|
129
|
-
})
|
130
|
-
.unwrap()
|
131
|
-
.to_f64(),
|
132
|
-
),
|
133
|
-
(_, ty) => {
|
134
|
-
VM::raise_ex(AnyException::new(
|
135
|
-
"ArgumentError",
|
136
|
-
Some(&format!(
|
137
|
-
"Cannot convert argument #{} to a WebAssembly value. Only integers and floats are supported. Given `{:?}`.",
|
138
|
-
nth + 1,
|
139
|
-
ty
|
140
|
-
))));
|
141
|
-
unreachable!()
|
142
|
-
}
|
143
|
-
};
|
144
|
-
|
145
|
-
function_arguments.push(value);
|
146
|
-
}
|
147
|
-
|
148
|
-
let results = function
|
149
|
-
.call(function_arguments.as_slice())
|
150
|
-
.map_err(|e| VM::raise_ex(AnyException::new("RuntimeError", Some(&format!("{}", e)))))
|
151
|
-
.unwrap();
|
152
|
-
|
153
|
-
match results[0] {
|
154
|
-
runtime::Value::I32(result) => Fixnum::new(result as i64).into(),
|
155
|
-
runtime::Value::I64(result) => Fixnum::new(result).into(),
|
156
|
-
runtime::Value::F32(result) => Float::new(result as f64).into(),
|
157
|
-
runtime::Value::F64(result) => Float::new(result).into(),
|
158
|
-
}
|
159
|
-
}
|
160
|
-
}
|
161
|
-
|
162
|
-
wrappable_struct!(
|
163
|
-
ExportedFunctions,
|
164
|
-
ExportedFunctionsWrapper,
|
165
|
-
EXPORTED_FUNCTIONS_WRAPPER
|
166
|
-
);
|
167
|
-
|
168
|
-
class!(RubyExportedFunctions);
|
169
|
-
|
170
|
-
/// Glue code to call the `ExportedFunctions.method_missing` method.
|
171
|
-
pub extern "C" fn ruby_exported_functions_method_missing(
|
172
|
-
argc: Argc,
|
173
|
-
argv: *const AnyObject,
|
174
|
-
itself: RubyExportedFunctions,
|
175
|
-
) -> AnyObject {
|
176
|
-
let arguments = Value::from(0);
|
177
|
-
|
178
|
-
unsafe {
|
179
|
-
let argv_pointer: *const Value = mem::transmute(argv);
|
180
|
-
|
181
|
-
class::rb_scan_args(argc, argv_pointer, str_to_cstring("*").as_ptr(), &arguments)
|
182
|
-
};
|
183
|
-
|
184
|
-
let mut arguments = Array::from(arguments);
|
185
|
-
let method_name = unsafe { arguments.shift().to::<Symbol>() };
|
186
|
-
let method_name = method_name.to_str();
|
187
|
-
|
188
|
-
itself
|
189
|
-
.get_data(&*EXPORTED_FUNCTIONS_WRAPPER)
|
190
|
-
.method_missing(method_name, arguments)
|
191
|
-
}
|
192
|
-
|
193
|
-
/// The `Instance` Ruby class.
|
194
|
-
pub struct Instance {
|
195
|
-
/// The WebAssembly instance.
|
196
|
-
instance: Rc<runtime::Instance>,
|
197
|
-
}
|
198
|
-
|
199
|
-
impl Instance {
|
200
|
-
/// Create a new instance of the `Instance` Ruby class.
|
201
|
-
/// The constructor receives bytes from a string.
|
202
|
-
pub fn new(bytes: &[u8]) -> Self {
|
203
|
-
let import_object = imports! {};
|
204
|
-
let instance = Rc::new(
|
205
|
-
runtime::instantiate(bytes, &import_object)
|
206
|
-
.map_err(|e| {
|
207
|
-
VM::raise_ex(AnyException::new(
|
208
|
-
"RuntimeError",
|
209
|
-
Some(&format!("Failed to instantiate the module:\n {}", e)),
|
210
|
-
))
|
211
|
-
})
|
212
|
-
.unwrap(),
|
213
|
-
);
|
214
|
-
|
215
|
-
Self { instance }
|
216
|
-
}
|
217
|
-
}
|
218
|
-
|
219
|
-
wrappable_struct!(Instance, InstanceWrapper, INSTANCE_WRAPPER);
|
220
|
-
|
221
|
-
class!(RubyInstance);
|
222
|
-
|
223
|
-
#[rustfmt::skip]
|
224
|
-
methods!(
|
225
|
-
RubyInstance,
|
226
|
-
_itself,
|
227
|
-
// Glue code to call the `Instance.new` method.
|
228
|
-
fn ruby_instance_new(bytes: RString) -> AnyObject {
|
229
|
-
let instance = Instance::new(
|
230
|
-
bytes
|
231
|
-
.map_err(|_| {
|
232
|
-
VM::raise_ex(AnyException::new(
|
233
|
-
"ArgumentError",
|
234
|
-
Some("WebAssembly module must be represented by Ruby bytes only."),
|
235
|
-
))
|
236
|
-
})
|
237
|
-
.unwrap()
|
238
|
-
.to_bytes_unchecked(),
|
239
|
-
);
|
240
|
-
let exported_functions = ExportedFunctions::new(instance.instance.clone());
|
241
|
-
|
242
|
-
let memory = instance
|
243
|
-
.instance
|
244
|
-
.exports()
|
245
|
-
.find_map(|(_, export)| match export {
|
246
|
-
Export::Memory(memory) => Some(Memory::new(Rc::new(memory))),
|
247
|
-
_ => None,
|
248
|
-
})
|
249
|
-
.ok_or_else(|| VM::raise_ex(AnyException::new("RuntimeError", Some("The WebAssembly module has no exported memory."))))
|
250
|
-
.unwrap();
|
251
|
-
|
252
|
-
let mut ruby_instance: AnyObject =
|
253
|
-
Class::from_existing("Instance").wrap_data(instance, &*INSTANCE_WRAPPER);
|
254
|
-
|
255
|
-
let ruby_exported_functions: RubyExportedFunctions =
|
256
|
-
Class::from_existing("ExportedFunctions")
|
257
|
-
.wrap_data(exported_functions, &*EXPORTED_FUNCTIONS_WRAPPER);
|
258
|
-
|
259
|
-
ruby_instance.instance_variable_set("@exports", ruby_exported_functions);
|
260
|
-
|
261
|
-
let ruby_memory: RubyMemory =
|
262
|
-
Class::from_existing("Memory").wrap_data(memory, &*MEMORY_WRAPPER);
|
263
|
-
|
264
|
-
ruby_instance.instance_variable_set("@memory", ruby_memory);
|
265
|
-
|
266
|
-
ruby_instance
|
267
|
-
}
|
268
|
-
|
269
|
-
// Glue code to call the `Instance.exports` getter method.
|
270
|
-
fn ruby_instance_exported_functions() -> RubyExportedFunctions {
|
271
|
-
unsafe {
|
272
|
-
_itself
|
273
|
-
.instance_variable_get("@exports")
|
274
|
-
.to::<RubyExportedFunctions>()
|
275
|
-
}
|
276
|
-
}
|
277
|
-
|
278
|
-
// Glue code to call the `Instance.memory` getter method.
|
279
|
-
fn ruby_instance_memory() -> RubyMemory {
|
280
|
-
unsafe { _itself.instance_variable_get("@memory").to::<RubyMemory>() }
|
281
|
-
}
|
282
|
-
);
|