The post shows how to pass array from javascript to cpp function as parameter and how to use javascript to receive array from cpp function.

We have to know the javascript TypedArray objects and different types of emscripten memory model firstly.

JS TypedArray objects

TypeValue RangeSize in bytesDescriptionWeb IDL typeEquivalent C type
Int8Array-128 to 12718-bit two’s complement signed integerbyteint8_t
Uint8Array0 to 25518-bit unsigned integeroctetuint8_t
Uint8ClampedArray0 to 25518-bit unsigned integer (clamped)octetuint8_t
Int16Array-32768 to 32767216-bit two’s complement signed integershortint16_t
Uint16Array0 to 65535216-bit unsigned integerunsigned shortuint16_t
Int32Array-2147483648 to 2147483647432-bit two’s complement signed integerlongint32_t
Uint32Array0 to 4294967295432-bit unsigned integerunsigned longuint32_t
Float32Array-3.4E38 to 3.4E38 and 1.2E-38 is the min positive number432-bit IEEE floating point number (7 significant digits e.g., 1.234567)unrestricted floatfloat
Float64Array-1.8E308 to 1.8E308 and 5E-324 is the min positive number864-bit IEEE floating point number (16 significant digits e.g., 1.23456789012345)unrestricted doubledouble
BigInt64Array-263 to 263 – 1864-bit two’s complement signed integerbigintint64_t (signed long long)
BigUint64Array0 to 264 – 1864-bit unsigned integerbigintuint64_t (unsigned long long)

Emscripten type accessors for the memory model

TypesMemory
HEAP8View for 8-bit signed memory
HEAP16View for 16-bit signed memory
HEAP32View for 32-bit signed memory
HEAPU8View for 8-bit unsigned memory
HEAPU16View for 16-bit unsigned memory
HEAPU32View for 32-bit unsigned memory
HEAPF32View for 32-bit float memory
HEAPF64View for 64-bit float memory

I create a demo program to test our example, the source code has been uploaded to GitHub, https://github.com/theArcticOcean/tutorials/tree/main/learnWebAssembly/passArrayToCPP.

Html:

<html>
   <head>
      <!-- Load WebAssembly module -->
      <script type="text/javascript" src="build_wasm/passArrayToCPP.js"></script>
   </head>
   <body>
      <div>
         Result: 
         <span id="answer"/>
      </div>
      <button id="showBools">show bools</button><br>
      <button id="intSum">int sum</button><br>
      <button id="doubleSum">double sum</button><br>
      <button id="intArray">int array</button><br>
      <button id="floatArray">float array</button><br>
      <script>
        var worker;
        var Module = {
        onRuntimeInitialized: function () {
            worker = new Module.Worker();
            console.log( worker + " start work!" );
        },
        };

        var app = createModule( Module );
        
        showBools.onclick = function()
        {
            var values = new Int8Array([true, false, false, true, true]);
            var heapSpace = Module._malloc(values.length * values.BYTES_PER_ELEMENT);
            Module.HEAP8.set(values, heapSpace); // bool has 1 byte

            worker.ShowBoolArray( heapSpace, values.length );
        }

        intSum.onclick = function()
        {
            var values = new Int32Array([1, 2, 3, 4, 5]);
            var heapSpace = Module._malloc(values.length * values.BYTES_PER_ELEMENT);
            Module.HEAP32.set(values, heapSpace>>2); // int has 4 bytes

            const result = worker.GetIntSum( heapSpace, values.length );
            console.log( "result " + result );
            document.getElementById("answer").innerHTML = result;
        }

        doubleSum.onclick = function()
        {
            var values = new Float64Array([0.1, 0.2, 0.3, 0.4, 0.5]);
            var heapSpace = Module._malloc(values.length * values.BYTES_PER_ELEMENT);
            Module.HEAPF64.set(values, heapSpace>>3); // double has 8 bytes

            const result = worker.GetDoubleSum( heapSpace, values.length );
            console.log( "result " + result );
            document.getElementById("answer").innerHTML = result;
        }

        intArray.onclick = function()
        {
            var heap = worker.GetIntArray();
            const arrayData = []
            for (let v=0; v < 3; v++) {
               arrayData.push( Module.HEAP32[heap/Int32Array.BYTES_PER_ELEMENT+v] )
            }

            console.log( arrayData );
        }

        floatArray.onclick = function()
        {
            var heap = worker.GetFloatArray( 3 );
            const arrayData = []
            for (let v=0; v < 3; v++) {
               arrayData.push( Module.HEAPF32[heap/Float32Array.BYTES_PER_ELEMENT+v] )
            }

            console.log( arrayData );
        }
      </script>
   </body>
