当数组的类型不是Uint8时,如何从Javascript代码访问asm.js堆上的数组?

时间:2017-10-20 04:52:44

标签: javascript arrays asm.js

我正在尝试使用emscripten和asm.js来加速我的Javascript代码。我需要从Int32Array获取数据到我编译的C函数中。根据{{​​3}},我可以分配缓冲区,将数据复制到其中,并调用一个函数将该缓冲区的指针作为输入,如下所示:

var buf = Module._malloc(myTypedArray.length*myTypedArray.BYTES_PER_ELEMENT);
Module.HEAPU8.set(myTypedArray, buf);
Module.ccall('my_function', 'number', ['number'], [buf]);
Module._free(buf);

但它不适用于除Uint8Array之外的任何内容,因为Uint8Array.set“帮助”将输入数组的数据类型转换为Uint8,而不仅仅是执行原始副本。换句话说,如果我尝试使用此方法将Int32Array.of(1, -1)复制到地址100的堆中,我将会得到

{ ... 100:1, 101:255, 102:0, 103:0, 104:0, 105:0, 106:0, 107:0 ... }

而不是

{ ... 100:1, 101:0, 102:0, 103:0, 104:255, 105:255, 106:255, 107:255 ... }

(假设小端)

那么我应该如何将数据复制到asm.js堆中?我知道ArrayBuffer对象可以按位转换为任何类型的数组类型,但似乎不可能执行反向(更正:请参阅Jaromanda X的注释)。此外,我阅读,考虑并拒绝了网站的建议,尽可能选择setValue / getValue,因为我有数百万的东西要复制,我想避免每个函数调用的开销。尽可能。

1 个答案:

答案 0 :(得分:1)

事实证明我错了:可以将Int32Array转换为ArrayBuffer,从而转换为原始数组的Uint8Array视图。这是一个函数的完整示例,它总结了一个int32_t数组,实现为将int32_t数组传递给C函数的JS函数:

sum.c(编译为sum.c.js)

#include <stdint.h>
#include <stddef.h>

double sum_i32(const int32_t* ints, size_t count) {
    double result = 0.0;
    while (count-- > 0) {
        result += *ints++;
    }
    return result;
}

sum.js

"use strict";

const cModule = require("./sum.c.js");

module.exports.sum_i32 = function sum_i32(array) {
    // Convert to array of int32_t if needed.
    if (!(array instanceof Int32Array)) {
        array = new Int32Array(array);
    }
    // Allocate a buffer to store a copy of the input array.
    const ptr = cModule._malloc(array.length * 4);
    let result = NaN;
    if (ptr === 0) {
        throw "Out of memory";
    }
    try {
        // View int32_t array as uint8_t using the int array's ArrayBuffer.
        const u8view = new Uint8Array(array.buffer);
        // Copy it to the right position in the heap and call the C function.
        cModule.HEAPU8.set(u8view, ptr);
        result = cModule._sum_i32(ptr, array.length);
    } finally {
        cModule._free(ptr);
    }
    return result;
}