2017-01-26 59 views
5

Bazı karmaşık dizi hesaplamaları yapmak için WebAssembly'ı test etmek istiyorum.WebAssembly işlevine bir argüman olarak bir JavaScript dizisi geçirme

// hello.cpp 
extern "C" { 

void array_add(int * summed, int* a, int* b) { 
    for (int i=0; i < 3; i++) { 
    summed[i] = a[i] + b[i]; 
    } 
} 

} 

Ve bu derlenmiş: diğerleri arasında üretir

emcc hello.cpp -s WASM=1 -s "MODULARIZE=1" -s "EXPORT_NAME='HELLO'" -s "BINARYEN_METHOD='native-wasm'" -s "EXPORTED_FUNCTIONS=['_array_add']" -o build/hello.js

, bir js

Yani 3 unsurları her içeren iki int dizileri eklenmesi basit C++ işlevini yazdım ve bir wasm dosyası. Aşağıdaki html sayfası ile bu yük:

<!doctype html> 
<html lang="en-us"> 
    <head> 
    <meta charset="utf-8"> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    <script type="text/javascript" src="build/hello.js"></script> 
    <script type="text/javascript"> 
     function reqListener() { 
     // Loading wasm module 
     var arrayBuffer = oReq.response 
     HELLO['wasmBinary'] = arrayBuffer 
     hello = HELLO({ wasmBinary: HELLO.wasmBinary }) 

     // Calling function 
     var result = new Int32Array(3) 
     var a = new Int32Array([1, 2, 3]) 
     var b = new Int32Array([4, 5, 2]) 
     hello._array_add(result, a, b) 
     console.log('result', result) 
     } 

     var oReq = new XMLHttpRequest(); 
     oReq.responseType = "arraybuffer"; 
     oReq.addEventListener("load", reqListener); 
     oReq.open("GET", "build/hello.wasm"); 
     oReq.send(); 
    </script> 
    </head> 
    <body> 

    </body> 
</html> 

Ama her nasılsa, result dizisi hep [0, 0, 0] olduğunu.

ccall() (bkz. emscripten docs) işlevini çağırmak da dahil olmak üzere çeşitli şeyleri denedim ve öyle görünüyor ki, benim wasm compiled işlevinin argümanı olarak bir dizi iletilemiyor. Aşağıdaki C++ fonksiyonlu Örneğin

: JavaScript olarak adlandırılan

extern "C" { 

int first(int * arr) { 
    return arr[0]; 
} 

} 

Sonuç bunun yerine değişken olarak geçirilen bir dizi beklenen değer, rastgele ish tamsayıdır.

Neyi eksik?

NB: Bu benim C++ cehalet ile ilgili bir acemi soru olup olmadığını

cevap

7

Sorunuz this one çok benzer ..., bu nedenle tüm özür C++ hakkında hemen hemen hiçbir şey bilmiyor: WebAssembly sadece destekler i32/Saklama için i64/f32/f64value types ve i8/i16.

Bu, işaretçilerden geçemeyeceğiniz anlamına gelir. Yaptığınız şey, C++ bakış açısıyla geldiğinizde tamamen saçmadır (cehalet için özür dilemeye gerek yok!), Ancak WebAssembly'ın sınırlarının işleyiş şekli değil. Bu da C++ uzmanlarına şaşırtıcı. dize söz konusu olduğu gibi

ihtiyacınız için ya:

  • Kopya kez bir ihracat arayarak bir defada birinde dizi girişi başına (örneğin set(size_t index, int value) gibi).
  • WebAssembly örneğinizin yığınını bir JavaScript olarak ArrayBuffer olarak açın ve istediğiniz değerleri ArrayBuffer'a doğrudan yazın.

Benim diğer yanıtında önerilen aynı kodla ikincisi yapabilirsiniz: "ama nasıl işaretçiler çalışır?": Muhtemelen merak ediyorsanız ++

const bin = ...; // WebAssembly binary, I assume below that it imports a memory from module "imports", field "memory". 
const module = new WebAssembly.Module(bin); 
const memory = new WebAssembly.Memory({ initial: 2 }); // Size is in pages. 
const instance = new WebAssembly.Instance(module, { imports: { memory: memory } }); 
const arrayBuffer = memory.buffer; 
const buffer = new Uint8Array(arrayBuffer); 

C'den geliyor. Yukarıdaki WebAssembly ↔ JavaScript'i etrafında işaretçileri geçemeyeceğinizi açıklarım!Inside WebAssembly işaretçileri basit i32 değerleri olarak temsil edilir. Empscripten bunu yapmak için LLVM'ye dayanır ve WebAssembly kendisini 4GiB maksimum yığın boyutuyla birlikte ILP32 olarak sunar.

