におけるメモリモデル


JavaScriptを実行するには、JavaScriptエンジンがリソースをダウンロードする必要があります.JavaScriptエンジンはリソースがダウンロードされるまで待ちます.ダウンロードしたら、JavaScriptエンジンを解析します.パーサーは、ソースコードをJavaScriptインタプリタが実行するバイトコードに変換します.
関数が複数回呼び出されるとき.The baseline compiler ( V 8で)コードをコンパイルします.コンパイルはメインスレッドで行われます.コンパイラはコンパイル時に時間を費やします.しかし、コンパイルされたコードは解釈されたコードより速く動きます.コンパイルされたコードはoptimising compiler .
関数をもっとたくさん呼び出すとき.コンパイラは関数をマークし、さらに最適化を試みます.この間re-optimisation , コンパイラは想定し、さらに最適化されたコードを生成します.この最適化は少し時間がかかりますが、生成されたコードははるかに高速です.
この関数は実行されます.最後に、コードはガベージコレクションです.

WebAssembly is fast. 🚀


Javascriptエンジンは、webassemblyモジュールをダウンロードします.ダウンロードしたらwebassemblyモジュールをデコードします.

Decoding is faster than parsing.


デコードされると、webassemblyモジュールがコンパイルされ、最適化されます.モジュールが既にコンパイルされて、最適化されているので、このステップは高速です.
モジュールが最終的に実行されます.

Note: there is no separate garbage collection step. The WebAssembly module takes care of allocating and de-allocating the memory.


さびとwebassemblyの上で私の本をチェックしてくださいhere
webassembly実行を高速化する探索では、ブラウザのベンダーがストリーミングコンパイルを実装しました.webasemblyモジュールがまだダウンロード中の間、ストリーミングコンパイルはJavaScriptエンジンがモジュールをコンパイルして、最適化するのを可能にします.ファイルが完全にダウンロードされるまで、エンジンが待つべきJavaScriptと異なります.これはプロセスを高速化します.
JavaScriptとwebassemblyはブラウザレベルで2つの異なるものです.Javascriptまたはその逆のwebassemblyを呼び出すのは遅いです.(これはどんな2つの言語の間の呼び出しにも良いです).これは交差点の境界にコストがかかるためです.
ブラウザベンダー(特にFirefox)は、境界交差点のコストを削減しようとしています.実際には、Firefoxでは、JavascriptがWebassembly呼び出しをするのは、JavaScriptからJavaScriptまでの呼び出しに比べてずっと高速です.
しかし、アプリケーションを設計している間、適切な注意は境界交差点に与えられなければなりません.それらはアプリケーションの主要なパフォーマンスボトルネックになります.この場合、webassemblyモジュールのメモリモデルを理解することが重要です.

におけるメモリモデル


The memory section webassemblyモジュールの線形メモリのベクトルです.

線形記憶モデル


A linear memory model is a memory addressing technique in which the memory is organized in a single contagious address space. It is also known as Flat memory model.


