MileyFu
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    Build [quickjs-wasi](https://github.com/second-state/wasmedge-quickjs) === # 1. clone project ```shell # new a workspace $ makedir wasm && cd wasm # quickjs-wasi rust binding wasm/$ git clone https://github.com/second-state/wasmedge-quickjs.git # quickjs-wasi wasm/$ git clone https://github.com/second-state/quickjs-wasi.git ``` ## wasmedge-quickjs This is quickjs-wasi's rust binding. It is a rust project. It is majorly using wasi's libquickjs.a generated by quickjs-wasi to compile rust code to qjs.wasm to use javascript in wasm. This is majorly to meet the need of Rust developers who are unfamiliar with C to extend quickjs in wasm. ## quickjs-wasi This library is quickjs being changed based on wasi and some features of quickjs have been deleted. It is majorly used to provide wasmedge-quickjs with * Static library `wasmedge-quickjs/lib/libquickjs.a` * Rust binging of quickjs's C api `wasmedge-quickjs/lib/binding.rs` ### build > Usually this is not needed. > This section can be skipped. **1、Generate qjs.c and qjscalc.c** ```shell quickjs-wasi$ make ``` This repl.c and qjscalc.c is the bytecode generated with the corresponding javascript file, mainly working as the repl feature of quickjs. This will be needed in the following compilation. **2、Generate qjs.wasm** > wasi-sdk(12) should be installed ```shell quickjs-wasi$ ./build_wasi.sh ``` This is a standard wasm compiled by quickjs. It can run directly. ```shell # run quickjs repl quickjs-wasi$ wasmedge --dir=.:. qjs.wasm QuickJS - Type "\h" for help qjs > print('hello') print('hello') hello undefined qjs > ``` **3. Generate libquickjs.a & binding.rs** > Rust bindgen needs to be installed ```shell quickjs-wasi$ cd lib quickjs-wasi/lib$ ./build_lib.sh # move to wasmedge-quickjs/lib/ cp libquickjs.a ../../wasmedge-quickjs/lib/ cp binding.rs ../../wasmedge-quickjs/lib/ ``` `wapper.c` has custom function. Majorly * Packaged static functions of C * Packaged some macro into functions `wapper.h` define exported function. It will be used by `bindgen` in ./build_lib.sh to generate `binding.rs`. >If a certain program is better to be implemented by C instead of rust, we can tweak `wapper.*` then re-generate to `libquickjs.a` and `binding.rs`. # 2. build [quickjs-wasi.wasm] > cargo-wasi extension needs to be installed > `cargo install cargo-wasi` > an easy-to-compile command ## Compile a standard quickjs-wasi.wasm ```shell wasmedge-quickjs/$ cargo wasi build --release wasmedge-quickjs/$ echo "print('hello')" > example_js/hello.js wasmedge-quickjs/$ wasmedge --dir=.:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/hello.js hello wasmedge-quickjs/$ ``` ## Compile quickjs-wasi.wasm + http This is a http-client feautre extended with [wasmedge_wasi_socket](https://github.com/second-state/wasmedge_wasi_socket) . ```shell wasmedge-quickjs/$ cargo wasi build --features=http --release wasmedge-quickjs/$ wasmedge --dir=.:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/http.js haha add: 3 get-test 200 {"Connection":"close","Server":"gunicorn/19.9.0","Content-Length":"310","Content-Type":"application/json","Access-Control-Allow-Origin":"*","Access-Control-Allow-Credentials":"true","D ate":"Sat, 28 Aug 2021 21:50:49 GMT"} { "args": { "a": "123" }, "headers": { "A": "b", "C": "1,2,3", "Host": "54.198.109.87", "Referer": "http://54.198.109.87/get?a=123", "X-Amzn-Trace-Id": "Root=1-612aafb9-74d3c8cc45407da9317ca34d" }, "origin": "36.155.117.30", "url": "http://54.198.109.87/get?a=123" } delete-test 200 {"Access-Control-Allow-Origin":"*","Date":"Sat, 28 Aug 2021 21:50:50 GMT","Content-Length":"379","Server":"gunicorn/19.9.0","Content-Type":"application/json","Access-Control-Allow-Cred entials":"true","Connection":"close"} { "args": { "a": "123" }, "data": "haha=1", "files": {}, "form": {}, "headers": { "Content-Length": "6", "Host": "54.198.109.87", "Referer": "http://54.198.109.87/delete?a=123", "X-Amzn-Trace-Id": "Root=1-612aafba-3b5865be294e90da4ea88cb4" }, "json": null, "origin": "36.155.117.30", "url": "http://54.198.109.87/delete?a=123" } wasmedge-quickjs/$ ``` For specific user guide for http-client, please refer to `wasmedge-quickjs/example_js/http.js` ## Compile quickjs-wasi.wasm + img This is an image feature extended with [image-rs](https://github.com/image-rs/image). Core code: wasmedge-quickjs/src/quickjs_sys/img_module.rs ```shell wasmedge-quickjs/$ cargo wasi build --features=img --release wasmedge-quickjs/$ wasmedge --dir=.:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/img_demo.js start load image buf: [object ArrayBuffer] 279434 new image from memory rgba pixels len 40000 rgb pixels len 30000 luma pixels len 10000 wasmedge-quickjs/$ ls example_js/ add.js bird.png bird_luma.png bird_new_1.png bird_new_2.jpg http_demo.js img_demo.js tensorflow_demo tensorflow_lite_demo wasmedge-quickjs/$ ``` Among these, `bird_luma.png bird_new_1.png bird_new_2.jpg` are the newly generated images. This image library is the dependency of tensorflow. ## Compile quickjs-wasi.wasm + tensorflow This is an extension of tensorflow feature with [wasmedge_tensorflow_interface](https://github.com/second-state/wasmedge_tensorflow_interface) as reference. Core code: wasmedge-quickjs/src/quickjs_sys/tensorflow_module.rs ```shell wasmedge-quickjs/$ cargo wasi build --features=tensorflow --release ``` **tensorflow classify** ```shell wasmedge-quickjs/$ wasmedge-tensorflow --dir=.:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/tensorflow_demo/main.js label index: 23 confidence: 0.6699743270874023 wasmedge-quickjs/$ ``` This is a tensorflow model for animal image classification. Index 23 is labeled **bald eagle** with a confidence of 0.6699 (max=1.0). **tensorflow-lite classify** ```shell wasmedge-quickjs/$ wasmedge-tensorflow --dir=.:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/tensorflow_lite_demo/main.js label index: 258 confidence: 0.8941176470588236 wasmedge-quickjs/$ ``` This is a tensorflow model for animal image classification. Index 258 is labeled **Hot dog** with a confidence of 0.8941176470588236 (max=1.0). # 3. Extend quickjs This part mainly explains how quickjs can be extended. How to deliver what C can achieve with rust. Developers can refer to image_module and tensorflow module to extend, ## How to extend HTTP to quickjs > Core code: wasmedge-quickjs/src/quickjs_sys/http_module.rs This part shows how to write a quickjs module using javascript and rust. ```rust // http_module.rs // This function will add a http module to ctx pub(super) fn init_module_http(ctx: &mut Context) { unsafe { let ctx = ctx.ctx; // The javascript part of http module is used to wrap the code written by rust let init_js = include_str!("../../js_lib/http.js"); // Get globalThis object let global = get_global(ctx); // Generate a new javascript function from http_module::get // And set it to global as http_get attribute // So you can use globalThis['http_get'](...) in javascript // to call the http_module::get function. // This is mainly for js_lib/http.js to use. set(ctx,"http_get",global,new_function(ctx, "http_get", Some(get))); ... // Execute javascript code in ctx let mut val = JS_Eval( ctx, // The javascript code to be executed // here is our package code make_c_string(init_js).as_ptr(), init_js.len(), // filename, which is in the code of the javascript user // import * from'http' 'http' in the end make_c_string("http").as_ptr() as *const i8, // Use Module type to execute, it will generate a module JS_EVAL_TYPE_MODULE as i32, ); // This way, the javascript code executed in the following ctx, // You can import * from'http' to use the http-client function packaged in http_module.rs. // Delete the function we set up earlier from globalThis. // Otherwise, javascript users can also use globalThis['http_get'](...) super::delete(ctx, "http_get", global); super::delete(ctx, "http_get", global); ... // If the execution result of JS_Eval is an exception if JS_IsException_real(val) > 0 { // dump this exception js_std_dump_error(ctx); } // Because js is the gc mechanism of reference counting // We need to free memory in this function // The corresponding function to increase the reference count is JS_DupV JS_FreeValue_real(ctx, val); JS_FreeValue_real(ctx, global); } } unsafe fn parse_response( ctx: *mut JSContext, r: Result<http_req::response::Response, http_req::error::Error>, body: &[u8], ) -> JSValue {...} unsafe fn parse_headers( ctx: *mut JSContext, req: &mut http_req::request::Request, header: JSValue, ) -> Result<(), JSValue> {...} unsafe fn parse_body(ctx: *mut JSContext, body: JSValue) -> Vec<u8> {...} pub extern "C" fn get( ctx: *mut JSContext, this_val: JSValue, argc: ::std::os::raw::c_int, argv: *mut JSValue, ) -> JSValue {...} pub extern "C" fn post( ctx: *mut JSContext, this_val: JSValue, argc: ::std::os::raw::c_int, argv: *mut JSValue, ) -> JSValue {...} pub extern "C" fn put( ctx: *mut JSContext, this_val: JSValue, argc: ::std::os::raw::c_int, argv: *mut JSValue, ) -> JSValue {...} pub extern "C" fn patch( ctx: *mut JSContext, this_val: JSValue, argc: ::std::os::raw::c_int, argv: *mut JSValue, ) -> JSValue {...} pub extern "C" fn delete( ctx: *mut JSContext, this_val: JSValue, argc: ::std::os::raw::c_int, argv: *mut JSValue, ) -> JSValue {...} ``` ## How to extend Tensorflow to quickjs > Core code: wasmedge-quickjs/src/quickjs_sys/tensorflow_module.rs ```rust // tensorflow_module.rs // import wasm host function mod wasmedge_tensorflow {...} pub mod tensorflow {...} pub mod tensorflow_lite { use super::wasmedge_tensorflow::*; use crate::quickjs_sys::*; use std::path::Path; struct TensorflowLiteSession { context: u64, data: Vec<u8>, } impl Drop for TensorflowLiteSession { fn drop(&mut self) { unsafe { wasmedge_tensorflowlite_delete_session(self.context); } } } impl TensorflowLiteSession { pub fn new_from_path<T: AsRef<Path>>(path: T) -> Result<Self, String> {...} pub unsafe fn add_input(&mut self, name: &str, tensor_buf: *const u8, tensor_buf_len: u32) {...} pub unsafe fn run(&mut self) {...} pub unsafe fn get_output(&self, name: &str) -> Vec<u8> {...} } // bind function // Wrap the rust function into the form of javascript native input and output parameters. // Complete the extraction of parameters and the wrapping of return value here unsafe extern "C" fn bind_add_input( ctx: *mut JSContext, this_val: JSValue, argc: ::std::os::raw::c_int, argv: *mut JSValue, ) -> JSValue {...} unsafe extern "C" fn bind_run( ctx: *mut JSContext, this_val: JSValue, argc: ::std::os::raw::c_int, argv: *mut JSValue, ) -> JSValue {...} unsafe extern "C" fn bind_get_output( ctx: *mut JSContext, this_val: JSValue, argc: ::std::os::raw::c_int, argv: *mut JSValue, ) -> JSValue {...} // bind to quickjs // Important function // This function is called when our newly created Class object is gc, that is, when the reference count returns to zero. // We need to free memory in this function unsafe extern "C" fn js_finalizer(rt: *mut JSRuntime, val: JSValue) { // Additional memory data of this object will be obtained, a *void let s = JS_GetOpaque(val, JS_CLASS_ID) as *mut TensorflowLiteSession; if !s.is_null() { // Back to the life cycle of rust and be released. Box::from_raw(s); } } // Important function // This function implements how to convert a rust object to JSValue unsafe fn Session_to_JSValue( ctx: *mut JSContext, session: Box<TensorflowLiteSession>, ) -> JSValue { let obj = JS_NewObjectClass(ctx, JS_CLASS_ID as i32); if JS_IsException_real(obj) > 0 { return obj; } // Important! Leak the memory of rust and escape the life cycle of rust. let ptr_data = Box::leak(session); JS_SetOpaque(obj, (ptr_data as *mut TensorflowLiteSession).cast()); obj } // Important function! // This function will be registered as the constructor of our custom class unsafe extern "C" fn js_ctor( ctx: *mut JSContext, new_target: JSValue, argc: ::std::os::raw::c_int, argv: *mut JSValue, ) -> JSValue { if argv.is_null() || argc == 0 { return js_throw_error(ctx, "argv is empty"); } let param = *argv; let session = if JS_IsString_real(param) > 0 { let path = match to_string(ctx, param) { Ok(path) => path, Err(e) => return js_throw_error(ctx, e), }; let session = match TensorflowLiteSession::new_from_path(path) { Ok(s) => s, Err(e) => return js_throw_error(ctx, e), }; Box::new(session) } else { return js_throw_error(ctx, "param error"); }; return Session_to_JSValue(ctx, session); } // For storing class_id pub static mut JS_CLASS_ID: JSClassID = 0; // For storing class's constructor, majorly used as JS_IsInstanceOf pub static mut JS_CLASS: JSValue = 0; // class definition static mut JS_CLASS_DEF: JSClassDef = JSClassDef { class_name: "TensorflowSession\0".as_ptr() as *const i8, finalizer: Some(js_finalizer), gc_mark: None, call: None, exotic: ::std::ptr::null_mut(), }; // class method list // Defined the class method name the javascript user can see static mut JS_PROTO_FUNCS: [JSCFunctionListEntry; 3] = [ CFUNC_DEF!("add_input\0", bind_add_input, 2), CFUNC_DEF!("run\0", bind_run, 0), CFUNC_DEF!("get_output\0", bind_get_output, 1), ]; // module init unsafe extern "C" fn js_module_init( ctx: *mut JSContext, m: *mut JSModuleDef, ) -> ::std::os::raw::c_int { // Create a class_id in js JS_NewClassID(&mut JS_CLASS_ID); // Bind a JSClassDef to this class_id JS_NewClass(JS_GetRuntime(ctx), JS_CLASS_ID, &JS_CLASS_DEF); let proto = JS_NewObject(ctx); JS_SetPropertyFunctionList( ctx, proto, JS_PROTO_FUNCS.as_ptr(), JS_PROTO_FUNCS.len() as i32, ); // Generate a constructor JS_CLASS = JS_NewCFunction2( ctx, Some(js_ctor), make_c_string("TensorflowLiteSession").as_ptr(), 1, JSCFunctionEnum_JS_CFUNC_constructor, 0, ); // Set up custom constructor of class JS_SetConstructor(ctx, JS_CLASS, proto); // Set up custom proto of class JS_SetClassProto(ctx, JS_CLASS_ID, proto); // Set up export in module // Here, the exported is the constructor exported of Class JS_SetModuleExport( ctx, m, make_c_string("TensorflowLiteSession").as_ptr(), JS_CLASS, ); 0 } // new Module // Create a new JSModule in CTX pub unsafe fn init_module_tensorflow_lite(ctx: *mut JSContext) -> *mut JSModuleDef { let name = make_c_string("tensorflow_lite"); let m = JS_NewCModule(ctx, name.as_ptr(), Some(js_module_init)); if m.is_null() { return m; } JS_AddModuleExport(ctx, m, make_c_string("TensorflowLiteSession").as_ptr()); return m; } } ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully