[
  {
    "path": ".gitignore",
    "content": "\n/target\n**/*.rs.bk\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"serverless-wasm\"\nversion = \"0.1.0\"\nlicense = \"MIT\"\nrepository = \"https://github.com/Geal/serverless-wasm\"\nreadme = \"README.md\"\nauthors = [\"Geoffroy Couprie <geo.couprie@gmail.com>\"]\n\n[dependencies]\nparity-wasm = \"^0.27\"\nrouille = \"^2.1\"\nslab = \"^0.3\"\ntoml = \"^0.4\"\nserde = \"^1.0\"\nserde_derive = \"^1.0\"\nmio = \"^0.6\"\nhttparse = \"^1.2\"\n#wasmi = \"^0.1\"\nwasmi = { git = \"https://github.com/geal/wasmi\" }\n#wasmi = { path = \"../wasmi\" }\ncretonne = \"*\"\ncretonne-wasm = \"^0.8\"\ncretonne-module = \"*\"\ncretonne-simplejit = \"^0.8\"\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2018 Geoffroy Couprie\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Serverless Web Assembly framework\n\n![Serverless WASM](https://raw.githubusercontent.com/geal/serverless-wasm/master/assets/serverless-wasm.jpg)\n\n## Why?\n\nFor fun.\n\n## But why?\n\n![but why?](https://raw.githubusercontent.com/geal/serverless-wasm/master/assets/butwhy.gif)\n\nThis is a small demo of Web Assembly's potential outside of browsers.\nIt has been designed with client side execution in mind, but there's\nnothing preventing it from running in other platforms.\nThere are people working on running WASM binaries from a shell, and\nputting WASM code inside kernels.\n\nHere are some benefits of Web Assembly's design:\n\n- maps well to CPU assembly (with Just In Time compilation in mind)\n- the virtual machine does not require garbage collection, only small memory areas\nthat will be handled by the guest code\n- meant to be sandboxed\n\nAnd here's the best part: it is meant to be a target language, a lot of other\nlanguages will compile to WASM. You can already write C or C++ and compile\nto WASM with emscripten. Rust's compiler natively supports it. There are demos\nin Go, Haskell and Ruby.\n\nThe network effects are huge: the major browsers implement it and can run any\nWASM app, and every language wants to run on the client side.\n\nNow, what happens when you leverage these advantages to build a server platform?\nYou get a system that can run a lot of small, sandboxed, resource limited\napplications, written in a lot of different languages.\n\nYou do not care about how to start it, you don't need to map it to filesystems\nand common runtimes like containers do. You just have some bytecode that imports\na few functions, and runs well isolated.\n\nThis is a bit like the serverless promise, the ability to run arbitrarily small\nfunctions, but without even caring about the startup time or the state size,\nthis will be the smallest you can think of.\n\n## What works\n\nCurrently, the server is able to load a pre built web assembly binary, exports\nsome function that it can use for logging, to build a response and connect to\nother servers, and handle requests using that wasm file (as long as it exports\na \"handle\" function).\n\n## How to run it\n\n### Requirements for WASM applications\n\nthe WASM application must export a `handle` function that takes no arguments and\nreturns no arguments.\n\nThe virtual machine currently exposes the following functions, that you can use\nto build your response:\n\n```rust\nextern {\n  fn log(ptr: *const u8, size: u64);\n\n  fn response_set_status_line(status: u32, ptr: *const u8, size: u64);\n  fn response_set_header(name_ptr: *const u8, name_size: u64, value_ptr: *const u8, value_size: u64);\n  fn response_set_body(ptr: *const u8, size: u64);\n\n  fn tcp_connect(ptr: *const u8, size: u64) -> i32;\n  fn tcp_read(fd: i32, ptr: *mut u8, size: u64) -> i64;\n  fn tcp_write(fd: i32, ptr: *const u8, size: u64) -> i64;\n}\n```\n\n### Configuration file\n\nYou define which WASM binary will handle which requests through a TOML configuration\nfile:\n\n```toml\nlisten_address = \"127.0.0.1:8080\"\n\n[[applications]]\nfile_path = \"./samples/testfunc.wasm\"\nmethod = \"GET\"\nurl_path = \"/hello\"\n\n[[applications]]\nfile_path = \"./samples/testbackend.wasm\"\nmethod = \"GET\"\nurl_path = \"/backend\"\n```\n\n### Running it\n\nYou can build and launch the server as follows:\n\n```rust\ncargo build && ./target/debug/serverless-wasm ./samples/config.toml\n```\n\n## Current features\n\n- [x] load web assembly file to handle requests\n- [x] logging function available from WASM\n- [x] API to build a response from WASM\n- [x] (blocking) TCP connections to backend servers or databases\n- [x] routing to mutiple apps depending on the request\n- [x] set up initial state via \"environment variables\"\n- [ ] proper error handling (the server will panic even if you give it the side eye)\n- [ ] (in progress) asynchronous event loop to receive connections and handle backend TCP connections\n- [ ] file system abstraction (loading files from S3 or other providers?)\n- [ ] (in progress) \"standard API\" for functions exported by the VM\n\n## Prior art\n\nWhile I was building this, I heard of [IceCore](https://github.com/losfair/IceCore),\nwhich looks quite cool, with JIT support, etc.\nIt's quite nice to see multiple platforms attempting this. Maybe we'll be able to\nagree onthe \"web assembly standard API\" so WASM apps can run on any of those :)\n"
  },
  {
    "path": "rustfmt.toml",
    "content": "tab_spaces = 2\nstruct_field_align_threshold = 100\nmax_width = 140\n"
  },
  {
    "path": "samples/config.toml",
    "content": "listen_address = \"127.0.0.1:8080\"\n\n[[applications]]\nfile_path = \"./samples/testfunc.wasm\"\nmethod = \"GET\"\nurl_path = \"/hello\"\nfunction = \"hello\"\n\n[[applications]]\nfile_path = \"./samples/testfunc.wasm\"\nmethod = \"GET\"\nurl_path = \"/bonjour\"\nfunction = \"bonjour\"\n\n[[applications]]\nfile_path = \"./samples/testbackend.wasm\"\nmethod = \"GET\"\nurl_path = \"/backend\"\nfunction = \"handle\"\nenv = { \"/env/backend\"= \"127.0.0.1:8181\"}\n"
  },
  {
    "path": "samples/testbackend/Cargo.toml",
    "content": "[package]\nname = \"testbackend\"\nversion = \"0.1.0\"\nauthors = [\"Geoffroy Couprie <geo.couprie@gmail.com>\"]\n\n[lib]\npath = \"src/lib.rs\"\ncrate-type = [\"cdylib\"]\n\n[dependencies]\nserverless-api = { path = \"../../serverless-api/\" }\n"
  },
  {
    "path": "samples/testbackend/build.sh",
    "content": "#!/bin/sh\nRUSTFLAGS=\"-Clink-args=--import-memory\" cargo +nightly build -v --target wasm32-unknown-unknown --release\ncp target/wasm32-unknown-unknown/release/testbackend.wasm ..\n\n"
  },
  {
    "path": "samples/testbackend/config.toml",
    "content": "rustflags = [\"-Clink-args=--import-memory\"]\n"
  },
  {
    "path": "samples/testbackend/src/lib.rs",
    "content": "use std::str;\nextern crate serverless_api as api;\n\n#[no_mangle]\npub extern \"C\" fn handle() {\n  api::log(\"Hello world with api!\");\n  let body;\n\n  let key = \"/env/backend\";\n  match api::db::get(key) {\n    None => {\n      body = format!(\"could not get value for key {}\", key);\n    },\n    Some(address) => {\n      api::log(&format!(\"connecting to backend at {}\", address));\n\n      match api::TcpStream::connect(&address) {\n        None => {\n          body = \"could not connect to backend\".to_string();\n        },\n        Some(mut socket) => {\n          match socket.write(b\"hello\\n\") {\n            None => {\n              body = \"could not write to backend server\".to_string();\n            },\n            Some(_) => {\n              let mut res: [u8; 100] = [0u8; 100];\n              match socket.read(&mut res) {\n                None => {\n                  body = \"could not read from backend server\".to_string();\n                },\n                Some(sz) => {\n                  api::log(&format!(\"read data from backend: \\\"{:?}\\\"\", str::from_utf8(&res[..sz]).unwrap()));\n\n                  body = format!(\"Hello world from wasm!\\nanswer from backend:\\n{}\\n\", str::from_utf8(&res[..sz]).unwrap());\n                  api::response::set_status(200, \"Ok\");\n                  api::response::set_header(\"Content-length\", &body.len().to_string());\n                  api::response::set_body(body.as_bytes());\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n\n  api::log(&body);\n  api::response::set_status(500, \"Server error\");\n  api::response::set_header(\"Content-length\", &body.len().to_string());\n  api::response::set_body(body.as_bytes());\n}\n"
  },
  {
    "path": "samples/testfunc/Cargo.toml",
    "content": "[package]\nname = \"testfunc\"\nversion = \"0.1.0\"\nauthors = [\"Geoffroy Couprie <geo.couprie@gmail.com>\"]\n\n[lib]\npath = \"src/lib.rs\"\ncrate-type = [\"cdylib\"]\n\n[dependencies]\nserverless-api = { path = \"../../serverless-api/\" }\n"
  },
  {
    "path": "samples/testfunc/build.sh",
    "content": "#!/bin/sh\nRUSTFLAGS=\"-Clink-args=--import-memory\" cargo +nightly build -v --target wasm32-unknown-unknown --release\ncp target/wasm32-unknown-unknown/release/testfunc.wasm ..\n\n"
  },
  {
    "path": "samples/testfunc/config.toml",
    "content": "rustflags = [\"-Clink-args=--import-memory\"]\n"
  },
  {
    "path": "samples/testfunc/src/lib.rs",
    "content": "use std::ptr;\nuse std::str;\nextern crate serverless_api as api;\n\n#[no_mangle]\npub extern \"C\" fn hello() {\n  api::log(\"Hello world with api!\");\n\n  api::response::set_status(200, \"Ok\");\n\n  let body = \"Hello world from wasm!\\n\";\n  api::response::set_header(\"Content-length\", &body.len().to_string());\n  api::response::set_body(body.as_bytes());\n}\n\n#[no_mangle]\npub extern \"C\" fn bonjour() {\n  api::log(\"Bonjour tout le monde!\");\n\n  api::response::set_status(200, \"Ok\");\n\n  let body = \"Bonjour tout le monde depuis le monde merveilleux de WASM!\\n\";\n  api::response::set_header(\"Content-length\", &body.len().to_string());\n  api::response::set_body(body.as_bytes());\n}\n"
  },
  {
    "path": "serverless-api/Cargo.toml",
    "content": "[package]\nname = \"serverless-api\"\nversion = \"0.1.0\"\nauthors = [\"Geoffroy Couprie <geo.couprie@gmail.com>\"]\n\n[dependencies]\n"
  },
  {
    "path": "serverless-api/src/lib.rs",
    "content": "use std::str;\n\nmod sys {\n  extern {\n    pub fn log(ptr: *const u8, size: u64);\n    pub fn response_set_status_line(status: u32, ptr: *const u8, size: u64);\n    pub fn response_set_header(name_ptr: *const u8, name_size: u64, value_ptr: *const u8, value_size: u64);\n    pub fn response_set_body(ptr: *const u8, size: u64);\n    pub fn tcp_connect(ptr: *const u8, size: u64) -> i32;\n    pub fn tcp_read(fd: i32, ptr: *mut u8, size: u64) -> i64;\n    pub fn tcp_write(fd: i32, ptr: *const u8, size: u64) -> i64;\n    pub fn db_get(key_ptr: *const u8, key_size: u64, value_ptr: *const u8, value_size: u64) -> i64;\n  }\n}\n\npub fn log(s: &str) {\n  unsafe { sys::log(s.as_ptr(), s.len() as u64) };\n}\n\npub mod db {\n  use super::sys;\n  use std::iter::repeat;\n\n  pub fn get(key: &str) -> Option<String> {\n    let mut empty = vec![];\n    let read_sz = unsafe {\n      sys::db_get(key.as_ptr(), key.len() as u64, (&mut empty).as_mut_ptr(), empty.len() as u64)\n    };\n\n    if read_sz < 0 {\n      return None;\n    } else if read_sz == 0 {\n      return Some(String::new());\n    }\n\n    let mut v = Vec::with_capacity(read_sz as usize);\n    v.extend(repeat(0).take(read_sz as usize));\n\n    let sz = unsafe {\n      sys::db_get(key.as_ptr(), key.len() as u64, v.as_mut_ptr(), v.len() as u64)\n    };\n\n    if sz < 0 {\n      return None;\n    } else if sz == 0 {\n      return Some(String::new());\n    }\n\n    if sz as usize != v.len() {\n      None\n    } else {\n      String::from_utf8(v).ok()\n    }\n  }\n}\n\npub mod response {\n  use super::sys;\n\n  pub fn set_status(status: u16, reason: &str) {\n    unsafe {\n      sys::response_set_status_line(status.into(), reason.as_ptr(), reason.len() as u64);\n    }\n  }\n\n  pub fn set_header(name: &str, value: &str) {\n    unsafe {\n      sys::response_set_header(name.as_ptr(), name.len() as u64, value.as_ptr(), value.len() as u64);\n    }\n  }\n\n  pub fn set_body(body: &[u8]) {\n    unsafe {\n      sys::response_set_body(body.as_ptr(), body.len() as u64);\n    }\n  }\n}\n\npub struct TcpStream {\n  fd: i32\n}\n\nimpl TcpStream {\n  pub fn connect(address: &str) -> Option<TcpStream> {\n    let fd = unsafe { sys::tcp_connect(address.as_ptr(), address.len() as u64) };\n    if fd < 0 {\n      None\n    } else {\n      Some(TcpStream { fd })\n    }\n  }\n\n  pub fn write(&mut self, data: &[u8]) -> Option<usize> {\n    let res = unsafe { sys::tcp_write(self.fd, data.as_ptr(), data.len() as u64) };\n    if res < 0 {\n      None\n    } else {\n      Some(res as usize)\n    }\n  }\n\n  pub fn read(&mut self, data: &mut [u8]) -> Option<usize> {\n    let res = unsafe { sys::tcp_read(self.fd, data.as_mut_ptr(), data.len() as u64) };\n    if res < 0 {\n      None\n    } else {\n      Some(res as usize)\n    }\n  }\n}\n\n"
  },
  {
    "path": "serverless-api/target/.rustc_info.json",
    "content": "{\"rustc_fingerprint\":10175240907518990213,\"outputs\":{\"1617349019360157463\":[\"___\\nlib___.rlib\\nlib___.dylib\\nlib___.dylib\\nlib___.a\\nlib___.dylib\\n/Users/geal/.rustup/toolchains/nightly-x86_64-apple-darwin\\ndebug_assertions\\nproc_macro\\ntarget_arch=\\\"x86_64\\\"\\ntarget_endian=\\\"little\\\"\\ntarget_env=\\\"\\\"\\ntarget_family=\\\"unix\\\"\\ntarget_feature=\\\"fxsr\\\"\\ntarget_feature=\\\"mmx\\\"\\ntarget_feature=\\\"sse\\\"\\ntarget_feature=\\\"sse2\\\"\\ntarget_feature=\\\"sse3\\\"\\ntarget_feature=\\\"ssse3\\\"\\ntarget_has_atomic=\\\"128\\\"\\ntarget_has_atomic=\\\"16\\\"\\ntarget_has_atomic=\\\"32\\\"\\ntarget_has_atomic=\\\"64\\\"\\ntarget_has_atomic=\\\"8\\\"\\ntarget_has_atomic=\\\"ptr\\\"\\ntarget_os=\\\"macos\\\"\\ntarget_pointer_width=\\\"64\\\"\\ntarget_thread_local\\ntarget_vendor=\\\"apple\\\"\\nunix\\n\",\"\"],\"1164083562126845933\":[\"rustc 1.27.0-nightly (9fae15374 2018-05-13)\\nbinary: rustc\\ncommit-hash: 9fae1537462bb10fd17d07816efc17cfe4786806\\ncommit-date: 2018-05-13\\nhost: x86_64-apple-darwin\\nrelease: 1.27.0-nightly\\nLLVM version: 6.0\\n\",\"\"],\"3144802570395919623\":[\"___\\nlib___.rlib\\nlib___.dylib\\nlib___.dylib\\nlib___.a\\nlib___.dylib\\n/Users/geal/.rustup/toolchains/nightly-x86_64-apple-darwin\\ndebug_assertions\\nproc_macro\\ntarget_arch=\\\"x86_64\\\"\\ntarget_endian=\\\"little\\\"\\ntarget_env=\\\"\\\"\\ntarget_family=\\\"unix\\\"\\ntarget_feature=\\\"fxsr\\\"\\ntarget_feature=\\\"mmx\\\"\\ntarget_feature=\\\"sse\\\"\\ntarget_feature=\\\"sse2\\\"\\ntarget_feature=\\\"sse3\\\"\\ntarget_feature=\\\"ssse3\\\"\\ntarget_has_atomic=\\\"128\\\"\\ntarget_has_atomic=\\\"16\\\"\\ntarget_has_atomic=\\\"32\\\"\\ntarget_has_atomic=\\\"64\\\"\\ntarget_has_atomic=\\\"8\\\"\\ntarget_has_atomic=\\\"ptr\\\"\\ntarget_os=\\\"macos\\\"\\ntarget_pointer_width=\\\"64\\\"\\ntarget_thread_local\\ntarget_vendor=\\\"apple\\\"\\nunix\\n\",\"\"]}}"
  },
  {
    "path": "serverless-api/target/debug/.cargo-lock",
    "content": ""
  },
  {
    "path": "serverless-api/target/debug/.fingerprint/serverless-api-58a0200541263288/lib-serverless_api-58a0200541263288",
    "content": "68e06764be0d3fe0"
  },
  {
    "path": "serverless-api/target/debug/.fingerprint/serverless-api-58a0200541263288/lib-serverless_api-58a0200541263288.json",
    "content": "{\"rustc\":2983502972076547984,\"features\":\"[]\",\"target\":12616003758275913516,\"profile\":16965165444893579269,\"path\":10872709659218687626,\"deps\":[],\"local\":[{\"MtimeBased\":[[1526638291,222510886],\".fingerprint/serverless-api-58a0200541263288/dep-lib-serverless_api-58a0200541263288\"]}],\"rustflags\":[],\"edition\":\"Edition2015\"}"
  },
  {
    "path": "serverless-api/target/debug/.fingerprint/serverless-api-81a9cad5d43bde63/lib-serverless_api-81a9cad5d43bde63",
    "content": "d109624b85f6a4ab"
  },
  {
    "path": "serverless-api/target/debug/.fingerprint/serverless-api-81a9cad5d43bde63/lib-serverless_api-81a9cad5d43bde63.json",
    "content": "{\"rustc\":2983502972076547984,\"features\":\"[]\",\"target\":12616003758275913516,\"profile\":4101608828254088483,\"path\":10872709659218687626,\"deps\":[],\"local\":[{\"MtimeBased\":[[1526637383,987549318],\".fingerprint/serverless-api-81a9cad5d43bde63/dep-lib-serverless_api-81a9cad5d43bde63\"]}],\"rustflags\":[],\"edition\":\"Edition2015\"}"
  },
  {
    "path": "serverless-api/target/debug/deps/serverless_api-58a0200541263288.d",
    "content": "/Users/geal/dev/rust/projects/serverless-wasm/serverless-api/target/debug/deps/libserverless_api-58a0200541263288.rlib: src/lib.rs\n\n/Users/geal/dev/rust/projects/serverless-wasm/serverless-api/target/debug/deps/serverless_api-58a0200541263288.d: src/lib.rs\n\nsrc/lib.rs:\n"
  },
  {
    "path": "serverless-api/target/debug/deps/serverless_api-81a9cad5d43bde63.d",
    "content": "/Users/geal/dev/rust/projects/serverless-wasm/serverless-api/target/debug/deps/serverless_api-81a9cad5d43bde63.rmeta: src/lib.rs\n\n/Users/geal/dev/rust/projects/serverless-wasm/serverless-api/target/debug/deps/serverless_api-81a9cad5d43bde63.d: src/lib.rs\n\nsrc/lib.rs:\n"
  },
  {
    "path": "serverless-api/target/debug/libserverless_api.d",
    "content": "/Users/geal/dev/rust/projects/serverless-wasm/serverless-api/target/debug/libserverless_api.rlib: /Users/geal/dev/rust/projects/serverless-wasm/serverless-api/src/lib.rs\n"
  },
  {
    "path": "src/async/host.rs",
    "content": "//! from https://github.com/paritytech/wasmi/blob/master/src/tests/host.rs\n\nuse slab::Slab;\nuse std::collections::HashMap;\nuse std::io::{Read, Write};\nuse std::iter::repeat;\nuse mio::net::TcpStream;\nuse std::net::SocketAddr;\nuse std::str;\nuse std::cmp;\nuse std::rc::Rc;\nuse std::cell::RefCell;\nuse wasmi::memory_units::Pages;\nuse wasmi::*;\nuse interpreter::Host;\n\n#[derive(Debug)]\npub enum AsyncHostError {\n  Connecting(SocketAddr),\n  TcpRead(i32, u32, u64),\n  TcpWrite(i32, u32, u64, usize),\n}\n\nimpl ::std::fmt::Display for AsyncHostError {\n  fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {\n    write!(f, \"{:?}\", self)\n  }\n}\n\nimpl HostError for AsyncHostError {}\n\n#[derive(Clone, Debug)]\npub struct PreparedResponse {\n  pub status_code: Option<u16>,\n  pub reason: Option<String>,\n  pub headers: Vec<(String, String)>,\n  pub body: Option<Vec<u8>>,\n}\n\nimpl PreparedResponse {\n  pub fn new() -> PreparedResponse {\n    PreparedResponse {\n      status_code: None,\n      reason: None,\n      headers: Vec::new(),\n      body: None,\n    }\n  }\n}\n\npub struct State {\n  pub memory: Option<MemoryRef>,\n  pub instance: Option<ModuleRef>,\n  pub prepared_response: PreparedResponse,\n  pub connections: Slab<TcpStream>,\n  pub db: HashMap<String, String>,\n}\n\nimpl State {\n  pub fn new() -> State {\n    State {\n      memory: None,//Some(MemoryInstance::alloc(Pages(3), Some(Pages(100))).unwrap()),\n      instance: None,\n      prepared_response: PreparedResponse::new(),\n      connections: Slab::with_capacity(100),\n      db: HashMap::new(),\n    }\n  }\n}\nimpl State {\n  pub fn get_buf(&mut self, ptr: u32, size: usize) -> Option<Vec<u8>> {\n    self.memory.as_ref().and_then(|mref| {\n      mref.get(ptr, size).map_err(|e| println!(\"get buf error: {:?}\", e)).ok()\n    })\n  }\n\n  pub fn write_buf(&mut self, ptr: u32, data: &[u8]) {\n    self.memory.as_ref().map(|m| m.set(ptr, data));\n  }\n}\n\n\npub struct AsyncHost {\n  pub inner: Rc<RefCell<State>>,\n}\n\nimpl Host for AsyncHost {\n  type State = State;\n\n  fn build(s: Rc<RefCell<Self::State>>) -> Self {\n    AsyncHost { inner: s }\n  }\n}\n\n/// log(ptr: *mut u8, size: u64)\n///\n/// Returns value at the given address in memory. This function\n/// requires attached memory.\nconst LOG_INDEX: usize = 0;\n\nconst RESPONSE_SET_STATUS_LINE: usize = 1;\nconst RESPONSE_SET_HEADER: usize = 2;\nconst RESPONSE_SET_BODY: usize = 3;\nconst TCP_CONNECT: usize = 4;\nconst TCP_READ: usize = 5;\nconst TCP_WRITE: usize = 6;\nconst DB_GET: usize = 7;\n\nimpl Externals for AsyncHost {\n  fn invoke_index(&mut self, index: usize, args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap> {\n    match index {\n      LOG_INDEX => {\n        let ptr: u32 = args.nth(0);\n        let sz: u64 = args.nth(1);\n\n        let v = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n\n        println!(\"log({} bytes): {}\", v.len(), str::from_utf8(&v).unwrap());\n        Ok(None)\n      }\n      RESPONSE_SET_STATUS_LINE => {\n        let status: u32 = args.nth(0);\n        let ptr: u32 = args.nth(1);\n        let sz: u64 = args.nth(2);\n\n        let reason = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n\n        self.inner.borrow_mut().prepared_response.status_code = Some(status as u16);\n        self.inner.borrow_mut().prepared_response.reason = Some(String::from_utf8(reason).unwrap());\n\n        Ok(None)\n      }\n      RESPONSE_SET_HEADER => {\n        let ptr1: u32 = args.nth(0);\n        let sz1: u64 = args.nth(1);\n        let ptr2: u32 = args.nth(2);\n        let sz2: u64 = args.nth(3);\n        let header_name = {\n          self\n            .inner\n            .borrow()\n            .memory\n            .as_ref()\n            .expect(\"Function 'inc_mem' expects attached memory\")\n            .get(ptr1, sz1 as usize)\n            .unwrap()\n        };\n        let header_value = {\n          self\n            .inner\n            .borrow()\n            .memory\n            .as_ref()\n            .expect(\"Function 'inc_mem' expects attached memory\")\n            .get(ptr2, sz2 as usize)\n            .unwrap()\n        };\n\n        self.inner.borrow_mut().prepared_response.headers.push((\n          String::from_utf8(header_name).unwrap(),\n          String::from_utf8(header_value).unwrap(),\n        ));\n        Ok(None)\n      }\n      RESPONSE_SET_BODY => {\n        let ptr: u32 = args.nth(0);\n        let sz: u64 = args.nth(1);\n\n        let body = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n        self.inner.borrow_mut().prepared_response.body = Some(body);\n        Ok(None)\n      }\n      TCP_CONNECT => {\n        let ptr: u32 = args.nth(0);\n        let sz: u64 = args.nth(1);\n\n        let v = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n        let address = String::from_utf8(v).unwrap();\n        println!(\"received tcp_connect for {:?}\", address);\n        let error = AsyncHostError::Connecting(address.parse().unwrap());\n        Err(Trap::new(TrapKind::Host(Box::new(error))))\n      }\n      TCP_READ => {\n        let fd: i32 = args.nth(0);\n        let ptr: u32 = args.nth(1);\n        let sz: u64 = args.nth(2);\n\n        let error = AsyncHostError::TcpRead(fd, ptr, sz);\n        Err(Trap::new(TrapKind::Host(Box::new(error))))\n\n        /*\n        let mut v = Vec::with_capacity(sz as usize);\n        v.extend(repeat(0).take(sz as usize));\n\n        let mut state = self.inner.borrow_mut();\n        if let Ok(sz) = state.connections[fd as usize].read(&mut v) {\n          state.memory.as_ref().map(|m| m.set(ptr, &v[..sz]));\n\n          Ok(Some(RuntimeValue::I64(sz as i64)))\n        } else {\n          Ok(Some(RuntimeValue::I64(-1)))\n        }\n        */\n      }\n      TCP_WRITE => {\n        let fd: i32 = args.nth(0);\n        let ptr: u32 = args.nth(1);\n        let sz: u64 = args.nth(2);\n\n        let error = AsyncHostError::TcpWrite(fd, ptr, sz, 0);\n        Err(Trap::new(TrapKind::Host(Box::new(error))))\n\n        /*\n        let buf = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n\n        if let Ok(sz) = self.inner.borrow_mut().connections[fd as usize].write(&buf) {\n          Ok(Some(RuntimeValue::I64(sz as i64)))\n        } else {\n          Ok(Some(RuntimeValue::I64(-1)))\n        }\n        */\n      }\n      DB_GET => {\n        let key_ptr: u32 = args.nth(0);\n        let key_sz: u64 = args.nth(1);\n        let value_ptr: u32 = args.nth(2);\n        let value_sz: u64 = args.nth(3);\n\n        let v = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(key_ptr, key_sz as usize)\n          .unwrap();\n        let key = String::from_utf8(v).unwrap();\n        println!(\"requested value for key {}\", key);\n\n        match self.inner.borrow().db.get(&key) {\n          None => Ok(Some(RuntimeValue::I64(-1))),\n          Some(value) => {\n            let to_write = cmp::min(value.len(), value_sz as usize);\n            self\n              .inner\n              .borrow()\n              .memory\n              .as_ref()\n              .map(|m| m.set(value_ptr, (&value[..to_write]).as_bytes()));\n            Ok(Some(RuntimeValue::I64(value.len() as i64)))\n          }\n        }\n      }\n      _ => panic!(\"env doesn't provide function at index {}\", index),\n    }\n  }\n}\n\nimpl State {\n  fn check_signature(&self, index: usize, signature: &Signature) -> bool {\n    let (params, ret_ty): (&[ValueType], Option<ValueType>) = match index {\n      LOG_INDEX => (&[ValueType::I32, ValueType::I64], None),\n      RESPONSE_SET_STATUS_LINE => (&[ValueType::I32, ValueType::I32, ValueType::I64], None),\n      RESPONSE_SET_HEADER => (\n        &[\n          ValueType::I32,\n          ValueType::I64,\n          ValueType::I32,\n          ValueType::I64,\n        ],\n        None,\n      ),\n      RESPONSE_SET_BODY => (&[ValueType::I32, ValueType::I64], None),\n      TCP_CONNECT => (&[ValueType::I32, ValueType::I64], Some(ValueType::I32)),\n      TCP_READ => (\n        &[ValueType::I32, ValueType::I32, ValueType::I64],\n        Some(ValueType::I64),\n      ),\n      TCP_WRITE => (\n        &[ValueType::I32, ValueType::I32, ValueType::I64],\n        Some(ValueType::I64),\n      ),\n      DB_GET => (\n        &[\n          ValueType::I32,\n          ValueType::I64,\n          ValueType::I32,\n          ValueType::I64,\n        ],\n        Some(ValueType::I64),\n      ),\n      _ => return false,\n    };\n\n    signature.params() == params && signature.return_type() == ret_ty\n  }\n}\n\nimpl ModuleImportResolver for State {\n  fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {\n    let index = match field_name {\n      \"log\" => LOG_INDEX,\n      \"response_set_status_line\" => RESPONSE_SET_STATUS_LINE,\n      \"response_set_header\" => RESPONSE_SET_HEADER,\n      \"response_set_body\" => RESPONSE_SET_BODY,\n      \"tcp_connect\" => TCP_CONNECT,\n      \"tcp_read\" => TCP_READ,\n      \"tcp_write\" => TCP_WRITE,\n      \"db_get\" => DB_GET,\n      _ => {\n        return Err(Error::Instantiation(format!(\n          \"Export {} not found\",\n          field_name\n        )))\n      }\n    };\n\n    if !self.check_signature(index, signature) {\n      return Err(Error::Instantiation(format!(\n        \"Export `{}` doesnt match expected type {:?}\",\n        field_name, signature\n      )));\n    }\n\n    Ok(FuncInstance::alloc_host(signature.clone(), index))\n  }\n\n  fn resolve_memory(&self, _field_name: &str, _memory_type: &MemoryDescriptor) -> Result<MemoryRef, Error> {\n    let Pages(initial1) = self.memory.as_ref().map(|m| m.initial()).unwrap();\n    let initial2 = _memory_type.initial() as usize;\n    //println!(\"requested {} pages\", initial2);\n    if initial2 > initial1 {\n      self.memory.as_ref().map(|_m| {\n        //println!(\"grow res: {:?}\", m.grow(Pages(initial2 - initial1)).unwrap());\n      });\n    }\n    let Pages(_initial) = self.memory.as_ref().map(|m| m.current_size()).unwrap();\n    //println!(\"current number of pages: {}\", initial);\n    //println!(\"resolving memory at name: {}\", field_name);\n    let res = self.memory.as_ref().unwrap().clone();\n\n    Ok(res)\n  }\n}\n\npub struct StateResolver {\n  pub inner: Rc<RefCell<State>>,\n}\n\nimpl ModuleImportResolver for StateResolver {\n  fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {\n    let index = match field_name {\n      \"log\" => LOG_INDEX,\n      \"response_set_status_line\" => RESPONSE_SET_STATUS_LINE,\n      \"response_set_header\" => RESPONSE_SET_HEADER,\n      \"response_set_body\" => RESPONSE_SET_BODY,\n      \"tcp_connect\" => TCP_CONNECT,\n      \"tcp_read\" => TCP_READ,\n      \"tcp_write\" => TCP_WRITE,\n      \"db_get\" => DB_GET,\n      _ => {\n        return Err(Error::Instantiation(format!(\n          \"Export {} not found\",\n          field_name\n        )))\n      }\n    };\n\n    if !self.inner.borrow().check_signature(index, signature) {\n      return Err(Error::Instantiation(format!(\n        \"Export `{}` doesnt match expected type {:?}\",\n        field_name, signature\n      )));\n    }\n\n    Ok(FuncInstance::alloc_host(signature.clone(), index))\n  }\n\n  fn resolve_memory(&self, _field_name: &str, _memory_type: &MemoryDescriptor) -> Result<MemoryRef, Error> {\n    self.inner.borrow_mut().memory = Some(MemoryInstance::alloc(Pages(_memory_type.initial() as usize), Some(Pages(100))).unwrap());\n    Ok(self.inner.borrow().memory.as_ref().unwrap().clone())\n  }\n}\n"
  },
  {
    "path": "src/async/mod.rs",
    "content": "use config::{ApplicationState, Config};\n\nuse mio::*;\nuse mio::net::{TcpListener, TcpStream};\nuse mio::unix::UnixReady;\nuse std::rc::Rc;\nuse std::cell::RefCell;\nuse std::collections::VecDeque;\nuse slab::Slab;\n\nmod host;\nmod session;\n\nconst SERVER: Token = Token(0);\n\npub fn server(config: Config) {\n  let state = ApplicationState::new(&config);\n\n  let addr = (&config.listen_address).parse().unwrap();\n  let server = TcpListener::bind(&addr).unwrap();\n\n  let mut poll = Poll::new().unwrap();\n\n  poll\n    .register(&server, SERVER, Ready::readable(), PollOpt::edge())\n    .unwrap();\n\n  let mut events = Events::with_capacity(1024);\n\n  let state = Rc::new(RefCell::new(state));\n  let mut connections = Slab::with_capacity(1024);\n  let mut ready = VecDeque::new();\n\n  loop {\n    poll.poll(&mut events, None).unwrap();\n    println!(\"got events: {:?}\", events);\n\n    for event in events.iter() {\n      match event.token() {\n        SERVER => {\n          if let Ok((sock, addr)) = server.accept() {\n            match connections.vacant_entry() {\n              None => {\n                println!(\"error: no more room for new connections\");\n              }\n              Some(entry) => {\n                let index = entry.index();\n                poll.register(\n                  &sock,\n                  Token(index + 1),\n                  Ready::readable() | Ready::writable() | Ready::from(UnixReady::hup() | UnixReady::error()),\n                  PollOpt::edge(),\n                );\n\n                let client = Rc::new(RefCell::new(session::Session::new(\n                  state.clone(),\n                  sock,\n                  index,\n                )));\n                entry.insert(client);\n              }\n            }\n          }\n        }\n        Token(i) => {\n          let client_token = i - 1;\n\n          if let Some(ref mut client) = connections.get_mut(client_token) {\n            if client\n              .borrow_mut()\n              .process_events(client_token, event.readiness())\n            {\n              ready.push_back(client_token);\n            }\n          } else {\n            println!(\n              \"non existing token {:?} got events {:?}\",\n              client_token,\n              event.readiness()\n            );\n          }\n        }\n        _ => unreachable!(),\n      }\n    }\n\n    for client_token in ready.drain(..) {\n      let mut cont = session::ExecutionResult::Continue;\n      if let Some(ref mut client) = connections.get_mut(client_token) {\n        cont = client.borrow_mut().execute();\n      } else {\n        println!(\"non existing token {:?} was marked as ready\", client_token);\n      }\n\n      match cont {\n        session::ExecutionResult::Close(tokens) => {\n          for t in tokens.iter() {\n            connections.remove(client_token);\n          }\n        },\n        session::ExecutionResult::ConnectBackend(address) => {\n          let client = connections.get(client_token).unwrap().clone();\n\n          match connections.vacant_entry() {\n            None => {\n              println!(\"error: no more room for new connections\");\n            }\n            Some(entry) => {\n              let index = entry.index();\n              let stream = TcpStream::connect(&address).unwrap();\n              poll.register(\n                &stream,\n                Token(index + 1),\n                Ready::readable() | Ready::writable() | Ready::from(UnixReady::hup() | UnixReady::error()),\n                PollOpt::edge(),\n              );\n              client.borrow_mut().add_backend(stream, index);\n\n              entry.insert(client);\n            }\n          }\n        },\n        _  => {}\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/async/session.rs",
    "content": "use mio::unix::UnixReady;\nuse mio::net::TcpStream;\nuse mio::{Poll, Ready};\nuse std::collections::HashMap;\nuse std::iter::repeat;\nuse std::rc::Rc;\nuse std::io::{ErrorKind, Read, Write};\nuse std::cell::RefCell;\nuse std::net::{SocketAddr, Shutdown};\nuse slab::Slab;\n\nuse interpreter::WasmInstance;\nuse super::host;\nuse config::ApplicationState;\nuse httparse;\nuse wasmi::{ExternVal, ImportsBuilder, ModuleInstance, TrapKind, RuntimeValue};\n\n#[derive(Debug, Clone, PartialEq)]\npub enum ExecutionResult {\n  WouldBlock,\n  Close(Vec<usize>),\n  Continue,\n  ConnectBackend(SocketAddr),\n  //Register(usize),\n  //Remove(Vec<usize>),\n}\n\n#[derive(Debug)]\npub struct Stream {\n  pub readiness: UnixReady,\n  pub interest: UnixReady,\n  pub stream: TcpStream,\n  pub index: usize,\n}\n\npub struct Buf {\n  buf: Vec<u8>,\n  offset: usize,\n  len: usize,\n}\n\n#[derive(Debug,Clone,PartialEq)]\npub enum SessionState {\n  WaitingForRequest,\n  WaitingForBackendConnect(usize),\n  TcpRead(i32, u32, usize),\n  TcpWrite(i32, Vec<u8>, usize),\n  Executing,\n  Done,\n}\n\npub struct Session {\n  client: Stream,\n  backends: HashMap<usize, Stream>,\n  instance: Option<WasmInstance<host::State, host::AsyncHost>>,\n  config: Rc<RefCell<ApplicationState>>,\n  buffer: Buf,\n  pub state: Option<SessionState>,\n  method: Option<String>,\n  path: Option<String>,\n  env: Option<Rc<RefCell<host::State>>>,\n}\n\nimpl Session {\n  pub fn new(config: Rc<RefCell<ApplicationState>>, stream: TcpStream, index: usize) -> Session {\n    let client = Stream {\n      readiness: UnixReady::from(Ready::empty()),\n      interest: UnixReady::from(Ready::readable()) | UnixReady::hup() | UnixReady::error(),\n      stream,\n      index,\n    };\n\n    let capacity = 8192;\n    let mut v = Vec::with_capacity(capacity);\n    v.extend(repeat(0).take(capacity));\n    let buffer = Buf {\n      buf: v,\n      offset: 0,\n      len: 0,\n    };\n\n    Session {\n      client,\n      backends: HashMap::new(),\n      instance: None,\n      config,\n      buffer,\n      state: Some(SessionState::WaitingForRequest),\n      method: None,\n      path: None,\n      env: None,\n    }\n  }\n\n  pub fn add_backend(&mut self, stream: TcpStream, index: usize) {\n    let s = Stream {\n      readiness: UnixReady::from(Ready::empty()),\n      interest: UnixReady::from(Ready::writable()) | UnixReady::hup() | UnixReady::error(),\n      stream,\n      index,\n    };\n\n    self.backends.insert(index, s);\n\n    self.state = Some(SessionState::WaitingForBackendConnect(index));\n  }\n\n  pub fn resume(&mut self)  -> ExecutionResult {\n    let res = self.instance.as_mut().map(|instance| instance.resume()).unwrap();\n    println!(\"resume result: {:?}\", res);\n    match res {\n      Err(t) => match t.kind() {\n        TrapKind::Host(ref err) => {\n          match err.as_ref().downcast_ref() {\n            Some(host::AsyncHostError::Connecting(address)) => {\n              println!(\"returning connect to backend server: {}\", address);\n              return ExecutionResult::ConnectBackend(address.clone());\n            },\n            Some(host::AsyncHostError::TcpWrite(fd, ptr, sz, written)) => {\n              self.backends.get_mut(&(*fd as usize)).map(|backend| backend.interest.insert(UnixReady::from(Ready::writable())));\n              let buf = self.env.as_mut().and_then(|env| env.borrow_mut().get_buf(*ptr, *sz as usize)).unwrap();\n              self.state = Some(SessionState::TcpWrite(*fd, buf, *written));\n              return ExecutionResult::Continue;\n            },\n            Some(host::AsyncHostError::TcpRead(fd, ptr, sz)) => {\n              self.backends.get_mut(&(*fd as usize)).map(|backend| backend.interest.insert(UnixReady::from(Ready::readable())));\n              self.state = Some(SessionState::TcpRead(*fd, *ptr, *sz as usize));\n              return ExecutionResult::Continue;\n            },\n            _ => { panic!(\"got host error: {:?}\", err) }\n          }\n        },\n        _ => {\n          panic!(\"got trap: {:?}\", t);\n        }\n      },\n      Ok(_) => if self\n        .instance\n        .as_mut()\n        .map(|instance| {\n          println!(\n            \"set up response: {:?}\",\n            instance.state.borrow().prepared_response\n          );\n          instance\n            .state\n            .borrow()\n            .prepared_response\n            .status_code\n            .is_some() && instance.state.borrow().prepared_response.body.is_some()\n        })\n        .unwrap_or(false)\n      {\n        self.client.interest.insert(Ready::writable());\n        return ExecutionResult::Continue\n      }\n    }\n\n    ExecutionResult::Continue\n  }\n\n  pub fn create_instance(&mut self) -> ExecutionResult {\n    let method = self.method.as_ref().unwrap();\n    let path = self.path.as_ref().unwrap();\n    if let Some((func_name, module, ref opt_env)) = self.config.borrow().route(method, path) {\n      let mut env = host::State::new();\n      if let Some(h) = opt_env {\n        env.db.extend(\n          h.iter()\n            .map(|(ref k, ref v)| (k.to_string(), v.to_string())),\n        );\n      }\n\n      let env = Rc::new(RefCell::new(env));\n      self.env = Some(env.clone());\n      let resolver = host::StateResolver { inner: env.clone() };\n\n      let main = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver(\"env\", &resolver))\n        .expect(\"Failed to instantiate module\")\n        .assert_no_start();\n\n      if let Some(ExternVal::Func(func_ref)) = main.export_by_name(func_name) {\n        let instance = WasmInstance::new(env, &func_ref, &[]);\n        self.instance = Some(instance);\n        ExecutionResult::Continue\n      } else {\n        println!(\"function not found\");\n        self\n          .client\n          .stream\n          .write(b\"HTTP/1.1 404 Not Found\\r\\nContent-length: 19\\r\\n\\r\\nFunction not found\\n\");\n        self.client.stream.shutdown(Shutdown::Both);\n        self.client.interest = UnixReady::from(Ready::empty());\n        ExecutionResult::Close(vec![self.client.index])\n      }\n    } else {\n      println!(\"route not found\");\n      self\n        .client\n        .stream\n        .write(b\"HTTP/1.1 404 Not Found\\r\\nContent-length: 16\\r\\n\\r\\nRoute not found\\n\");\n      self.client.stream.shutdown(Shutdown::Both);\n      self.client.interest = UnixReady::from(Ready::empty());\n      ExecutionResult::Close(vec![self.client.index])\n    }\n  }\n\n  pub fn process_events(&mut self, token: usize, events: Ready) -> bool {\n    println!(\"client[{}]:  token {} got events {:?}\", self.client.index, token, events);\n    if token == self.client.index {\n      self.client.readiness = self.client.readiness | UnixReady::from(events);\n\n      self.client.readiness & self.client.interest != UnixReady::from(Ready::empty())\n    } else {\n      if let Some(ref mut stream) = self.backends.get_mut(&token) {\n        println!(\"state: {:?}\", self.state);\n        if self.state == Some(SessionState::WaitingForBackendConnect(token)) {\n          self.instance.as_mut().map(|instance| instance.add_function_result(RuntimeValue::I32(token as i32)));\n          self.state = Some(SessionState::Executing);\n        }\n\n        stream.readiness.insert(UnixReady::from(events));\n        stream.readiness & stream.interest != UnixReady::from(Ready::empty())\n      } else {\n        println!(\"non existing backend {} got events {:?}\", token, events);\n        false\n      }\n    }\n  }\n\n  pub fn execute(&mut self) -> ExecutionResult {\n    loop {\n      let front_readiness = self.client.readiness & self.client.interest;\n\n      if front_readiness.is_readable() {\n        let res = self.front_readable();\n        if res != ExecutionResult::Continue {\n          return res;\n        }\n      }\n\n      if front_readiness.is_writable() {\n        let res = self.front_writable();\n        if res != ExecutionResult::Continue {\n          return res;\n        }\n      }\n\n      let res = self.process();\n      if res != ExecutionResult::Continue {\n        return res;\n      }\n\n    }\n  }\n\n  fn front_readable(&mut self) -> ExecutionResult {\n    if self.state == Some(SessionState::WaitingForRequest) {\n      loop {\n        if self.buffer.offset + self.buffer.len == self.buffer.buf.len() {\n          break;\n        }\n\n        match self\n          .client\n          .stream\n          .read(&mut self.buffer.buf[self.buffer.offset + self.buffer.len..])\n        {\n          Ok(0) => {\n            return ExecutionResult::Close(vec![self.client.index]);\n          }\n          Ok(sz) => {\n            self.buffer.len += sz;\n          }\n          Err(e) => {\n            if e.kind() == ErrorKind::WouldBlock {\n              self.client.readiness.remove(Ready::readable());\n              break;\n            }\n          }\n        }\n      }\n\n      ExecutionResult::Continue\n    } else {\n      ExecutionResult::Close(vec![self.client.index])\n    }\n  }\n\n  fn process(&mut self) -> ExecutionResult {\n    println!(\"[{}] process\", self.client.index);\n\n    let state = self.state.take().unwrap();\n    match state {\n      SessionState::WaitingForRequest => {\n\n        let (method, path) = {\n          let mut headers = [httparse::Header {\n            name: \"\",\n            value: &[],\n          }; 16];\n          let mut req = httparse::Request::new(&mut headers);\n          match req.parse(&self.buffer.buf[self.buffer.offset..self.buffer.len]) {\n            Err(e) => {\n              println!(\"http parsing error: {:?}\", e);\n              self.state = Some(SessionState::WaitingForRequest);\n              return ExecutionResult::Close(vec![self.client.index]);\n            }\n            Ok(httparse::Status::Partial) => {\n              self.state = Some(SessionState::WaitingForRequest);\n              return ExecutionResult::Continue;\n            }\n            Ok(httparse::Status::Complete(sz)) => {\n              self.buffer.offset += sz;\n              println!(\"got request: {:?}\", req);\n              (\n                req.method.unwrap().to_string(),\n                req.path.unwrap().to_string(),\n              )\n            }\n          }\n        };\n\n        self.client.interest.remove(Ready::readable());\n        self.method = Some(method);\n        self.path   = Some(path);\n        self.state  = Some(SessionState::Executing);\n        ExecutionResult::Continue\n      },\n      SessionState::Executing => {\n        if self.instance.is_none() {\n          let res = self.create_instance();\n          if res != ExecutionResult::Continue {\n            self.state = Some(SessionState::Executing);\n            return res;\n          }\n        }\n\n        println!(\"resuming\");\n        self.state = Some(SessionState::Executing);\n        self.resume()\n      },\n      SessionState::TcpRead(fd, ptr, sz) => {\n        let readiness = self.backends[&(fd as usize)].readiness & self.backends[&(fd as usize)].interest;\n        println!(\"tcpread({}): readiness: {:?}\", fd, readiness);\n        if readiness.is_readable() {\n          let mut buffer = Vec::with_capacity(sz as usize);\n          buffer.extend(repeat(0).take(sz as usize));\n          let mut read = 0usize;\n\n          loop {\n            match self.backends.get_mut(&(fd as usize)).unwrap().stream.read(&mut buffer[read..]) {\n              Ok(0) => {\n                println!(\"read 0\");\n                self.backends.get_mut(&(fd as usize)).map(|backend| backend.readiness.remove(Ready::readable()));\n                self.env.as_mut().map(|env| env.borrow_mut().write_buf(ptr, &buffer[..read]));\n                self.instance.as_mut().map(|instance| instance.add_function_result(RuntimeValue::I64(read as i64)));\n                self.state = Some(SessionState::Executing);\n                return ExecutionResult::Continue;\n              },\n              Ok(sz) => {\n                read += sz;\n                println!(\"read {} bytes\", read);\n\n                if read == sz {\n                  //FIXME: return result\n                  self.env.as_mut().map(|env| env.borrow_mut().write_buf(ptr, &buffer[..read]));\n                  self.instance.as_mut().map(|instance| instance.add_function_result(RuntimeValue::I64(read as i64)));\n                  self.state = Some(SessionState::Executing);\n                  return ExecutionResult::Continue;\n                }\n              },\n              Err(e) => match e.kind() {\n                ErrorKind::WouldBlock => {\n                  println!(\"wouldblock\");\n                  self.backends.get_mut(&(fd as usize)).map(|backend| backend.readiness.remove(Ready::readable()));\n                  self.env.as_mut().map(|env| env.borrow_mut().write_buf(ptr, &buffer[..read]));\n                  self.instance.as_mut().map(|instance| instance.add_function_result(RuntimeValue::I64(read as i64)));\n                  self.state = Some(SessionState::Executing);\n                  return ExecutionResult::Continue;\n                },\n                e => {\n                  println!(\"backend socket error: {:?}\", e);\n                  self.instance.as_mut().map(|instance| instance.add_function_result(RuntimeValue::I64(-1)));\n                  self.state = Some(SessionState::Executing);\n                  //FIXME\n                  return ExecutionResult::Continue;\n                }\n              }\n            }\n          }\n        } else {\n          self.state = Some(SessionState::TcpRead(fd, ptr, sz));\n          ExecutionResult::WouldBlock\n        }\n      },\n      SessionState::TcpWrite(fd, buffer, mut written) => {\n        let readiness = self.backends[&(fd as usize)].readiness & self.backends[&(fd as usize)].interest;\n        if readiness.is_writable() {\n          loop {\n            match self.backends.get_mut(&(fd as usize)).unwrap().stream.write(&buffer[written..]) {\n              Ok(0) => {\n                self.backends.get_mut(&(fd as usize)).map(|backend| backend.readiness.remove(Ready::writable()));\n                self.instance.as_mut().map(|instance| instance.add_function_result(RuntimeValue::I64(written as i64)));\n                self.state = Some(SessionState::Executing);\n                return ExecutionResult::Continue;\n              },\n              Ok(sz) => {\n                written += sz;\n                println!(\"wrote {} bytes\", sz);\n\n                if written == buffer.len() {\n                  //FIXME: return result\n                  self.state = Some(SessionState::Executing);\n                  self.instance.as_mut().map(|instance| instance.add_function_result(RuntimeValue::I64(written as i64)));\n                  return ExecutionResult::Continue;\n                }\n              },\n              Err(e) => match e.kind() {\n                ErrorKind::WouldBlock => {\n                  println!(\"wouldblock\");\n                  self.backends.get_mut(&(fd as usize)).map(|backend| backend.readiness.remove(Ready::writable()));\n                  self.state = Some(SessionState::TcpWrite(fd, buffer, written));\n                  return ExecutionResult::Continue;\n                },\n                e => {\n                  println!(\"backend socket error: {:?}\", e);\n                  self.instance.as_mut().map(|instance| instance.add_function_result(RuntimeValue::I64(-1)));\n                  self.state = Some(SessionState::Executing);\n                  //FIXME\n                  return ExecutionResult::Continue;\n                }\n              }\n            }\n          }\n\n        } else {\n          self.state = Some(SessionState::TcpWrite(fd, buffer, written));\n          ExecutionResult::WouldBlock\n        }\n\n\n        //FIXME: handle error and hup\n\n      },\n      SessionState::WaitingForBackendConnect(_) => {\n        panic!(\"should not have called execute() in WaitingForBackendConnect\");\n      },\n      SessionState::Done => {\n        panic!(\"done\");\n      }\n    }\n  }\n\n  fn front_writable(&mut self) -> ExecutionResult {\n    println!(\"[{}] front writable\", self.client.index);\n    let response = self\n      .instance\n      .as_mut()\n      .map(|instance| instance.state.borrow().prepared_response.clone())\n      .unwrap();\n\n    self\n      .client\n      .stream\n      .write_fmt(format_args!(\"HTTP/1.1 {} {}\\r\\n\", response.status_code.unwrap(), response.reason.unwrap()));\n    for header in response.headers.iter() {\n      self\n        .client\n        .stream\n        .write_fmt(format_args!(\"{}: {}\\r\\n\", header.0, header.1));\n    }\n    self.client.stream.write(b\"\\r\\n\");\n    self.client.stream.write(&response.body.unwrap()[..]);\n\n    ExecutionResult::Close(vec![self.client.index])\n  }\n}\n"
  },
  {
    "path": "src/config.rs",
    "content": "use interpreter::load_module;\nuse std::collections::HashMap;\nuse std::fs::File;\nuse std::io::Read;\nuse toml;\nuse wasmi::Module;\n\n#[derive(Deserialize, Debug)]\npub struct WasmApp {\n  pub file_path: String,\n  pub method: String,\n  pub url_path: String,\n  pub function: String,\n  pub env: Option<HashMap<String, String>>,\n}\n\n#[derive(Deserialize, Debug)]\npub struct Config {\n  pub listen_address: String,\n  pub applications: Vec<WasmApp>,\n}\n\npub fn load(file: &str) -> Option<Config> {\n  if let Ok(mut file) = File::open(file) {\n    let mut contents = String::new();\n    if let Ok(_) = file.read_to_string(&mut contents) {\n      return toml::from_str(&contents)\n        .map_err(|e| {\n          println!(\"configuration deserialization error: {:?}\", e);\n          e\n        })\n        .ok();\n    }\n  }\n  None\n}\n\npub struct ApplicationState {\n  /// (method, url path) -> (function name, module path, env)\n  pub routes: HashMap<(String, String), (String, String, Option<HashMap<String, String>>)>,\n  /// module path -> Module\n  pub modules: HashMap<String, Module>,\n}\n\nimpl ApplicationState {\n  pub fn new(config: &Config) -> ApplicationState {\n    let mut routes = HashMap::new();\n    let mut modules = HashMap::new();\n\n    for app in config.applications.iter() {\n      //FIXME: it might be good to not panic when we don't find the function in the module\n      let module = load_module(&app.file_path, &app.function);\n\n      if !modules.contains_key(&app.file_path) {\n        modules.insert(app.file_path.clone(), module);\n      }\n\n      routes.insert(\n        (app.method.clone(), app.url_path.clone()),\n        (app.function.clone(), app.file_path.clone(), app.env.clone()),\n      );\n    }\n\n    ApplicationState {\n      routes: routes,\n      modules: modules,\n    }\n  }\n\n  pub fn route(&self, method: &str, url: &str) -> Option<(&str, &Module, &Option<HashMap<String, String>>)> {\n    if let Some((func_name, module_path, ref opt_env)) = self.routes.get(&(method.to_string(), url.to_string())) {\n      if let Some(module) = self.modules.get(module_path) {\n        return Some((func_name, module, opt_env));\n      }\n    }\n\n    None\n  }\n}\n"
  },
  {
    "path": "src/interpreter.rs",
    "content": "use parity_wasm;\nuse parity_wasm::elements::{External, FunctionType, Internal, Type, ValueType};\nuse std::collections::VecDeque;\nuse wasmi::{self, Module};\nuse wasmi::{BlockFrameType, Externals, FuncInstance, FuncRef, FunctionContext, Interpreter, RunResult, RuntimeValue, Trap, TrapKind};\nuse std::marker;\nuse std::rc::Rc;\nuse std::cell::RefCell;\n\npub const DEFAULT_VALUE_STACK_LIMIT: usize = 16384;\npub const DEFAULT_FRAME_STACK_LIMIT: usize = 16384;\n\npub trait HostBuilder<'a, S> {\n  fn build(s: &'a mut S) -> Self;\n}\n\npub trait Host {\n  type State;\n\n  fn build(s: Rc<RefCell<Self::State>>) -> Self;\n}\n\npub struct WasmInstance<S, E: Externals + Host<State = S>> {\n  pub state: Rc<RefCell<S>>,\n  pub stack: VecDeque<FunctionContext>,\n  _marker: marker::PhantomData<E>,\n}\n\nimpl<S, E: Externals + Host<State = S>> WasmInstance<S, E> {\n  pub fn new(state: Rc<RefCell<S>>, func_ref: &FuncRef, args: &[RuntimeValue]) -> WasmInstance<S, E> {\n    let stack = create_stack(&func_ref, args);\n\n    WasmInstance {\n      state: state,\n      stack,\n      _marker: marker::PhantomData,\n    }\n  }\n\n  pub fn resume(&mut self) -> Result<Option<RuntimeValue>, Trap> {\n    let mut host = E::build(self.state.clone());\n    let mut interpreter = Interpreter::new(&mut host);\n\n    println!(\"WasmInstance::resume: stack\\n{:?}\", self.stack);\n    my_run_interpreter_loop(&mut interpreter, &mut self.stack)\n  }\n\n  pub fn add_function_result(&mut self, return_value: RuntimeValue) {\n    self.stack.back_mut().map(|function_context| {\n      function_context.value_stack_mut().push(return_value).expect(\"should have pushed the return value\");\n      println!(\"adding return value to {:?} initialized: {}\",\n        function_context.function, function_context.is_initialized);\n    });\n    println!(\"added function result {:?}, stack len:{}\", return_value, self.stack.len());\n  }\n}\n\npub fn create_stack(func: &FuncRef, args: &[RuntimeValue]) -> VecDeque<FunctionContext> {\n  let context = FunctionContext::new(\n    func.clone(),\n    DEFAULT_VALUE_STACK_LIMIT,\n    DEFAULT_FRAME_STACK_LIMIT,\n    func.signature(),\n    args.into_iter().cloned().collect(),\n  );\n\n  let mut function_stack = VecDeque::new();\n  function_stack.push_back(context);\n\n  function_stack\n}\n\npub fn my_run_interpreter_loop<E>(\n  interpreter: &mut Interpreter<E>,\n  function_stack: &mut VecDeque<FunctionContext>,\n) -> Result<Option<RuntimeValue>, Trap>\nwhere\n  E: Externals,\n{\n  loop {\n    let mut function_context = function_stack\n      .pop_back()\n      .expect(\"on loop entry - not empty; on loop continue - checking for emptiness; qed\");\n    let function_ref = function_context.function.clone();\n    let function_body = function_ref\n      .body()\n      .expect(\"Host functions checked in function_return below; Internal functions always have a body; qed\");\n    if !function_context.is_initialized() {\n      let return_type = function_context.return_type;\n      function_context.initialize(&function_body.locals);\n      function_context\n        .push_frame(&function_body.labels, BlockFrameType::Function, return_type)\n        .map_err(Trap::new)?;\n    }\n\n    let function_return = interpreter\n      .do_run_function(\n        &mut function_context,\n        function_body.opcodes.elements(),\n        &function_body.labels,\n      )\n      .map_err(Trap::new)?;\n\n    match function_return {\n      RunResult::Return(return_value) => match function_stack.back_mut() {\n        Some(caller_context) => if let Some(return_value) = return_value {\n          caller_context\n            .value_stack_mut()\n            .push(return_value)\n            .map_err(Trap::new)?;\n        },\n        None => return Ok(return_value),\n      },\n      RunResult::NestedCall(nested_func) => {\n        //println!(\"calling nested func, stack len={}\", function_stack.len());\n        match FuncInstance::invoke_context(&nested_func, &mut function_context, interpreter.externals) {\n          Err(t) => {\n            if let TrapKind::Host(_) = t.kind() {\n              //function_context.value_stack_mut().push(RuntimeValue::I32(42)).expect(\"should have pushed the return value\");\n              function_stack.push_back(function_context);\n              println!(\"got host trapkind\");\n              return Err(t);\n            } else {\n              println!(\"resume got error: {:?}\", t);\n              return Err(t);\n            }\n          },\n          Ok(None) => {\n            function_stack.push_back(function_context);\n            //println!(\"got ok(none) stack len={}\", function_stack.len());\n          }\n          Ok(Some(nested_context)) => {\n            function_stack.push_back(function_context);\n            function_stack.push_back(nested_context);\n            //println!(\"got ok(some(nested_context)) stack len={}\", function_stack.len());\n          }\n        }\n      }\n    }\n  }\n}\n\npub fn load_module(file: &str, func_name: &str) -> Module {\n  let module = parity_wasm::deserialize_file(file).expect(\"File to be deserialized\");\n\n  // Extracts call arguments from command-line arguments\n  let _args = {\n    // Export section has an entry with a func_name with an index inside a module\n    let export_section = module.export_section().expect(\"No export section found\");\n    // It's a section with function declarations (which are references to the type section entries)\n    let function_section = module\n      .function_section()\n      .expect(\"No function section found\");\n    // Type section stores function types which are referenced by function_section entries\n    let type_section = module.type_section().expect(\"No type section found\");\n\n    // Given function name used to find export section entry which contains\n    // an `internal` field which points to the index in the function index space\n    let found_entry = export_section\n      .entries()\n      .iter()\n      .find(|entry| func_name == entry.field())\n      .expect(&format!(\"No export with name {} found\", func_name));\n\n    // Function index in the function index space (internally-defined + imported)\n    let function_index: usize = match found_entry.internal() {\n      &Internal::Function(index) => index as usize,\n      _ => panic!(\"Founded export is not a function\"),\n    };\n\n    // We need to count import section entries (functions only!) to subtract it from function_index\n    // and obtain the index within the function section\n    let import_section_len: usize = match module.import_section() {\n      Some(import) => import\n        .entries()\n        .iter()\n        .map(|entry| {\n          //println!(\"importing entry {:?}\", entry);\n          entry\n        })\n        .filter(|entry| match entry.external() {\n          &External::Function(_) => true,\n          _ => false,\n        })\n        .count(),\n      None => 0,\n    };\n\n    // Calculates a function index within module's function section\n    let function_index_in_section = function_index - import_section_len;\n\n    // Getting a type reference from a function section entry\n    let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;\n\n    // Use the reference to get an actual function type\n    let function_type: &FunctionType = match &type_section.types()[func_type_ref] {\n      &Type::Function(ref func_type) => func_type,\n    };\n\n    // Parses arguments and constructs runtime values in correspondence of their types\n    function_type\n      .params()\n      .iter()\n      .enumerate()\n      .map(|(_i, value)| match value {\n        &ValueType::I32 => RuntimeValue::I32(\n          0, /* program_args[i]\n\t\t\t\t\t\t\t\t.parse::<i32>()\n\t\t\t\t\t\t\t\t.expect(&format!(\"Can't parse arg #{} as i32\", program_args[i])),*/\n        ),\n        &ValueType::I64 => RuntimeValue::I64(\n          0, /*  program_args[i]\n\t\t\t\t\t\t\t\t\t .parse::<i64>()\n\t\t\t\t\t\t\t\t\t .expect(&format!(\"Can't parse arg #{} as i64\", program_args[i])),*/\n        ),\n        &ValueType::F32 => RuntimeValue::F32(\n          0.0, /* program_args[i]\n\t\t\t\t\t\t\t\t\t\t.parse::<f32>()\n\t\t\t\t\t\t\t\t\t\t.expect(&format!(\"Can't parse arg #{} as f32\", program_args[i])),*/\n        ),\n        &ValueType::F64 => RuntimeValue::F64(\n          0.0, /*  program_args[i]\n\t\t\t\t\t\t\t\t\t\t .parse::<f64>()\n\t\t\t\t\t\t\t\t\t\t .expect(&format!(\"Can't parse arg #{} as f64\", program_args[i])),*/\n        ),\n      })\n      .collect::<Vec<RuntimeValue>>()\n  };\n\n  wasmi::Module::from_parity_wasm_module(module).expect(\"Module to be valid\")\n}\n"
  },
  {
    "path": "src/jit/env.rs",
    "content": "use cretonne_wasm::{\n  ModuleEnvironment, GlobalIndex, MemoryIndex, TableIndex,\n  FunctionIndex, Table, Memory, Global, SignatureIndex,\n  FuncTranslator, FuncEnvironment, GlobalValue\n};\nuse cretonne::prelude::{settings::{self, Flags}, types::*, InstBuilder, Signature};\nuse cretonne::codegen::{\n  ir::{self, ExternalName, Function},\n  cursor::FuncCursor\n};\n\npub struct Exportable<T> {\n  /// A wasm entity.\n  pub entity: T,\n\n  /// Names under which the entity is exported.\n  pub export_names: Vec<String>,\n}\n\nimpl<T> Exportable<T> {\n  pub fn new(entity: T) -> Self {\n    Self {\n      entity,\n      export_names: Vec::new(),\n    }\n  }\n}\n\npub struct ModuleInfo {\n  pub flags: Flags,\n  pub signatures: Vec<Signature>,\n  pub imported_funcs: Vec<(String, String)>,\n  pub functions: Vec<Exportable<SignatureIndex>>,\n  pub function_bodies: Vec<Function>,\n  pub memories: Vec<Exportable<Memory>>,\n  pub tables: Vec<Exportable<Table>>,\n  pub globals: Vec<Exportable<Global>>,\n  pub start_func: Option<FunctionIndex>,\n}\n\nimpl ModuleInfo {\n  pub fn new() -> ModuleInfo {\n    ModuleInfo {\n      flags: settings::Flags::new(settings::builder()),\n      signatures: Vec::new(),\n      imported_funcs: Vec::new(),\n      functions: Vec::new(),\n      function_bodies: Vec::new(),\n      memories: Vec::new(),\n      tables: Vec::new(),\n      globals: Vec::new(),\n      start_func: None,\n    }\n  }\n}\n\npub struct Env {\n  pub info: ModuleInfo,\n  trans: FuncTranslator,\n}\n\nimpl Env {\n  pub fn new() -> Env {\n    Env {\n      info: ModuleInfo::new(),\n      trans: FuncTranslator::new(),\n    }\n  }\n}\n\nfn get_func_name(func_index: FunctionIndex) -> ir::ExternalName {\n  ExternalName::user(0, func_index as u32)\n}\n\nimpl<'data> ModuleEnvironment<'data> for Env {\n  fn flags(&self) -> &Flags {\n    &self.info.flags\n  }\n\n  fn get_func_name(&self, func_index: FunctionIndex) -> ExternalName {\n    get_func_name(func_index)\n  }\n\n  fn declare_signature(&mut self, sig: &Signature) {\n    self.info.signatures.push(sig.clone());\n  }\n\n  fn get_signature(&self, sig_index: SignatureIndex) -> &Signature {\n    &self.info.signatures[sig_index]\n  }\n\n  fn declare_func_import(\n      &mut self,\n      sig_index: SignatureIndex,\n      module: &'data str,\n      field: &'data str\n  ) {\n    assert_eq!(\n            self.info.functions.len(),\n            self.info.imported_funcs.len(),\n            \"Imported functions must be declared first\"\n        );\n    self.info.functions.push(Exportable::new(sig_index));\n    self.info.imported_funcs.push((\n      String::from(module),\n      String::from(field),\n    ));\n    println!(\"declared function import {}:{}\", module, field);\n  }\n\n  fn get_num_func_imports(&self) -> usize {\n    self.info.imported_funcs.len()\n  }\n\n  fn declare_func_type(&mut self, sig_index: SignatureIndex) {\n    self.info.functions.push(Exportable::new(sig_index));\n  }\n\n  fn get_func_type(&self, func_index: FunctionIndex) -> SignatureIndex {\n    self.info.functions[func_index].entity\n  }\n\n  fn declare_global(&mut self, global: Global) {\n    self.info.globals.push(Exportable::new(global));\n  }\n\n  fn get_global(&self, global_index: GlobalIndex) -> &Global {\n    &self.info.globals[global_index].entity\n  }\n\n  fn declare_table(&mut self, table: Table) {\n    self.info.tables.push(Exportable::new(table));\n  }\n\n  fn declare_table_elements(\n      &mut self,\n      table_index: TableIndex,\n      base: Option<GlobalIndex>,\n      offset: usize,\n      elements: Vec<FunctionIndex>\n  ) {\n    //println!(\"declaring table elements at table n°{} base {:?} offset {}:{:?}\", table_index, base, offset, elements);\n  }\n\n  fn declare_memory(&mut self, memory: Memory) {\n    println!(\"declaring new memory zone, min: {}, max: {:?}, shared: {}\", memory.pages_count, memory.maximum,\n      memory.shared);\n    self.info.memories.push(Exportable::new(memory));\n  }\n\n  fn declare_data_initialization(\n      &mut self,\n      memory_index: MemoryIndex,\n      base: Option<GlobalIndex>,\n      offset: usize, \n      data: &'data [u8]\n  ) {\n    println!(\"declaring data init for memory n°{}, base {:?}, offset {}, data: {:?}\",\n      memory_index, base, offset, data.len());\n }\n\n  fn declare_func_export(\n      &mut self,\n      func_index: FunctionIndex,\n      name: &'data str\n  ) {\n    println!(\"exporting function n°{} at '{}'\", func_index, name);\n    self.info.functions[func_index].export_names.push(\n      String::from(name)\n      )\n  }\n\n  fn declare_table_export(\n      &mut self,\n      table_index: TableIndex,\n      name: &'data str\n  ) { unimplemented!() }\n  fn declare_memory_export(\n      &mut self,\n      memory_index: MemoryIndex,\n      name: &'data str\n  ) { unimplemented!() }\n  fn declare_global_export(\n      &mut self,\n      global_index: GlobalIndex,\n      name: &'data str\n  ) { unimplemented!() }\n\n  fn declare_start_func(&mut self, index: FunctionIndex) {\n    debug_assert!(self.info.start_func.is_none());\n    self.info.start_func = Some(index);\n  }\n\n  fn define_function_body(\n      &mut self,\n      body_bytes: &'data [u8]\n  ) -> Result<(), String> {\n    let func = {\n      let mut func_environ = FuncEnv::new(&self.info);\n      let function_index = self.get_num_func_imports() + self.info.function_bodies.len();\n      let name = get_func_name(function_index);\n      let sig = func_environ.vmctx_sig(self.get_func_type(function_index));\n      let mut func = Function::with_name_signature(name, sig);\n      self.trans\n        .translate(body_bytes, &mut func, &mut func_environ)\n        .map_err(|e| format!(\"{}\", e))?;\n      func\n    };\n\n    self.info.function_bodies.push(func);\n    Ok(())\n  }\n}\n\npub struct FuncEnv<'env> {\n    pub mod_info: &'env ModuleInfo,\n}\n\nimpl<'env> FuncEnv<'env> {\n    pub fn new(mod_info: &'env ModuleInfo) -> Self {\n        Self { mod_info }\n    }\n\n    // Create a signature for `sigidx` amended with a `vmctx` argument after the standard wasm\n    // arguments.\n    fn vmctx_sig(&self, sigidx: SignatureIndex) -> ir::Signature {\n        let mut sig = self.mod_info.signatures[sigidx].clone();\n        sig.params.push(ir::AbiParam::special(\n            self.native_pointer(),\n            ir::ArgumentPurpose::VMContext,\n        ));\n        sig\n    }\n}\n\nimpl<'env> FuncEnvironment for FuncEnv<'env> {\n    fn flags(&self) -> &settings::Flags {\n        &self.mod_info.flags\n    }\n\n    fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {\n        // Just create a dummy `vmctx` global.\n        let offset = ((index * 8) as i32 + 8).into();\n        let gv = func.create_global_var(ir::GlobalVarData::VMContext { offset });\n        GlobalValue::Memory {\n            gv,\n            ty: self.mod_info.globals[index].entity.ty,\n        }\n    }\n\n    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {\n        // Create a static heap whose base address is stored at `vmctx+0`.\n        let gv = func.create_global_var(ir::GlobalVarData::VMContext { offset: 0.into() });\n\n        func.create_heap(ir::HeapData {\n            base: ir::HeapBase::GlobalVar(gv),\n            min_size: 0.into(),\n            guard_size: 0x8000_0000.into(),\n            style: ir::HeapStyle::Static { bound: 0x1_0000_0000.into() },\n        })\n    }\n\n    fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {\n        // A real implementation would probably change the calling convention and add `vmctx` and\n        // signature index arguments.\n        func.import_signature(self.vmctx_sig(index))\n    }\n\n    fn make_direct_func(&mut self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {\n        let sigidx = self.mod_info.functions[index].entity;\n        // A real implementation would probably add a `vmctx` argument.\n        // And maybe attempt some signature de-duplication.\n        let signature = func.import_signature(self.vmctx_sig(sigidx));\n        let name = get_func_name(index);\n        func.import_function(ir::ExtFuncData {\n            name,\n            signature,\n            colocated: false,\n        })\n    }\n\n    fn translate_call_indirect(\n        &mut self,\n        mut pos: FuncCursor,\n        _table_index: TableIndex,\n        _sig_index: SignatureIndex,\n        sig_ref: ir::SigRef,\n        callee: ir::Value,\n        call_args: &[ir::Value],\n    ) -> ir::Inst {\n        // Pass the current function's vmctx parameter on to the callee.\n        let vmctx = pos.func\n            .special_param(ir::ArgumentPurpose::VMContext)\n            .expect(\"Missing vmctx parameter\");\n\n        // The `callee` value is an index into a table of function pointers.\n        // Apparently, that table is stored at absolute address 0 in this dummy environment.\n        // TODO: Generate bounds checking code.\n        let ptr = self.native_pointer();\n        let callee_offset = if ptr == I32 {\n            pos.ins().imul_imm(callee, 4)\n        } else {\n            let ext = pos.ins().uextend(I64, callee);\n            pos.ins().imul_imm(ext, 4)\n        };\n        let mut mflags = ir::MemFlags::new();\n        mflags.set_notrap();\n        mflags.set_aligned();\n        let func_ptr = pos.ins().load(ptr, mflags, callee_offset, 0);\n\n        // Build a value list for the indirect call instruction containing the callee, call_args,\n        // and the vmctx parameter.\n        let mut args = ir::ValueList::default();\n        args.push(func_ptr, &mut pos.func.dfg.value_lists);\n        args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);\n        args.push(vmctx, &mut pos.func.dfg.value_lists);\n\n        pos.ins()\n            .CallIndirect(ir::Opcode::CallIndirect, VOID, sig_ref, args)\n            .0\n    }\n\n    fn translate_call(\n        &mut self,\n        mut pos: FuncCursor,\n        _callee_index: FunctionIndex,\n        callee: ir::FuncRef,\n        call_args: &[ir::Value],\n    ) -> ir::Inst {\n        // Pass the current function's vmctx parameter on to the callee.\n        let vmctx = pos.func\n            .special_param(ir::ArgumentPurpose::VMContext)\n            .expect(\"Missing vmctx parameter\");\n\n        // Build a value list for the call instruction containing the call_args and the vmctx\n        // parameter.\n        let mut args = ir::ValueList::default();\n        args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);\n        args.push(vmctx, &mut pos.func.dfg.value_lists);\n\n        pos.ins().Call(ir::Opcode::Call, VOID, callee, args).0\n    }\n\n    fn translate_grow_memory(\n        &mut self,\n        mut pos: FuncCursor,\n        _index: MemoryIndex,\n        _heap: ir::Heap,\n        _val: ir::Value,\n    ) -> ir::Value {\n        pos.ins().iconst(I32, -1)\n    }\n\n    fn translate_current_memory(\n        &mut self,\n        mut pos: FuncCursor,\n        _index: MemoryIndex,\n        _heap: ir::Heap,\n    ) -> ir::Value {\n        pos.ins().iconst(I32, -1)\n    }\n}\n"
  },
  {
    "path": "src/jit/mod.rs",
    "content": "use config::Config;\n\nuse cretonne_wasm::{translate_module, DummyEnvironment};\nuse std::fs::File;\nuse std::io::Read;\n\nmod env;\n\npub fn server(config: Config) {\n  for app in config.applications.iter() {\n    println!(\"loading {}:{} at '{} {}'\", app.file_path, app.function, app.method, app.url_path);\n    if let Ok(mut file) = File::open(&app.file_path) {\n      let mut data = Vec::new();\n      file.read_to_end(&mut data);\n\n      //let mut env = DummyEnvironment::default();\n\n      let mut env = env::Env::new();\n\n      translate_module(&data, &mut env).unwrap();\n\n      //let func_env = env.func_env();\n      //println!(\"bytecode:\\n{:?}\", env.func_bytecode_sizes);\n    }\n  }\n}\n"
  },
  {
    "path": "src/main.rs",
    "content": "extern crate httparse;\nextern crate mio;\nextern crate parity_wasm;\nextern crate rouille;\nextern crate slab;\nextern crate toml;\nextern crate wasmi;\nextern crate cretonne;\nextern crate cretonne_wasm;\nextern crate cretonne_module;\nextern crate cretonne_simplejit;\n\n#[macro_use]\nextern crate serde_derive;\n\nuse std::env::args;\n\nmod async;\nmod config;\nmod interpreter;\nmod sync;\nmod jit;\n\nfn main() {\n  let args: Vec<_> = args().collect();\n  if args.len() != 2 {\n    println!(\"Usage: {} <config_file>\", args[0]);\n    return;\n  }\n\n  if let Some(config) = config::load(&args[1]) {\n    async::server(config);\n  } else {\n    println!(\"invalid configuration\");\n  }\n}\n"
  },
  {
    "path": "src/sync/host.rs",
    "content": "//! from https://github.com/paritytech/wasmi/blob/master/src/tests/host.rs\n\nuse slab::Slab;\nuse std::collections::HashMap;\nuse std::io::{Read, Write};\nuse std::iter::repeat;\nuse std::net::TcpStream;\nuse std::str;\nuse std::cmp;\nuse std::rc::Rc;\nuse std::cell::RefCell;\nuse wasmi::memory_units::Pages;\nuse wasmi::*;\nuse interpreter::Host;\n\n#[derive(Debug, Clone, PartialEq)]\nstruct HostErrorWithCode {\n  error_code: u32,\n}\n\nimpl ::std::fmt::Display for HostErrorWithCode {\n  fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {\n    write!(f, \"{}\", self.error_code)\n  }\n}\n\nimpl HostError for HostErrorWithCode {}\n\n#[derive(Clone)]\npub struct PreparedResponse {\n  pub status_code: Option<u16>,\n  pub headers: Vec<(String, String)>,\n  pub body: Option<Vec<u8>>,\n}\n\nimpl PreparedResponse {\n  pub fn new() -> PreparedResponse {\n    PreparedResponse {\n      status_code: None,\n      headers: Vec::new(),\n      body: None,\n    }\n  }\n}\n\npub struct State {\n  memory: Option<MemoryRef>,\n  instance: Option<ModuleRef>,\n  pub prepared_response: PreparedResponse,\n  connections: Slab<TcpStream>,\n  pub db: HashMap<String, String>,\n}\n\nimpl State {\n  pub fn new() -> State {\n    State {\n      memory: Some(MemoryInstance::alloc(Pages(3), Some(Pages(10))).unwrap()),\n      instance: None,\n      prepared_response: PreparedResponse::new(),\n      connections: Slab::with_capacity(100),\n      db: HashMap::new(),\n    }\n  }\n}\n\npub struct SyncHost {\n  pub inner: Rc<RefCell<State>>,\n}\n\nimpl Host for SyncHost {\n  type State = State;\n\n  fn build(s: Rc<RefCell<Self::State>>) -> Self {\n    SyncHost { inner: s }\n  }\n}\n\n/// log(ptr: *mut u8, size: u64)\n///\n/// Returns value at the given address in memory. This function\n/// requires attached memory.\nconst LOG_INDEX: usize = 0;\n\nconst RESPONSE_SET_STATUS_LINE: usize = 1;\nconst RESPONSE_SET_HEADER: usize = 2;\nconst RESPONSE_SET_BODY: usize = 3;\nconst TCP_CONNECT: usize = 4;\nconst TCP_READ: usize = 5;\nconst TCP_WRITE: usize = 6;\nconst DB_GET: usize = 7;\n\nimpl Externals for SyncHost {\n  fn invoke_index(&mut self, index: usize, args: RuntimeArgs) -> Result<Option<RuntimeValue>, Trap> {\n    match index {\n      LOG_INDEX => {\n        let ptr: u32 = args.nth(0);\n        let sz: u64 = args.nth(1);\n\n        let v = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n\n        println!(\"log({} bytes): {}\", v.len(), str::from_utf8(&v).unwrap());\n        Ok(None)\n      }\n      RESPONSE_SET_STATUS_LINE => {\n        let status: u32 = args.nth(0);\n        let ptr: u32 = args.nth(1);\n        let sz: u64 = args.nth(2);\n\n        let _reason = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n\n        self.inner.borrow_mut().prepared_response.status_code = Some(status as u16);\n\n        Ok(None)\n      }\n      RESPONSE_SET_HEADER => {\n        let ptr1: u32 = args.nth(0);\n        let sz1: u64 = args.nth(1);\n        let ptr2: u32 = args.nth(2);\n        let sz2: u64 = args.nth(3);\n        let header_name = {\n          self\n            .inner\n            .borrow()\n            .memory\n            .as_ref()\n            .expect(\"Function 'inc_mem' expects attached memory\")\n            .get(ptr1, sz1 as usize)\n            .unwrap()\n        };\n        let header_value = {\n          self\n            .inner\n            .borrow()\n            .memory\n            .as_ref()\n            .expect(\"Function 'inc_mem' expects attached memory\")\n            .get(ptr2, sz2 as usize)\n            .unwrap()\n        };\n\n        self.inner.borrow_mut().prepared_response.headers.push((\n          String::from_utf8(header_name).unwrap(),\n          String::from_utf8(header_value).unwrap(),\n        ));\n        Ok(None)\n      }\n      RESPONSE_SET_BODY => {\n        let ptr: u32 = args.nth(0);\n        let sz: u64 = args.nth(1);\n\n        let body = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n        self.inner.borrow_mut().prepared_response.body = Some(body);\n        Ok(None)\n      }\n      TCP_CONNECT => {\n        let ptr: u32 = args.nth(0);\n        let sz: u64 = args.nth(1);\n\n        let v = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n        let address = String::from_utf8(v).unwrap();\n        if let Ok(socket) = TcpStream::connect(&address) {\n          if let Ok(fd) = self.inner.borrow_mut().connections.insert(socket) {\n            Ok(Some(RuntimeValue::I32(fd as i32)))\n          } else {\n            Ok(Some(RuntimeValue::I32(-2)))\n          }\n        } else {\n          Ok(Some(RuntimeValue::I32(-1)))\n        }\n      }\n      TCP_READ => {\n        let fd: i32 = args.nth(0);\n        let ptr: u32 = args.nth(1);\n        let sz: u64 = args.nth(2);\n        let mut v = Vec::with_capacity(sz as usize);\n        v.extend(repeat(0).take(sz as usize));\n        let mut state = self.inner.borrow_mut();\n        if let Ok(sz) = state.connections[fd as usize].read(&mut v) {\n          state.memory.as_ref().map(|m| m.set(ptr, &v[..sz]));\n\n          Ok(Some(RuntimeValue::I64(sz as i64)))\n        } else {\n          Ok(Some(RuntimeValue::I64(-1)))\n        }\n      }\n      TCP_WRITE => {\n        let fd: i32 = args.nth(0);\n        let ptr: u32 = args.nth(1);\n        let sz: u64 = args.nth(2);\n\n        let buf = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(ptr, sz as usize)\n          .unwrap();\n\n        if let Ok(sz) = self.inner.borrow_mut().connections[fd as usize].write(&buf) {\n          Ok(Some(RuntimeValue::I64(sz as i64)))\n        } else {\n          Ok(Some(RuntimeValue::I64(-1)))\n        }\n      }\n      DB_GET => {\n        let key_ptr: u32 = args.nth(0);\n        let key_sz: u64 = args.nth(1);\n        let value_ptr: u32 = args.nth(2);\n        let value_sz: u64 = args.nth(3);\n\n        let v = self\n          .inner\n          .borrow()\n          .memory\n          .as_ref()\n          .expect(\"Function 'inc_mem' expects attached memory\")\n          .get(key_ptr, key_sz as usize)\n          .unwrap();\n        let key = String::from_utf8(v).unwrap();\n        println!(\"requested value for key {}\", key);\n\n        match self.inner.borrow().db.get(&key) {\n          None => Ok(Some(RuntimeValue::I64(-1))),\n          Some(value) => {\n            let to_write = cmp::min(value.len(), value_sz as usize);\n            self\n              .inner\n              .borrow()\n              .memory\n              .as_ref()\n              .map(|m| m.set(value_ptr, (&value[..to_write]).as_bytes()));\n            Ok(Some(RuntimeValue::I64(value.len() as i64)))\n          }\n        }\n      }\n      _ => panic!(\"env doesn't provide function at index {}\", index),\n    }\n  }\n}\n\nimpl State {\n  fn check_signature(&self, index: usize, signature: &Signature) -> bool {\n    let (params, ret_ty): (&[ValueType], Option<ValueType>) = match index {\n      LOG_INDEX => (&[ValueType::I32, ValueType::I64], None),\n      RESPONSE_SET_STATUS_LINE => (&[ValueType::I32, ValueType::I32, ValueType::I64], None),\n      RESPONSE_SET_HEADER => (\n        &[\n          ValueType::I32,\n          ValueType::I64,\n          ValueType::I32,\n          ValueType::I64,\n        ],\n        None,\n      ),\n      RESPONSE_SET_BODY => (&[ValueType::I32, ValueType::I64], None),\n      TCP_CONNECT => (&[ValueType::I32, ValueType::I64], Some(ValueType::I32)),\n      TCP_READ => (\n        &[ValueType::I32, ValueType::I32, ValueType::I64],\n        Some(ValueType::I64),\n      ),\n      TCP_WRITE => (\n        &[ValueType::I32, ValueType::I32, ValueType::I64],\n        Some(ValueType::I64),\n      ),\n      DB_GET => (\n        &[\n          ValueType::I32,\n          ValueType::I64,\n          ValueType::I32,\n          ValueType::I64,\n        ],\n        Some(ValueType::I64),\n      ),\n      _ => return false,\n    };\n\n    signature.params() == params && signature.return_type() == ret_ty\n  }\n}\n\nimpl ModuleImportResolver for State {\n  fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result<FuncRef, Error> {\n    let index = match field_name {\n      \"log\" => LOG_INDEX,\n      \"response_set_status_line\" => RESPONSE_SET_STATUS_LINE,\n      \"response_set_header\" => RESPONSE_SET_HEADER,\n      \"response_set_body\" => RESPONSE_SET_BODY,\n      \"tcp_connect\" => TCP_CONNECT,\n      \"tcp_read\" => TCP_READ,\n      \"tcp_write\" => TCP_WRITE,\n      \"db_get\" => DB_GET,\n      _ => {\n        return Err(Error::Instantiation(format!(\n          \"Export {} not found\",\n          field_name\n        )))\n      }\n    };\n\n    if !self.check_signature(index, signature) {\n      return Err(Error::Instantiation(format!(\n        \"Export `{}` doesnt match expected type {:?}\",\n        field_name, signature\n      )));\n    }\n\n    Ok(FuncInstance::alloc_host(signature.clone(), index))\n  }\n\n  fn resolve_memory(&self, _field_name: &str, _memory_type: &MemoryDescriptor) -> Result<MemoryRef, Error> {\n    let Pages(initial1) = self.memory.as_ref().map(|m| m.initial()).unwrap();\n    let initial2 = _memory_type.initial() as usize;\n    //println!(\"requested {} pages\", initial2);\n    if initial2 > initial1 {\n      self.memory.as_ref().map(|_m| {\n        //println!(\"grow res: {:?}\", m.grow(Pages(initial2 - initial1)).unwrap());\n      });\n    }\n    let Pages(_initial) = self.memory.as_ref().map(|m| m.current_size()).unwrap();\n    //println!(\"current number of pages: {}\", initial);\n    //println!(\"resolving memory at name: {}\", field_name);\n    let res = self.memory.as_ref().unwrap().clone();\n\n    Ok(res)\n  }\n}\n"
  },
  {
    "path": "src/sync/mod.rs",
    "content": "use rouille;\nuse wasmi::{Error, ExternVal, ImportsBuilder, ModuleInstance};\nuse std::rc::Rc;\nuse std::cell::RefCell;\n\nuse config::{ApplicationState, Config};\nuse interpreter::WasmInstance;\n\nmod host;\n\npub fn server(config: Config) {\n  let state = ApplicationState::new(&config);\n\n  rouille::start_server(&config.listen_address, move |request| {\n    if let Some((func_name, module, ref opt_env)) = state.route(request.method(), &request.url()) {\n      let mut env = host::State::new();\n      if let Some(h) = opt_env {\n        env.db.extend(\n          h.iter()\n            .map(|(ref k, ref v)| (k.to_string(), v.to_string())),\n        );\n      }\n      let main = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver(\"env\", &env))\n        .expect(\"Failed to instantiate module\")\n        .assert_no_start();\n\n      let mut response = env.prepared_response.clone();\n      if let Some(ExternVal::Func(func_ref)) = main.export_by_name(func_name) {\n        let mut instance: WasmInstance<host::State, host::SyncHost> = WasmInstance::new(Rc::new(RefCell::new(env)), &func_ref, &[]);\n        let res = instance.resume().map_err(|t| Error::Trap(t));\n        println!(\"invocation result: {:?}\", res);\n        response = instance.state.borrow().prepared_response.clone();\n      } else {\n        panic!(\"handle error here\");\n      };\n\n      if let host::PreparedResponse {\n        status_code: Some(status),\n        headers,\n        body: Some(body),\n      } = response\n      {\n        rouille::Response {\n          status_code: status,\n          headers: Vec::new(),\n          data: rouille::ResponseBody::from_data(body),\n          upgrade: None,\n        }\n      } else {\n        rouille::Response::text(\"wasm failed\").with_status_code(500)\n      }\n    } else {\n      rouille::Response::empty_404()\n    }\n  });\n}\n\n/*\npub fn start(file: &str) {\n    let module = load_module(file, \"handle\");\n    let mut env = host::SyncHost::new();\n    let main = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver(\"env\", &env))\n      .expect(\"Failed to instantiate module\")\n      .assert_no_start();\n\n    println!(\n        \"Result: {:?}\",\n        main.invoke_export(\"handle\", &[], &mut env)\n    );\n}\n*/\n"
  }
]