Working with anyref

You can also browse this source code online and clone the wasmtime repository to run the example locally.

This example demonstrates using anyref values.

anyref.wat

(module
  (table $table (export "table") 10 anyref)

  (global $global (export "global") (mut anyref) (ref.null any))

  (func (export "take_anyref") (param anyref)
    nop
  )

  (func (export "return_anyref") (result anyref)
    i32.const 42
    ref.i31
  )
)

anyref.cc

/*
Example of using `anyref` values.

You can build the example using CMake:

mkdir build && (cd build && cmake .. && \
  cmake --build . --target wasmtime-anyref-cpp)

And then run it:

build/wasmtime-anyref-cpp
*/

#include <fstream>
#include <iostream>
#include <sstream>
#include <wasmtime.hh>

using namespace wasmtime;

std::string readFile(const char *name) {
  std::ifstream watFile;
  watFile.open(name);
  std::stringstream strStream;
  strStream << watFile.rdbuf();
  return strStream.str();
}

int main() {
  std::cout << "Initializing...\n";
  Config config;
  config.wasm_reference_types(true);
  config.wasm_function_references(true);
  config.wasm_gc(true);
  Engine engine(std::move(config));
  Store store(engine);

  std::cout << "Compiling module...\n";
  auto wat = readFile("examples/anyref.wat");
  Module module = Module::compile(engine, wat).unwrap();

  std::cout << "Instantiating module...\n";
  Instance instance = Instance::create(store, module, {}).unwrap();

  std::cout << "Creating new `anyref` from i31...\n";
  // Create an i31ref wrapping 1234
  auto cx = store.context();
  AnyRef i31 = AnyRef::i31(cx, 1234);
  Val anyref_val(i31);
  auto opt_any = anyref_val.anyref(cx);
  if (!opt_any || !opt_any->u31(cx) || *opt_any->u31(cx) != 1234) {
    std::cerr << "> Error creating i31 anyref\n";
    return 1;
  }

  std::cout << "Touching `anyref` table...\n";
  Table table = std::get<Table>(*instance.get(store, "table"));
  table.set(store, 3, anyref_val).unwrap();
  auto elem_opt = table.get(store, 3);
  if (!elem_opt) {
    std::cerr << "> Error getting table element\n";
    return 1;
  }
  auto elem_any = elem_opt->anyref(cx);
  if (!elem_any || !elem_any->u31(cx) || *elem_any->u31(cx) != 1234) {
    std::cerr << "> Error verifying table element\n";
    return 1;
  }

  std::cout << "Touching `anyref` global...\n";
  Global global = std::get<Global>(*instance.get(store, "global"));
  global.set(store, anyref_val).unwrap();
  Val global_val = global.get(store);
  auto global_any = global_val.anyref(cx);
  if (!global_any || !global_any->u31(cx) || *global_any->u31(cx) != 1234) {
    std::cerr << "> Error verifying global value\n";
    return 1;
  }

  std::cout << "Passing `anyref` into func...\n";
  Func take_anyref = std::get<Func>(*instance.get(store, "take_anyref"));
  take_anyref.call(store, {anyref_val}).unwrap();

  std::cout << "Getting `anyref` from func...\n";
  Func return_anyref = std::get<Func>(*instance.get(store, "return_anyref"));
  auto results = return_anyref.call(store, {}).unwrap();
  if (results.size() != 1) {
    std::cerr << "> Unexpected number of results\n";
    return 1;
  }
  auto ret_any = results[0].anyref(cx);
  if (!ret_any || !ret_any->u31(cx) || *ret_any->u31(cx) != 42) {
    std::cerr << "> Error verifying returned anyref\n";
    return 1;
  }

  std::cout << "GCing within the store...\n";
  store.context().gc();

  std::cout << "Done.\n";
  return 0;
}