2017-01-26 7 views
5

पर तर्क के रूप में पास करें, मैं कुछ जटिल सरणी गणनाओं के लिए WebAssembly का परीक्षण करना चाहता हूं।एक जावास्क्रिप्ट सरणी को WebAssembly फ़ंक्शन

// 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]; 
    } 
} 

} 

और के साथ इस संकलित:

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

कौन सा दूसरों के बीच उत्पन्न करता है, एक js

तो मैं एक साधारण सी ++ समारोह 3 तत्वों से युक्त दो int सरणियों जोड़ने लिखा है और wasm फ़ाइल। मैं निम्नलिखित html पृष्ठ के साथ इन लोड:

<!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> 

लेकिन किसी भी तरह, result सरणी हमेशा [0, 0, 0] है।

मैं (emscripten docs देखें) ccall() साथ फ़ंक्शन को कॉल और ऐसा लगता है कि मैं एक सरणी मेरी Wasm संकलित समारोह के तर्क के रूप में पारित नहीं प्राप्त कर सकते हैं सहित चीजों की एक किस्म की कोशिश की है।

उदाहरण के लिए, निम्नलिखित सी ++ समारोह के साथ:

extern "C" { 

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

} 

परिणाम जब जावास्क्रिप्ट में बुलाया सरणी मैं तर्क के रूप में पारित कर दिया से उम्मीद मान की बजाय एक यादृच्छिक-ish पूर्णांक है।

मुझे क्या याद आ रही है?

नायब: मैं सी के बारे में ++ काफी कुछ भी नहीं पता है, इसलिए सभी क्षमा याचना अगर यह अभी शुरुआत मेरी सी ++ अज्ञान से संबंधित सवाल यह है कि ...

उत्तर

7

आपका प्रश्न बहुत this one के समान है: WebAssembly केवल समर्थन करता है, i32/भंडारण के लिए i64/f32/f64value types साथ ही साथ i8/i16

इसका मतलब है कि आप पॉइंटर्स में पास नहीं कर सकते हैं। जब आप सी ++ बिंदु से आ रहे हैं (अज्ञानता के लिए माफ़ी मांगने की ज़रूरत नहीं है), तो आप जो कर रहे हैं वह पूरी तरह से सचेत है, लेकिन यह नहीं है कि WebAssembly की सीमा कैसे काम करती है। सी ++ विशेषज्ञों के लिए भी यह आश्चर्यजनक है।

स्ट्रिंग प्रश्न में के रूप में, आप की जरूरत करने के लिए या तो:

  • कॉपी एक बार एक निर्यात को फोन करके एक समय में एक में सरणी प्रविष्टि प्रति (जैसे set(size_t index, int value) के रूप में)।
  • जावास्क्रिप्ट में ArrayBuffer के रूप में अपने WebAssembly इंस्टेंस के ढेर का पर्दाफाश करें, और सीधे ArrayBuffer में इच्छित मानों को लिखें।

आप एक ही कोड मैं अन्य जवाब में प्रस्तावित के साथ बाद कर सकते हैं:

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); 

सी से आ ++ आप शायद सोच रहे हैं: "लेकिन कैसे संकेत काम करते हैं?"। ऊपर मैं समझाता हूं कि WebAssembly ↔ जावास्क्रिप्ट आप पॉइंटर्स को पास नहीं कर सकते!WebAssembly पॉइंटर्स के अंदर सरल i32 मानों के रूप में दर्शाए जाते हैं। Empscripten ऐसा करने के लिए एलएलवीएम पर निर्भर करता है, और चूंकि WebAssembly स्वयं को 4 जीआईबी अधिकतम ढेर आकार के साथ आईएलपी 32 के रूप में प्रस्तुत करता है, यह जस्ट वर्क्स।

अप्रत्यक्ष फ़ंक्शन कॉल और फ़ंक्शन पॉइंटर्स के लिए इसमें दिलचस्प प्रभाव पड़ता है! मैं एक और सवाल ;-)

के लिए कि छोड़ देंगे हालांकि यह मतलब है कि जावास्क्रिप्ट WebAssembly को "बात" कर सकते हैं संकेत के बारे में: एक i32 एक i32 है। यदि आपको पता है कि एक मूल्य ढेर में कहीं है तो आप जावास्क्रिप्ट पर i32 पास कर सकते हैं, और जावास्क्रिप्ट इसे संशोधित कर सकता है और उसे वेबएस्क्रिप्ट में वापस भेज सकता है। यदि जावास्क्रिप्ट में ढेर के ArrayBuffer तक पहुंच है तो i32 होने से आपको पता चलेगा कि ढेर में कहां हैं, और सी ++ से ढेर को संशोधित करें।

वेबसाइस्प्लर्स ढेर अधिकांश सी ++ ढेर से अलग है हालांकि: इसमें निष्पादन योग्य पृष्ठों तक पहुंच नहीं है, न ही इसे कॉल स्टैक तक पहुंच है (या इसके बजाय, अधिकांश कॉल स्टैक: एलएलवीएम जैसे कंपाइलर्स " WebAssembly के स्थानीय लोगों का उपयोग करने के बजाय ढेर में कुछ पता-ले जाने वाले मानों को स्पिल करें)। यह मूल रूप से हार्वर्ड आर्किटेक्चर करता है (वॉन न्यूमैन के विपरीत)।


तो क्या आपके hello._array_add(result, a, b) कर रही है? ToInteger का उपयोग कर a और b को सरणी से समन्वयित करना। यह 0 बन जाता है, जो WebAssembly में एक मान्य ढेर स्थान है! आप अपने ढेर के बहुत अप्रत्याशित हिस्से तक पहुंच रहे हैं!

3

तो अन्य इसी तरह के सवाल करने के लिए धन्यवाद:

Pass array to C function with emscripten

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

और एपीआई डॉक्स:

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

मैं यह पता लगा है।

#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; 
} 

} 

जो तुम इस तरह संकलन कर सकते हैं:: कैसे Wasm कार्य करने के लिए एक सरणी पारित करने के लिए examplify करने के लिए/एक सरणी वापस पाने, मैं C++ एक सरल सरणी प्रतिलिपि को लागू किया है

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

और इस तरह ब्राउज़र में चलाएँ:

<!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> 

नोट यहाँ arrayToPtr और ptrToArray कार्यों ... वे क्या कर रही हैं उत्तीर्ण/वापसी सरणी का काम।

संबंधित मुद्दे