Dolaylı işlev çağrıları ve işlev göstergeleri için ilginç etkileri var! Bunu başka bir soru için bırakacağım ;-)

Ancak bu, JavaScript'in WebAssembly için işaretçiler hakkında "konuşabileceği" anlamına gelir: i32, i32. Eğer bir değerin yığın içinde bir yerde olduğunu biliyorsanız, o zaman o i32'u JavaScript'e aktarabilir ve JavaScript bunu değiştirebilir ve WebAssembly'a geri gönderebilir. JavaScript yığın en ArrayBuffer erişimi varsa o zaman bir i32 sahip ++ nerede yığın şeyler olduğunu biliyorum ve C yaptığınız gibi yığın değiştirmenize olanak tanır.

WebAssembly yığını çoğu C++ yığınından farklı olsa da: çalıştırılabilir sayfalara erişimi yoktur veya çağrı yığınına erişimi yoktur (ya da daha çok çağrı yığınının çoğu: LLVM gibi derleyiciler olabilir " "bazı adres alınan değerleri WebAssembly'ın yerlilerini kullanmak yerine yığına dökmek". Bu, Harvard mimarilerinin (von Neumann'ın aksine) yaptığı şeydir.


hello._array_add(result, a, b) ne yapıyor? a ve b kodlarını ToInteger kullanarak dizilerden zorlama. Bu, WebAssembly içinde geçerli bir yığın yeri olan 0 olur! Yığının çok beklenmeyen bir kısmına erişiyorsun! Diğer benzer sorulara

3

Çok teşekkürler:

Pass array to C function with emscripten

How to handle passing/returning array pointers to emscripten compiled code?

Ve API dosyaları:

https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#getValue

ben bunu çözmüş olmasının.

#include <stdint.h> 

extern "C" { 

int* copy_array(int* in_array, int length) { 
    int out_array[length]; 
    for (int i=0; i<length; i++) { 
    out_array[i] = in_array[i]; 
    } 
    return out_array; 
} 

} 

böyle derlemek olabilir: wasm işlevin bir dizi geçmesine nasıl örneklendirir.Personel için/geri dizisini almak, C++ basit dizi kopyasını uygulamış

emcc wasm_dsp.cpp -s WASM=1 -s "MODULARIZE=1" -s "EXPORT_NAME='WasmDsp'" -s "BINARYEN_METHOD='native-wasm'" -s "EXPORTED_FUNCTIONS=['_copy_array']" -o build/wasm_dsp.js

Ve böyle tarayıcıda çalıştırın:

<!doctype html> 
<html lang="en-us"> 
    <head> 
    <meta charset="utf-8"> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    <script type="text/javascript" src="build/wasm_dsp.js"></script> 
    <script type="text/javascript"> 
     function reqListener() { 
     // Loading wasm module 
     var arrayBuffer = oReq.response 
     WasmDsp['wasmBinary'] = arrayBuffer 
     wasmDsp = WasmDsp({ wasmBinary: WasmDsp.wasmBinary }) 

     var inArray = new Int32Array([22, 44, 66, 999]) 
     var nByte = 4 
     copyArray = wasmDsp.cwrap('copy_array', null, ['number', 'number']); 

     // Takes an Int32Array, copies it to the heap and returns a pointer 
     function arrayToPtr(array) { 
      var ptr = wasmDsp._malloc(array.length * nByte) 
      wasmDsp.HEAP32.set(array, ptr/nByte) 
      return ptr 
     } 

     // Takes a pointer and array length, and returns a Int32Array from the heap 
     function ptrToArray(ptr, length) { 
      var array = new Int32Array(length) 
      var pos = ptr/nByte 
      array.set(wasmDsp.HEAP32.subarray(pos, pos + length)) 
      return array 
     } 

     var copiedArray = ptrToArray(
      copyArray(arrayToPtr(inArray), inArray.length) 
     , inArray.length) 

     console.log(copiedArray) 
     } 

     var oReq = new XMLHttpRequest(); 
     oReq.responseType = "arraybuffer"; 
     oReq.addEventListener("load", reqListener); 
     oReq.open("GET", "build/wasm_dsp.wasm"); 
     oReq.send(); 
    </script> 
    </head> 
    <body> 

    </body> 
</html> 

Not burada arrayToPtr ve ptrToArray fonksiyonlar ... yaptıklarını olanlar dizi geçirme/döndürme işi.

İlgili konular