简体   繁体   English

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

[英]How do I access arrays on the asm.js heap from Javascript code, when the array's type is not Uint8?

I'm trying to use emscripten and asm.js in order to speed up my Javascript code.我正在尝试使用 emscripten 和 asm.js 来加速我的 Javascript 代码。 I need to get data from an Int32Array into my compiled C function.我需要从Int32Array获取数据到我编译的 C 函数中。 According to this Github site I can allocate a buffer, copy data into it, and call a function taking that buffer's pointer as input, like so:根据这个 Github 站点,我可以分配一个缓冲区,将数据复制到其中,并调用一个将该缓冲区的指针作为输入的函数,如下所示:

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

But it doesn't work for anything besides an Uint8Array , because Uint8Array.set "helpfully" converts the input array's data type to Uint8 instead of just doing a raw copy.但它不适用于除Uint8Array之外的任何内容,因为Uint8Array.set “有帮助地”将输入数组的数据类型转换为Uint8而不仅仅是执行原始副本。 In other words, if I try to copy Int32Array.of(1, -1) into the heap at address 100 using this method, I'll get换句话说,如果我尝试使用这种方法将Int32Array.of(1, -1)复制到地址 100 处的堆中,我会得到

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

instead of代替

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

(assuming little endian) (假设小端)

So how am I supposed to copy the data to and from the asm.js heap?那么我应该如何将数据复制到 asm.js 堆或从该堆复制数据? I understand that an ArrayBuffer object can be bitwise-casted to any typed array type, but it doesn't seem possible to do the reverse (correction: see Jaromanda X's comment).我知道ArrayBuffer对象可以按位转换为任何类型的数组类型,但似乎不可能反过来(更正:参见 Jaromanda X 的评论)。 Also, I read, considered, and rejected the website's suggestion to prefer setValue / getValue whenever possible because I have millions of things to copy and I'd like to avoid the overhead of one function call each if at all possible.此外,我阅读、考虑并拒绝了网站关于尽可能使用setValue / getValue的建议,因为我有数百万个东西要复制,如果可能的话,我想避免每个函数调用的开销。

So it turns out I was wrong: it is possible to convert Int32Array to an ArrayBuffer and consequently to an Uint8Array view of the original array.所以事实证明我错了:可以将Int32Array转换为ArrayBuffer ,从而转换为原始数组的Uint8Array视图。 Here's a complete example of a function that sums up an array of int32_t implemented as a JS function passing an array of int32_t to a C function:这是一个函数的完整示例,该函数汇总了一个int32_t数组,该数组实现为一个 JS 函数,将一个int32_t数组传递给一个 C 函数:

sum.c (compiled to sum.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 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM