Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define Instance, Module, etc. inside Wasmer module #4

Merged
merged 1 commit into from
May 7, 2019
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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Then, we can execute it in Ruby (!) with the `examples/simple.rb` file:
require "wasmer"

bytes = IO.read "simple.wasm", mode: "rb"
instance = Instance.new bytes
instance = Wasmer::Instance.new bytes
puts instance.exports.sum 1, 2
```

Expand All @@ -85,7 +85,7 @@ require "wasmer"
wasm_bytes = IO.read "my_program.wasm", mode: "rb"

# Instantiates the Wasm module.
instance = Instance.new wasm_bytes
instance = Wasmer::Instance.new wasm_bytes

# Call a function on it.
result = instance.exports.sum 1, 2
Expand All @@ -109,7 +109,7 @@ See below for more information.
## The `Memory` class

A WebAssembly instance has its own memory, represented by the `Memory`
class. It is accessible by the `Instance.memory` getter.
class. It is accessible by the `Wasmer::Instance.memory` getter.

The `Memory` class offers methods to create views of the memory
internal buffer, e.g. `uint8_view`, `int8_view`, `uint16_view`
Expand Down Expand Up @@ -159,7 +159,7 @@ require "wasmer"
wasm_bytes = IO.read "my_program.wasm", mode: "rb"

# Instantiates the Wasm module.
instance = Instance.new wasm_bytes
instance = Wasmer::Instance.new wasm_bytes

# Call a function that returns a pointer to a string for instance.
pointer = instance.exports.return_string
Expand Down
2 changes: 1 addition & 1 deletion examples/memory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

file = File.expand_path "memory.wasm", File.dirname(__FILE__)
bytes = IO.read file, mode: "rb"
instance = Instance.new bytes
instance = Wasmer::Instance.new bytes
pointer = instance.exports.return_hello

memory = instance.memory.uint8_view pointer
Expand Down
2 changes: 1 addition & 1 deletion examples/simple.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

file = File.expand_path "simple.wasm", File.dirname(__FILE__)
bytes = IO.read file, mode: "rb"
instance = Instance.new bytes
instance = Wasmer::Instance.new bytes
puts instance.exports.sum 1, 2
10 changes: 6 additions & 4 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rutie::{
rubysys::{class, value::ValueType},
types::{Argc, Value},
util::str_to_cstring,
wrappable_struct, AnyException, AnyObject, Array, Class, Exception, Fixnum, Float, Object,
wrappable_struct, AnyException, AnyObject, Array, Module, Exception, Fixnum, Float, Object,
RString, Symbol, VM,
};
use std::{mem, rc::Rc};
Expand Down Expand Up @@ -249,17 +249,19 @@ methods!(
.ok_or_else(|| VM::raise_ex(AnyException::new("RuntimeError", Some("The WebAssembly module has no exported memory."))))
.unwrap();

let wasmer_module = Module::from_existing("Wasmer");

let mut ruby_instance: AnyObject =
Class::from_existing("Instance").wrap_data(instance, &*INSTANCE_WRAPPER);
wasmer_module.get_nested_class("Instance").wrap_data(instance, &*INSTANCE_WRAPPER);

let ruby_exported_functions: RubyExportedFunctions =
Class::from_existing("ExportedFunctions")
wasmer_module.get_nested_class("ExportedFunctions")
.wrap_data(exported_functions, &*EXPORTED_FUNCTIONS_WRAPPER);

ruby_instance.instance_variable_set("@exports", ruby_exported_functions);

let ruby_memory: RubyMemory =
Class::from_existing("Memory").wrap_data(memory, &*MEMORY_WRAPPER);
wasmer_module.get_nested_class("Memory").wrap_data(memory, &*MEMORY_WRAPPER);

ruby_instance.instance_variable_set("@memory", ruby_memory);

Expand Down
14 changes: 8 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![deny(warnings)]

use rutie::{Class, Object};
use rutie::{Class, Module, Object};

pub mod instance;
pub mod memory;
Expand All @@ -9,10 +9,12 @@ pub mod module;
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn Init_wasmer() {
let mut wasmer_module = Module::from_existing("Wasmer");

let instance_data_class = Class::from_existing("Object");

// Declare the `Instance` Ruby class.
Class::new("Instance", Some(&instance_data_class)).define(|itself| {
wasmer_module.define_nested_class("Instance", Some(&instance_data_class)).define(|itself| {
// Declare the `self.new` method.
itself.def_self("new", instance::ruby_instance_new);

Expand All @@ -26,7 +28,7 @@ pub extern "C" fn Init_wasmer() {
let exported_functions_data_class = Class::from_existing("Object");

// Declare the `ExportedFunctions` Ruby class.
Class::new("ExportedFunctions", Some(&exported_functions_data_class)).define(|itself| {
wasmer_module.define_nested_class("ExportedFunctions", Some(&exported_functions_data_class)).define(|itself| {
// Declare the `method_missing` method.
itself.def(
"method_missing",
Expand All @@ -37,15 +39,15 @@ pub extern "C" fn Init_wasmer() {
let module_data_class = Class::from_existing("Object");

// Declare the `Module` Ruby class.
Class::new("Module", Some(&module_data_class)).define(|itself| {
wasmer_module.define_nested_class("Module", Some(&module_data_class)).define(|itself| {
// Declare the `self.validate` method.
itself.def_self("validate", module::ruby_module_validate);
});

let memory_data_class = Class::from_existing("Object");

// Declare the `Memory` Ruby class.
Class::new("Memory", Some(&memory_data_class)).define(|itself| {
wasmer_module.define_nested_class("Memory", Some(&memory_data_class)).define(|itself| {
// Declare the `view` method.
itself.def("uint8_view", memory::ruby_memory_uint8array);

Expand All @@ -70,7 +72,7 @@ pub extern "C" fn Init_wasmer() {
let uint8array_data_class = Class::from_existing("Object");

// Declare the `MemoryView` Ruby class.
Class::new(stringify!($class_name), Some(&uint8array_data_class)).define(|itself| {
wasmer_module.define_nested_class(stringify!($class_name), Some(&uint8array_data_class)).define(|itself| {
// Declare the `bytes_per_element` getter method.
itself.def(
"bytes_per_element",
Expand Down
20 changes: 13 additions & 7 deletions src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::memory::view::{
uint8array::{RubyMemoryView as RubyUint8Array, MEMORY_VIEW_WRAPPER as UINT8ARRAY_WRAPPER},
};
use lazy_static::lazy_static;
use rutie::{class, methods, wrappable_struct, Class, Integer, Object};
use rutie::{class, methods, wrappable_struct, Module, Integer, Object};
use std::rc::Rc;
use wasmer_runtime as runtime;

Expand Down Expand Up @@ -65,7 +65,8 @@ methods!(
.unwrap_or(0);
let memory_view = itself.get_data(&*MEMORY_WRAPPER).uint8_view(offset);

Class::from_existing("Uint8Array").wrap_data(memory_view, &*UINT8ARRAY_WRAPPER)
let wasmer_module = Module::from_existing("Wasmer");
wasmer_module.get_nested_class("Uint8Array").wrap_data(memory_view, &*UINT8ARRAY_WRAPPER)
}

// Glue code to call the `Memory.int8_view` method.
Expand All @@ -75,7 +76,8 @@ methods!(
.unwrap_or(0);
let memory_view = itself.get_data(&*MEMORY_WRAPPER).int8_view(offset);

Class::from_existing("Int8Array").wrap_data(memory_view, &*INT8ARRAY_WRAPPER)
let wasmer_module = Module::from_existing("Wasmer");
wasmer_module.get_nested_class("Int8Array").wrap_data(memory_view, &*INT8ARRAY_WRAPPER)
}

// Glue code to call the `Memory.uint16_view` method.
Expand All @@ -85,7 +87,8 @@ methods!(
.unwrap_or(0);
let memory_view = itself.get_data(&*MEMORY_WRAPPER).uint16_view(offset);

Class::from_existing("Uint16Array").wrap_data(memory_view, &*UINT16ARRAY_WRAPPER)
let wasmer_module = Module::from_existing("Wasmer");
wasmer_module.get_nested_class("Uint16Array").wrap_data(memory_view, &*UINT16ARRAY_WRAPPER)
}

// Glue code to call the `Memory.int16_view` method.
Expand All @@ -95,7 +98,8 @@ methods!(
.unwrap_or(0);
let memory_view = itself.get_data(&*MEMORY_WRAPPER).int16_view(offset);

Class::from_existing("Int16Array").wrap_data(memory_view, &*INT16ARRAY_WRAPPER)
let wasmer_module = Module::from_existing("Wasmer");
wasmer_module.get_nested_class("Int16Array").wrap_data(memory_view, &*INT16ARRAY_WRAPPER)
}

// Glue code to call the `Memory.uint32_view` method.
Expand All @@ -105,7 +109,8 @@ methods!(
.unwrap_or(0);
let memory_view = itself.get_data(&*MEMORY_WRAPPER).uint32_view(offset);

Class::from_existing("Uint32Array").wrap_data(memory_view, &*UINT32ARRAY_WRAPPER)
let wasmer_module = Module::from_existing("Wasmer");
wasmer_module.get_nested_class("Uint32Array").wrap_data(memory_view, &*UINT32ARRAY_WRAPPER)
}

// Glue code to call the `Memory.int32_view` method.
Expand All @@ -115,6 +120,7 @@ methods!(
.unwrap_or(0);
let memory_view = itself.get_data(&*MEMORY_WRAPPER).int32_view(offset);

Class::from_existing("Int32Array").wrap_data(memory_view, &*INT32ARRAY_WRAPPER)
let wasmer_module = Module::from_existing("Wasmer");
wasmer_module.get_nested_class("Int32Array").wrap_data(memory_view, &*INT32ARRAY_WRAPPER)
}
);
38 changes: 19 additions & 19 deletions tests/instance_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,100 +10,100 @@ def invalid_bytes
end

def test_can_construct
assert Instance.new self.bytes
assert Wasmer::Instance.new self.bytes
end

def test_constructor_needs_bytes
error = assert_raises(ArgumentError) {
Instance.new 123
Wasmer::Instance.new 123
}
assert_equal "WebAssembly module must be represented by Ruby bytes only.", error.message
end

def test_module_must_have_an_exported_memory
error = assert_raises(RuntimeError) {
bytes = IO.read File.expand_path("no_memory.wasm", File.dirname(__FILE__)), mode: "rb"
Instance.new bytes
Wasmer::Instance.new bytes
}
assert_equal "The WebAssembly module has no exported memory.", error.message
end

def test_invalid_module
error = assert_raises(RuntimeError) {
Instance.new self.invalid_bytes
Wasmer::Instance.new self.invalid_bytes
}
assert_equal "Failed to instantiate the module:\n compile error: Validation error \"Invalid type\"", error.message
end

def test_basic_sum
assert_equal 3, Instance.new(self.bytes).exports.sum(1, 2)
assert_equal 3, Wasmer::Instance.new(self.bytes).exports.sum(1, 2)
end

def test_call_unknown_function
error = assert_raises(RuntimeError) {
Instance.new(self.bytes).exports.foo
Wasmer::Instance.new(self.bytes).exports.foo
}
assert_equal "Function `foo` does not exist.", error.message
end

def test_call_missing_argument
error = assert_raises(ArgumentError) {
Instance.new(self.bytes).exports.sum 1
Wasmer::Instance.new(self.bytes).exports.sum 1
}
assert_equal "Missing 1 argument(s) when calling `sum`: Expect 2 argument(s), given 1.", error.message
end

def test_call_extra_argument
error = assert_raises(ArgumentError) {
Instance.new(self.bytes).exports.sum 1, 2, 3
Wasmer::Instance.new(self.bytes).exports.sum 1, 2, 3
}
assert_equal "Given 1 extra argument(s) when calling `sum`: Expect 2 argument(s), given 3.", error.message
end

def test_call_cannot_convert_argument
error = assert_raises(ArgumentError) {
Instance.new(self.bytes).exports.sum 1, "2"
Wasmer::Instance.new(self.bytes).exports.sum 1, "2"
}
assert_equal "Cannot convert argument #2 to a WebAssembly value. Only integers and floats are supported. Given `RString`.", error.message
end

def test_call_arity_0
assert_equal 42, Instance.new(self.bytes).exports.arity_0
assert_equal 42, Wasmer::Instance.new(self.bytes).exports.arity_0
end

def test_call_i32_i32
assert_equal 7, Instance.new(self.bytes).exports.i32_i32(7)
assert_equal 7, Wasmer::Instance.new(self.bytes).exports.i32_i32(7)
end

def test_call_i64_i64
assert_equal 7, Instance.new(self.bytes).exports.i64_i64(7)
assert_equal 7, Wasmer::Instance.new(self.bytes).exports.i64_i64(7)
end

def test_call_f32_f32
assert_equal 7.0, Instance.new(self.bytes).exports.f32_f32(7.0)
assert_equal 7.0, Wasmer::Instance.new(self.bytes).exports.f32_f32(7.0)
end

def test_call_f64_f64
assert_equal 7.0, Instance.new(self.bytes).exports.f64_f64(7.0)
assert_equal 7.0, Wasmer::Instance.new(self.bytes).exports.f64_f64(7.0)
end

def test_call_i32_i64_f32_f64_f64
assert_equal 1 + 2 + 3.4 + 5.6, Instance.new(self.bytes).exports.i32_i64_f32_f64_f64(1, 2, 3.4, 5.6).round(6)
assert_equal 1 + 2 + 3.4 + 5.6, Wasmer::Instance.new(self.bytes).exports.i32_i64_f32_f64_f64(1, 2, 3.4, 5.6).round(6)
end

def test_call_bool_casted_to_i32
assert_equal 1, Instance.new(self.bytes).exports.bool_casted_to_i32
assert_equal 1, Wasmer::Instance.new(self.bytes).exports.bool_casted_to_i32
end

def test_call_string
assert_equal 1048576, Instance.new(self.bytes).exports.string
assert_equal 1048576, Wasmer::Instance.new(self.bytes).exports.string
end

def test_exports
assert_instance_of ExportedFunctions, Instance.new(self.bytes).exports
assert_instance_of Wasmer::ExportedFunctions, Wasmer::Instance.new(self.bytes).exports
end

def test_memory
assert_instance_of Memory, Instance.new(self.bytes).memory
assert_instance_of Wasmer::Memory, Wasmer::Instance.new(self.bytes).memory
end
end
Loading