diff --git a/runner/index.html b/runner/index.html
index 9fe9d54..771129c 100644
--- a/runner/index.html
+++ b/runner/index.html
@@ -82,13 +82,13 @@
env.gas = function(upd) {
console.log("used " + upd + " gas");
}
-
if (!imports.env.memory) {
imports.env.memory = memory;
}
if (!imports.env.table) {
imports.env.table = new WebAssembly.Table({ initial: 0, maximum: 0, element: 'anyfunc' });
}
+ window.testMemory = memory;
return new WebAssembly.Instance(module, imports);
});
}
@@ -99,14 +99,20 @@
var exports = instance.exports;
var call = exports._call;
var malloc = exports._malloc;
- var data_ptr = malloc(1024*8);
- console.log("data_ptr: " + data_ptr);
+ // raw call context
+ var context_ptr = malloc(256);
+
+ // raw persistent storage
+ var storage_ptr = malloc(8192);
+
+ console.log("context_ptr: " + context_ptr);
+ console.log("storage_ptr: " + storage_ptr);
var button = document.getElementById('do-call');
button.value = 'Execute call';
button.addEventListener('click', function() {
- call();
+ let new_storage_ptr = call(context_ptr, storage_ptr);
console.log("Call succeded");
}, false);
}
diff --git a/samples/contract3.rs b/samples/contract3.rs
index ec72451..ec8b80a 100644
--- a/samples/contract3.rs
+++ b/samples/contract3.rs
@@ -2,15 +2,103 @@
#![feature(drop_types_in_const)]
#![no_main]
+// as it is experimental preamble
+#![allow(dead_code)]
+
use std::slice;
-#[link_args = "-s WASM=1 -s NO_EXIT_RUNTIME=1 -s NO_FILESYSTEM=1 -s EXPORTED_FUNCTIONS=['_call']"]
+#[link_args = "-s WASM=1 -s NO_EXIT_RUNTIME=1 -s NO_FILESYSTEM=1 -s"]
extern {}
+/// Safe (?) wrapper around call context
+struct CallArgs {
+ context: Box<[u8]>,
+ result: Vec,
+ storage: Vec,
+}
+
+unsafe fn read_ptr_mut(slc: &[u8]) -> *mut u8 {
+ std::ptr::null_mut().offset(read_u32(slc) as isize)
+}
+
+fn read_u32(slc: &[u8]) -> u32 {
+ use std::ops::Shl;
+ (slc[0] as u32) + (slc[1] as u32).shl(8) + (slc[2] as u32).shl(16) + (slc[3] as u32).shl(24)
+}
+
+fn write_u32(dst: &mut [u8], val: u32) {
+ dst[0] = (val & 0x000000ff) as u8;
+ dst[1] = (val & 0x0000ff00 >> 8) as u8;
+ dst[2] = (val & 0x00ff0000 >> 16) as u8;
+ dst[3] = (val & 0xff000000 >> 24) as u8;
+}
+
+fn write_ptr(dst: &mut [u8], ptr: *mut u8) {
+ // todo: consider: add assert that arch is 32bit
+ write_u32(dst, ptr as usize as u32);
+}
+
+impl CallArgs {
+ pub fn from_raw(ptr: *mut u8) -> CallArgs {
+ let desc_slice = unsafe { slice::from_raw_parts(ptr, 6 * 4) };
+
+ let context_ptr = unsafe { read_ptr_mut(&desc_slice[0..4]) };
+ let context_len = read_u32(&desc_slice[4..8]) as usize;
+
+ let storage_ptr = unsafe { read_ptr_mut(&desc_slice[8..12]) };
+ let storage_len = read_u32(&desc_slice[12..16]) as usize;
+
+ let result_ptr = unsafe { read_ptr_mut(&desc_slice[16..20]) };
+ let result_len = read_u32(&desc_slice[20..24]) as usize;
+
+ CallArgs {
+ context: unsafe { Box::<[u8]>::from_raw(slice::from_raw_parts_mut(context_ptr, context_len)) },
+ result: unsafe { Vec::from_raw_parts(result_ptr, result_len, result_len) },
+ // todo: consider: storage (and result?) might also have initial allocation size passed in
+ // the descriptor along with length
+ storage: unsafe { Vec::from_raw_parts(storage_ptr, storage_len, storage_len) },
+ }
+ }
+
+ pub fn context(&self) -> &[u8] {
+ &self.context
+ }
+
+ pub fn result_mut(&mut self) -> &mut Vec {
+ &mut self.result
+ }
+
+ pub fn storage(&self) -> &[u8] {
+ &self.storage
+ }
+
+ pub fn storage_mut(&mut self) -> &mut Vec {
+ &mut self.storage
+ }
+
+ pub fn save(self, ptr: *mut u8) {
+ let dst = unsafe { slice::from_raw_parts_mut(ptr, 6 * 4) };
+ let context = self.context;
+ let mut result = self.result;
+ let mut storage = self.storage;
+
+ // context unmodified and memory is managed in calling code
+ std::mem::forget(context);
+
+ write_ptr(dst, storage.as_mut_ptr());
+ write_u32(dst, storage.len() as u32);
+ // managed in calling code
+ std::mem::forget(storage);
+
+ write_ptr(dst, result.as_mut_ptr());
+ write_u32(dst, result.len() as u32);
+ // managed in calling code
+ std::mem::forget(result);
+ }
+
+}
+
#[no_mangle]
-pub fn call(input: *mut u8) {
- let slice = unsafe { slice::from_raw_parts_mut(input, 8192) }; // 8kb input data
- for i in 0..8192 {
- slice[i] = slice[i] + 2;
- }
+pub fn call(descriptor: *mut u8) {
+ let context = CallArgs::from_raw(descriptor);
}
\ No newline at end of file