# Arrays example

Shows how to exchange and work with arrays either created in WebAssembly or in JavaScript.

# Contents

  • Using the loader and the full runtime to work with managed objects.
  • Creating arrays in WebAssembly and using them in JavaScript.
  • Creating arrays in JavaScript and using them in WebAssembly.
  • Using both copies of and live views on arrays.
  • Performing unchecked accesses where the length of an array is known.
  • Pinning objects externally to prevent premature garbage collection.

# Example

#!optimize=speed&runtime=default&exportRuntime
/** Creates a new array and returns it to JavaScript. */
export function createArray(length: i32): Int32Array {
  return new Int32Array(length)
}

/** Randomizes the specified array's values. */
export function randomizeArray(arr: Int32Array): void {
  for (let i = 0, k = arr.length; i < k; ++i) {
    let value = i32((Math.random() * 2.0 - 1.0) * i32.MAX_VALUE)
    unchecked(arr[i] = value)
  }
}

/** Computes the sum of an array's values and returns the sum to JavaScript. */
export function sumArray(arr: Int32Array): i32 {
  let total = 0
  for (let i = 0, k = arr.length; i < k; ++i) {
    total += unchecked(arr[i])
  }
  return total
}

// We'll need the unique Int32Array id when allocating one in JavaScript
export const Int32Array_ID = idof<Int32Array>()

#!html
<textarea id="output" style="width: 100%; height: 100%" readonly></textarea>
<script>
loader.instantiate(module_wasm).then(({ exports }) => {
  const output = document.getElementById('output')

  /** Logs a message to the textarea. */
  function log(message = '') {
    output.value += `${message}\n`
  }

  // A simple example using an array created in WebAssembly.
  function example1() {
    log('=== Example1 ===')

    // Obtain the necessary runtime helpers
    const { __pin, __unpin, __getArray } = exports

    // Create a new array in WebAssembly and get a reference to it. Note that
    // the array is not reachable from within WebAssembly, only externally, so
    // we should pin it to prevent it from becoming garbage collected too early.
    let arrayPtr = __pin(exports.createArray(5))
    log(`Array pointer: ${arrayPtr}`)

    // Log its elements to make sure these are zero
    log('Initial values: ' + __getArray(arrayPtr).join(', '))

    // Randomize the array in WebAssembly and log it again
    exports.randomizeArray(arrayPtr)
    log('Randomized values: ' + __getArray(arrayPtr).join(', '))

    // Compute the array values' sum and log it. This will overflow i32 range.
    let total = exports.sumArray(arrayPtr)
    log(`Sum (likely overflown): ${total}`)

    // We are done with the array, so __unpin it so it can become collected.
    __unpin(arrayPtr)

    log()
  }
  example1()

  // A slightly more advanced example allocating the array in JavaScript instead
  // of WebAssembly, and utilizing a live view to modify it in WebAssembly memory.
  function example2() {
    log('=== Example2 ===')

    // Obtain the necessary runtime helpers
    const { __pin, __unpin, __newArray, __getArray, __getArrayView } = exports

    // Create a new array, but this time in JavaScript. Note that the array is
    // again not reachable from within WebAssembly, only externally, so we
    // should pin it to prevent it from becoming garbage collected too early.
    let arrayPtr = __pin(__newArray(exports.Int32Array_ID, [
      3, 4, 5, 6, 7, 8, 9
    ]))
    log('Array pointer: ' + arrayPtr)

    // Log its elements to make sure these are the provided values
    log('Initial values: ' + __getArray(arrayPtr).join(', '))

    // Compute the array values' sum and log it
    let total = exports.sumArray(arrayPtr)
    log('Sum: ' + total)

    // Instead of copying, let's obtain a live view on the array and modify its
    // values right in WebAssembly memory.
    let view = __getArrayView(arrayPtr)
    view.reverse()

    // Log the array's elements, now reversed
    log('Reversed values: ' + __getArray(arrayPtr).join(', '))

    // We are done with the array, so __unpin it so it can become collected.
    __unpin(arrayPtr)

    log()
  }
  example2()
})
</script>

NOTE

This example utilizes the loader to work with managed objects, hence requires --exportRuntime to be set to expose the runtime helpers to JavaScript.

# Resources

Further information on using the loader and the runtime helpers is available as part of the loader's and the garbage collection documentation.