</html>

passArrayToCPP.h

#pragma once

#include <string>

class Worker
{
public:
    Worker();

    int GetIntSum(uintptr_t arrayBuffer, int size);
    double GetDoubleSum(uintptr_t arrayBuffer, int size);
    void ShowBoolArray(uintptr_t arrayBuffer, int size);
    
    uintptr_t GetIntArray();
    uintptr_t GetFloatArray(int size);
};

passArrayToCPP.cpp

#include "passArrayToCPP.h"
#include <iostream>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

int Worker::GetIntSum(uintptr_t arrayBuffer, int size)
{
    std::cout << "GetIntSum start work:" << std::endl;
    auto array = reinterpret_cast<int *>( arrayBuffer );
    int sum = 0;
    for( int i = 0; i < size; ++i )
    {
        sum = sum + array[i];
        std::cout << array[i] << std::endl;
    }
    std::cout << "sum: " << sum << std::endl;
    return sum;
}

double Worker::GetDoubleSum(uintptr_t arrayBuffer, int size)
{
    std::cout << "GetDoubleSum start work:" << std::endl;
    auto array = reinterpret_cast<double *>( arrayBuffer );
    double sum = 0;
    for( int i = 0; i < size; ++i )
    {
        sum = sum + array[i];
        std::cout << array[i] << std::endl;
    }
    std::cout << "sum: " << sum << std::endl;
    return sum;
}

void Worker::ShowBoolArray(uintptr_t arrayBuffer, int size)
{
    auto array = reinterpret_cast<bool *>( arrayBuffer );
    for( int i = 0; i < size; ++i )
    {
        std::cout << "bool: " << array[i] << std::endl;
    }
}

uintptr_t Worker::GetIntArray()
{
    int *values = new int[3];
    values[0] = 1;
    values[1] = 2;
    values[2] = 3;
    return uintptr_t( values );
}

uintptr_t Worker::GetFloatArray(int size)
{
    float values[size];
    for( int i = 0; i < size; ++i )
    {
        values[i] = i*2;
    }

    auto arrayPtr = uintptr_t( &values[0] );
    return arrayPtr;
}

Worker::Worker()
{
    std::cout << "generate Worker!" << std::endl;
}

binding.cpp

#include <emscripten/bind.h>
#include "passArrayToCPP.h"

using namespace emscripten;

EMSCRIPTEN_BINDINGS(worker) {
   class_<Worker>("Worker")
      .constructor()
      .function("GetIntSum", &Worker::GetIntSum)
      .function("GetDoubleSum", &Worker::GetDoubleSum)
      .function("ShowBoolArray", &Worker::ShowBoolArray)
      .function("GetIntArray", &Worker::GetIntArray)
      .function("GetFloatArray", &Worker::GetFloatArray)
      ;
}

Let’s build the project for web page and test it.

cd <project-path>
mkdir build_wasm
cd build_wasm/
emcmake cmake ../
make -j8

Set up a small http server to view.

cd <project-server>
python -m http.server 4000

Test our web page, it seems right.

Categories: Web

0 0 votes
Article Rating
Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
hutzlibu
hutzlibu
1 year ago

Thanks for writing this.
But compiling the example with emscripten 3.1.41 works, but gives me:

Uncaught TypeError: Module._malloc is not a function

in the index.html for “show bools”, “int sum” and “double sum”.
The buttons for “int array” and “float array” work as expected.

hutzlibu
hutzlibu
1 year ago

Found a solution, replacing in index.html:

Module._malloc 

with

Module.asm.malloc

Tex To PDF
: convert the Latex file which suffix is tex to a PDF file

X
3
0
Would love your thoughts, please comment.x
()
x