線形メモリモデルは、メモリを理解し、プログラムし、表現することを容易にする.
彼らは巨大な欠点がある
  • 要素の再配置のための高い実行時間
  • 多くの記憶領域を浪費する

  • メモリは解釈されていないデータの生のバイトのベクトルである.メモリの生のバイトを保持するために、変更可能な配列バッファを使用します.JavaScriptとweBassemblyは、メモリに対して同期的に読み書きできます.
    メモリを割り当てることができますWebAssembly.memory() コンストラクタです.

    コードを書く✍️


    webassemblyからJavaScriptへ


    webassemblyモジュール(Rustで書かれた)からJavaScriptにメモリを通して値を渡す方法を最初に見ましょう.
    新しいプロジェクトを作成するcargo .
    $ cargo new --lib memory_world
    
    プロジェクトが正常に作成されたら.お気に入りのエディタでプロジェクトを開きます.編集しましょうsrc/lib.rs 下記の内容で
    #![no_std]
    
    use core::panic::PanicInfo;
    use core::slice::from_raw_parts_mut;
    
    #[no_mangle]
    fn memory_to_js() {
        let obj: &mut [u8];
    
        unsafe {
            obj = from_raw_parts_mut::<u8>(0 as *mut u8, 1);
        }
    
        obj[0] = 13;
    }
    
    #[panic_handler]
    fn panic(_info: &PanicInfo) -> !{
        loop{}
    }
    
    これを加えるCargo.toml :
    [lib]
    crate-type = ["cdylib"]
    

    何がある?


    さびファイルは#![no_std] . The #![no_std] 属性はstd - crateの代わりに錆コンパイラをコアcrateに戻すように指示します.コア木箱はプラットフォーム不機嫌です.コアのcrateはstd crateの小さなサブセットです.これにより、バイナリサイズが劇的に減少します.
    機能memory_to_js に注釈付き#[no_mangle] . この関数は、共有メモリ内の値を変更するため、値を返しません.
    タイプの可変スライスを定義しますu8 and name it as obj . それから私たちはfrom_raw_parts_mut 作成するu8 ポインタと長さの使用.デフォルトでは0 我々はちょうど取る1 要素.
    私たちは生のメモリにアクセスしているので、呼び出しをunsafe ブロック.生成されたスライスfrom_raw_parts_mut 変更可能です.
    最後に、我々は13 最初のインデックスで.
    unsafe {
        obj = from_raw_parts_mut::<u8>(0 as *mut u8, 1);
    }
    
    obj[0] = 13;
    
    また、apanic_handler 任意のパニックをキャプチャし、今のところそれを無視する(あなたの生産アプリケーションでこれをしないでください).

    Note that we are not using wasm_bindgen here.


    JavaScriptでは、webassemblyモジュールを読み込み、モジュールからまっすぐアクセスします.
    まず、webassemblyモジュールを取得し、インスタンス化します.
    const bytes = await fetch("target/wasm32-unknown-unknown/debug/memory_world.wasm");
    const response = await bytes.arrayBuffer();
    const result = await WebAssembly.instantiate(response, {});
    
    結果オブジェクトは、すべてのインポートされエクスポートされた関数を含むWebBassemblyオブジェクトです.エクスポートするmemory_to_js 関数からresult.exports .
    result.exports.memory_to_js();
    
    この関数はwebassembly modulememory_to_js 関数を共有し、共有メモリに値を代入する.
    共有メモリはresult.exports.memory.buffer オブジェクト.
    const memObj = new UInt8Array(result.exports.memory.buffer, 0).slice(0, 1);
    console.log(memObj[0]); // 13
    
    メモリはload and store バイナリ命令.これらのバイナリ命令はoffsetalignment . The alignment ベース2対数表現です.

    Note: WebAssembly currently provides only 32-bit address ranges. In future, WebAssembly may provide 64-bit address range.


    JavaScriptからwebassemblyへ


    私たちは、JavaScriptとwebassemblyの間でメモリを共有する方法を見ました.今はJavaScriptのメモリを作成し、錆の中でそれを使用する時間です.
    JavaScriptランド内のメモリには、WebBassembly Landを割り当てる方法がありません.型として、webassembly明示的な型情報を期待します.webassembly landにどのようにメモリを割り当て、どのように解放するかを伝える必要があります.
    JavaScript経由でメモリを作成するには、WebAssembly.Memory() コンストラクタ.
    メモリコンストラクターは、オブジェクトを既定値を設定します.それらは
  • 初期-メモリの初期サイズ
  • max -メモリの最大サイズ(任意)
  • shared -共有メモリを使用するかどうかを示す
  • 初期および最大の単位は( webassembly )ページです.各ページは64 KBまで保持します.

    コードを書く✍️


    メモリを初期化します.
    const memory = new WebAssembly.Memory({initial: 10, maximum: 100});
    
    メモリは初期化されるWebAssembly.Memory() 初期値のコンストラクタ10 pages と最大値100 pages . これはそれぞれ640 KBと6.4 MBの初期値と最大値に変換されます.
    const bytes = await fetch("target/wasm32-unknown-unknown/debug/memory_world.wasm");
    const response = await bytes.arrayBuffer();
    const instance = await WebAssembly.instantiate(response, { js: { mem: memory } });
    
    webassemblyモジュールを取得し、インスタンス化します.しかし、インスタンス化する間、我々はメモリオブジェクトを通過します.
    const s = new Set([1, 2, 3]);
    let jsArr = Uint8Array.from(s);
    
    私たちはtypedArray ( UInt8Array ) 値1、2、3で.
    const len = jsArr.length;
    let wasmArrPtr = instance.exports.malloc(length);
    
    webassemblyモジュールには、メモリに作成されたオブジェクトのサイズについての手がかりがありません.webassemblyメモリを割り当てる必要があります.メモリの割り当てと解放を手動で書く必要があります.このステップでは、配列の長さを送信し、そのメモリを割り当てます.これはメモリの位置へのポインタを与える.
    let wasmArr = new Uint8Array(instance.exports.memory.buffer, wasmArrPtr, len);
    
    それから、バッファ(合計利用可能なメモリ)、メモリオフセット(wasmattrptr)、およびメモリの長さを持つ新しいtypedarrayを作成します.
    wasmArr.set(jsArr);
    
    最後に、ローカルに作成されたtypedarrayを設定します.jsArr ) を返します.wasmArrPtr .
    const sum = instance.exports.accumulate(wasmArrPtr, len); // -> 7
    console.log(sum);
    
    私たちはpointerlength を追加します.webassemblyモジュールでは、メモリから値を取得して使用します.
    錆でmalloc and accumulate 関数は以下の通りである.
    use std::alloc::{alloc, dealloc,  Layout};
    use std::mem;
    
    #[no_mangle]
    fn malloc(size: usize) -> *mut u8 {
        let align = std::mem::align_of::<usize>();
        if let Ok(layout) = Layout::from_size_align(size, align) {
            unsafe {
                if layout.size() > 0 {
                    let ptr = alloc(layout);
                    if !ptr.is_null() {
                        return ptr
                    }
                } else {
                    return align as *mut u8
                }
            }
        }
        std::process::abort
    }
    
    サイズを考えると、malloc関数はメモリブロックを割り当てます.
    #[no_mangle]
    fn accumulate(data: *mut u8, len: usize) -> i32 {
        let y = unsafe { std::slice::from_raw_parts(data as *const u8, len) };
        let mut sum = 0;
        for i in 0..len {
            sum = sum + y[i];
        }
        sum as i32
    }
    

    累積関数は共有配列とサイズ( len )を取ります。そして、共有メモリからデータを復元する。その後、データを実行し、データ内のすべての要素の合計を返します。


    あなたがポストを楽しんだならば、あなたはさびとwebassemblyの上で私の本が好きかもしれません.チェックアウトhere
    👇 レポ👇

    センディルマル / Rustwasmメモリモデル


    WebBassemblyとJavaScriptの間でメモリを共有する


    探検する興味


    Javascript APIを使用したwebassembly memoryhere
    webassemblyのメモリアクセスはhere
    もっとチェックfrom_raw_parts_mut アットhere
    TypedArrayについてのチェックhere
    //💻 GitHub // ✍️ Blog // 🔶 hackernews
    閉じるこの動画はお気に入りから削除されています.❤️