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

Type Value Range Size in bytes Description Web IDL type Equivalent C type
Int8Array -128 to 127 1 8-bit two’s complement signed integer byte int8_t
Uint8Array 0 to 255 1 8-bit unsigned integer octet uint8_t
Uint8ClampedArray 0 to 255 1 8-bit unsigned integer (clamped) octet uint8_t
Int16Array -32768 to 32767 2 16-bit two’s complement signed integer short int16_t
Uint16Array 0 to 65535 2 16-bit unsigned integer unsigned short uint16_t
Int32Array -2147483648 to 2147483647 4 32-bit two’s complement signed integer long int32_t
Uint32Array 0 to 4294967295 4 32-bit unsigned integer unsigned long uint32_t
Float32Array -3.4E38 to 3.4E38 and 1.2E-38 is the min positive number 4 32-bit IEEE floating point number (7 significant digits e.g., 1.234567) unrestricted float float
Float64Array -1.8E308 to 1.8E308 and 5E-324 is the min positive number 8 64-bit IEEE floating point number (16 significant digits e.g., 1.23456789012345) unrestricted double double
BigInt64Array -263 to 263 – 1 8 64-bit two’s complement signed integer bigint int64_t (signed long long)
BigUint64Array 0 to 264 – 1 8 64-bit unsigned integer bigint uint64_t (unsigned long long)

Emscripten type accessors for the memory model

Types Memory
HEAP8 View for 8-bit signed memory
HEAP16 View for 16-bit signed memory
HEAP32 View for 32-bit signed memory
HEAPU8 View for 8-bit unsigned memory
HEAPU16 View for 16-bit unsigned memory
HEAPU32 View for 32-bit unsigned memory
HEAPF32 View for 32-bit float memory
HEAPF64 View 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