Assemblyscript: Fastest way to get a Int32Array from JavaScript into i32[]?

Created on 15 Nov 2019  路  9Comments  路  Source: AssemblyScript/assemblyscript

I'm passing in a pointer to a Int32Array from JavaScript and using it in my AssemblyScript. The i32[] type has a lot of convenience methods that are helpful, so I am converting it in the AssemblyScript code. I am wondering if there is a faster/more convenient way to do that than:

export function Int32ArrayToi32Array(originalArray: Int32Array): i32[] {

  let i32Array: i32[] = [];
  for (let i = 0; i < originalArray.length; i++) {
    i32Array[i] = originalArray[i];
  }

  // i32Array has .forEach, .indexOf, .join etc

  return i32Array;

}

Also if there is a faster way to do the inverse of this that would be useful to know too. Thanks in advance!

question stale

Most helpful comment

Looks correct, yeah. Didn't consider zeroing out, so this should be even faster. Looks like providing Array/TypedArray.from (with just array for now) could help to make this easier.

All 9 comments

The fastest way might be to make an Array<i32> right away on the JS side, so all there is to it is passing the reference around. For example:

// wasm
export const I32ARRAY_ID = idof<i32[]>();
export function takesArray(arr: i32[]): void {
  ...
}
// js with the loader
var ptr = module.__retain(module.__allocArray(module.I32ARRAY_ID, [ ... ]));
module.takesArray(ptr);
module.__release(ptr);

Other than that it seems like your approach is the safest way to do it, with everything else going into unsafe territory of setting up the object manually and memory.copying the buffer.

The faster way of copying I mentioned, if absolutely necessary, would be something along the lines of:

export function Int32ArrayToi32Array(originalArray: Int32Array): i32[] {
  let i32Array = new Array<i32>(originalArray.length);
  memory.copy(changetype<usize>(i32Array.buffer), changetype<usize>(originalArray.buffer), <usize>originalArray.length << 2);
  return i32Array;
}

Works in both directions.

@dcodeIO This is probably what I would do, only because new Array() would return zeroed out data right? Not sure this is _technically_ faster, but it's what I would personally write.

export function convert<T extends ArrayBufferView>(input: T): valueof<T>[] {
  let byteLength = input.byteLength;
  let length = input.length;
  let output = __alloc(offsetof<valueof<T>[]>(), idof<valueof<T>[]>());
  let buffer = __alloc(byteLength, idof<ArrayBuffer>());
  store<i32>(output, length, offsetof<valueof<T>[]>("length_"));
  store<usize>(output, __retain(buffer), offsetof<valueof<T>[]>("buffer"));
  store<usize>(output, buffer, offsetof<valueof<T>[]>("dataStart"));
  store<i32>(output, byteLength, offsetof<valueof<T>[]>("byteLength"));
  memory.copy(
    output,
    input.dataStart,
    byteLength,
  );

  if (isManaged<valueof<T>>()) {
    for (let i = 0; i < length; i++) {
      __retain(load<usize>(buffer + (<usize>i << alignof<usize>())));
    }
  }

  return changetype<valueof<T>[]>(output);
}

Looks correct, yeah. Didn't consider zeroing out, so this should be even faster. Looks like providing Array/TypedArray.from (with just array for now) could help to make this easier.

The fastest way always pass typed arrays between JS and AS and using loader's utils like __getUint32Array, __getFloat64Array and etc. If you need Array<i32> internally for dynamic purposes or when you don't know final size of result buffer you could create Array<i32> process it and later copy it to Int32Array via memory.copy and return from exported function. That's will be fastest I guess. When you know size and don't grow array always use typed array instead dynamic array

An Array<i32> isn't so different from an Int32Array in its layout, so with an Array<i32> internally, it should also be possible to use __getInt32Array on that (didn't test). The difference is mostly that Array<i32> can grow its memory, which must be taken care of, and has an additional mutable .length property.

Hmm, yeah __getInt32Array could work for Array<i32> but need tests

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Sorry I never replied this. The @dcodeIO had the best approach for my specific issue was to create a i32 array directly on the JavaScript side. The other suggestions were also great for gaining a broader understanding of solutions to the problem, so thank you for that!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MaxGraey picture MaxGraey  路  3Comments

MaxGraey picture MaxGraey  路  4Comments

andy-hanson picture andy-hanson  路  4Comments

DanielMazurkiewicz picture DanielMazurkiewicz  路  4Comments

torch2424 picture torch2424  路  5Comments