Commit ec9bc860 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-c-api] Roll 351b9b7: Support multiple return values

This just adds the upstream tests; our implementation already had support.

Change-Id: If8d340ebe79eae65d12164a01883482d521b8451
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1762287Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63280}
parent 81642fa6
......@@ -34,6 +34,7 @@ v8_executable("wasm_api_tests") {
"globals.cc",
"hostref.cc",
"memory.cc",
"multi-return.cc",
"reflect.cc",
"run-all-wasm-api-tests.cc",
"serialize.cc",
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "test/wasm-api-tests/wasm-api-test.h"
namespace v8 {
namespace internal {
namespace wasm {
using ::wasm::I32;
using ::wasm::I64;
namespace {
own<Trap> Callback(const Val args[], Val results[]) {
results[0] = args[3].copy();
results[1] = args[1].copy();
results[2] = args[2].copy();
results[3] = args[0].copy();
return nullptr;
}
} // namespace
TEST_F(WasmCapiTest, MultiReturn) {
ValueType reps[] = {kWasmI32, kWasmI64, kWasmI64, kWasmI32,
kWasmI32, kWasmI64, kWasmI64, kWasmI32};
FunctionSig sig(4, 4, reps);
uint32_t func_index = builder()->AddImport(CStrVector("f"), &sig);
byte code[] = {WASM_CALL_FUNCTION(func_index, WASM_GET_LOCAL(0),
WASM_GET_LOCAL(2), WASM_GET_LOCAL(1),
WASM_GET_LOCAL(3))};
AddExportedFunction(CStrVector("g"), code, sizeof(code), &sig);
ownvec<ValType> types =
ownvec<ValType>::make(ValType::make(I32), ValType::make(I64),
ValType::make(I64), ValType::make(I32));
own<FuncType> func_type =
FuncType::make(types.deep_copy(), types.deep_copy());
own<Func> callback = Func::make(store(), func_type.get(), Callback);
Extern* imports[] = {callback.get()};
Instantiate(imports);
Func* run_func = GetExportedFunction(0);
Val args[] = {Val::i32(1), Val::i64(2), Val::i64(3), Val::i32(4)};
Val results[4];
own<Trap> trap = run_func->call(args, results);
EXPECT_EQ(nullptr, trap);
EXPECT_EQ(4, results[0].i32());
EXPECT_EQ(3, results[1].i64());
EXPECT_EQ(2, results[2].i64());
EXPECT_EQ(1, results[3].i32());
}
} // namespace wasm
} // namespace internal
} // namespace v8
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "wasm.h"
#define own
// A function to be called from Wasm code.
own wasm_trap_t* callback(
const wasm_val_t args[], wasm_val_t results[]
) {
printf("Calling back...\n> ");
printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n",
args[0].of.i32, args[1].of.i64, args[2].of.i64, args[3].of.i32);
printf("\n");
wasm_val_copy(&results[0], &args[0]);
return NULL;
}
// A function closure.
own wasm_trap_t* closure_callback(
void* env, const wasm_val_t args[], wasm_val_t results[]
) {
int i = *(int*)env;
printf("Calling back closure...\n");
printf("> %d\n", i);
results[0].kind = WASM_I32;
results[0].of.i32 = (int32_t)i;
return NULL;
}
int main(int argc, const char* argv[]) {
// Initialize.
printf("Initializing...\n");
wasm_engine_t* engine = wasm_engine_new();
wasm_store_t* store = wasm_store_new(engine);
// Load binary.
printf("Loading binary...\n");
FILE* file = fopen("multi.wasm", "r");
if (!file) {
printf("> Error loading module!\n");
return 1;
}
fseek(file, 0L, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0L, SEEK_SET);
wasm_byte_vec_t binary;
wasm_byte_vec_new_uninitialized(&binary, file_size);
if (fread(binary.data, file_size, 1, file) != 1) {
printf("> Error loading module!\n");
return 1;
}
fclose(file);
// Compile.
printf("Compiling module...\n");
own wasm_module_t* module = wasm_module_new(store, &binary);
if (!module) {
printf("> Error compiling module!\n");
return 1;
}
wasm_byte_vec_delete(&binary);
// Create external print functions.
printf("Creating callback...\n");
wasm_valtype_t* types[4] = {
wasm_valtype_new_i32(), wasm_valtype_new_i64(),
wasm_valtype_new_i64(), wasm_valtype_new_i32()
};
own wasm_valtype_vec_t tuple1, tuple2;
wasm_valtype_vec_new(&tuple1, 4, types);
wasm_valtype_vec_copy(&tuple2, &tuple1);
own wasm_functype_t* callback_type = wasm_functype_new(&tuple1, &tuple2);
own wasm_func_t* callback_func = wasm_func_new(store, callback_type, callback);
wasm_functype_delete(callback_type);
// Instantiate.
printf("Instantiating module...\n");
const wasm_extern_t* imports[] = {wasm_func_as_extern(callback_func)};
own wasm_instance_t* instance = wasm_instance_new(store, module, imports);
if (!instance) {
printf("> Error instantiating module!\n");
return 1;
}
wasm_func_delete(callback_func);
// Extract export.
printf("Extracting export...\n");
own wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
if (exports.size == 0) {
printf("> Error accessing exports!\n");
return 1;
}
const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]);
if (run_func == NULL) {
printf("> Error accessing export!\n");
return 1;
}
wasm_module_delete(module);
wasm_instance_delete(instance);
// Call.
printf("Calling export...\n");
wasm_val_t args[4];
args[0].kind = WASM_I32;
args[0].of.i32 = 1;
args[1].kind = WASM_I64;
args[1].of.i64 = 2;
args[2].kind = WASM_I64;
args[2].of.i64 = 3;
args[3].kind = WASM_I32;
args[3].of.i32 = 4;
wasm_val_t results[4];
if (wasm_func_call(run_func, args, results)) {
printf("> Error calling function!\n");
return 1;
}
wasm_extern_vec_delete(&exports);
// Print result.
printf("Printing result...\n");
printf("> %"PRIu32" %"PRIu64" %"PRIu64" %"PRIu32"\n",
results[0].of.i32, results[1].of.i64,
results[2].of.i64, results[3].of.i32);
assert(results[0].of.i32 == 4);
assert(results[1].of.i64 == 3);
assert(results[2].of.i64 == 2);
assert(results[3].of.i32 == 1);
// Shut down.
printf("Shutting down...\n");
wasm_store_delete(store);
wasm_engine_delete(engine);
// All done.
printf("Done.\n");
return 0;
}
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cinttypes>
#include "wasm.hh"
// A function to be called from Wasm code.
auto callback(
const wasm::Val args[], wasm::Val results[]
) -> wasm::own<wasm::Trap> {
std::cout << "Calling back..." << std::endl;
std::cout << "> " << args[0].i32();
std::cout << " " << args[1].i64();
std::cout << " " << args[2].i64();
std::cout << " " << args[3].i32() << std::endl;
results[0] = args[3].copy();
results[1] = args[1].copy();
results[2] = args[2].copy();
results[3] = args[0].copy();
return nullptr;
}
void run() {
// Initialize.
std::cout << "Initializing..." << std::endl;
auto engine = wasm::Engine::make();
auto store_ = wasm::Store::make(engine.get());
auto store = store_.get();
// Load binary.
std::cout << "Loading binary..." << std::endl;
std::ifstream file("multi.wasm");
file.seekg(0, std::ios_base::end);
auto file_size = file.tellg();
file.seekg(0);
auto binary = wasm::vec<byte_t>::make_uninitialized(file_size);
file.read(binary.get(), file_size);
file.close();
if (file.fail()) {
std::cout << "> Error loading module!" << std::endl;
exit(1);
}
// Compile.
std::cout << "Compiling module..." << std::endl;
auto module = wasm::Module::make(store, binary);
if (!module) {
std::cout << "> Error compiling module!" << std::endl;
exit(1);
}
// Create external print functions.
std::cout << "Creating callback..." << std::endl;
auto tuple = wasm::ownvec<wasm::ValType>::make(
wasm::ValType::make(wasm::I32),
wasm::ValType::make(wasm::I64),
wasm::ValType::make(wasm::I64),
wasm::ValType::make(wasm::I32)
);
auto callback_type =
wasm::FuncType::make(tuple.deep_copy(), tuple.deep_copy());
auto callback_func = wasm::Func::make(store, callback_type.get(), callback);
// Instantiate.
std::cout << "Instantiating module..." << std::endl;
wasm::Extern* imports[] = {callback_func.get()};
auto instance = wasm::Instance::make(store, module.get(), imports);
if (!instance) {
std::cout << "> Error instantiating module!" << std::endl;
exit(1);
}
// Extract export.
std::cout << "Extracting export..." << std::endl;
auto exports = instance->exports();
if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) {
std::cout << "> Error accessing export!" << std::endl;
exit(1);
}
auto run_func = exports[0]->func();
// Call.
std::cout << "Calling export..." << std::endl;
wasm::Val args[] = {
wasm::Val::i32(1), wasm::Val::i64(2), wasm::Val::i64(3), wasm::Val::i32(4)
};
wasm::Val results[4];
if (wasm::own<wasm::Trap> trap = run_func->call(args, results)) {
std::cout << "> Error calling function! " << trap->message().get() << std::endl;
exit(1);
}
// Print result.
std::cout << "Printing result..." << std::endl;
std::cout << "> " << results[0].i32();
std::cout << " " << results[1].i64();
std::cout << " " << results[2].i64();
std::cout << " " << results[3].i32() << std::endl;
assert(results[0].i32() == 4);
assert(results[1].i64() == 3);
assert(results[2].i64() == 2);
assert(results[3].i32() == 1);
// Shut down.
std::cout << "Shutting down..." << std::endl;
}
int main(int argc, const char* argv[]) {
run();
std::cout << "Done." << std::endl;
return 0;
}
(module
(func $f (import "" "f") (param i32 i64 i64 i32) (result i32 i64 i64 i32))
(func $g (export "g") (param i32 i64 i64 i32) (result i32 i64 i64 i32)
(call $f (local.get 0) (local.get 2) (local.get 1) (local.get 3))
)
)
......@@ -38,7 +38,7 @@ CLANG_PATH = os.path.join(CHECKOUT_PATH, "third_party", "llvm-build",
"Release+Asserts", "bin")
EXAMPLES = ["hello", "callback", "trap", "reflect", "global", "table",
"memory", "finalize", "serialize", "threads", "hostref"]
"memory", "finalize", "serialize", "threads", "hostref", "multi"]
CLANG = {
"name": "Clang",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment