diff options
Diffstat (limited to 'deps/v8/test/wasm-api-tests/callbacks.cc')
-rw-r--r-- | deps/v8/test/wasm-api-tests/callbacks.cc | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/deps/v8/test/wasm-api-tests/callbacks.cc b/deps/v8/test/wasm-api-tests/callbacks.cc new file mode 100644 index 0000000000..1c91d9ca54 --- /dev/null +++ b/deps/v8/test/wasm-api-tests/callbacks.cc @@ -0,0 +1,195 @@ +// 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 "src/execution/isolate.h" +#include "src/heap/heap.h" +#include "src/wasm/c-api.h" +#include "src/wasm/wasm-module-builder.h" +#include "src/wasm/wasm-opcodes.h" +#include "src/zone/accounting-allocator.h" +#include "src/zone/zone.h" +#include "test/common/wasm/wasm-macro-gen.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/wasm-api/wasm.hh" + +namespace wasm { + +// TODO(jkummerow): Drop these from the API. +#ifdef DEBUG +template <class T> +void vec<T>::make_data() {} + +template <class T> +void vec<T>::free_data() {} +#endif + +} // namespace wasm + +namespace v8 { +namespace internal { +namespace wasm { + +namespace { + +using ::wasm::Engine; +using ::wasm::Extern; +using ::wasm::Func; +using ::wasm::FuncType; +using ::wasm::Instance; +using ::wasm::Module; +using ::wasm::own; +using ::wasm::Store; +using ::wasm::Trap; +using ::wasm::Val; +using ::wasm::ValType; +using ::wasm::vec; + +own<Trap*> Stage2(void* env, const Val args[], Val results[]); + +class WasmCapiTest : public ::testing::Test { + public: + WasmCapiTest() + : Test(), + zone_(&allocator_, ZONE_NAME), + builder_(&zone_), + exports_(vec<Extern*>::make()), + wasm_sig_(1, 1, wasm_sig_types_) { + engine_ = Engine::make(); + store_ = Store::make(engine_.get()); + + // Build the following function: + // int32 stage1(int32 arg0) { return stage2(arg0); } + uint32_t stage2_index = + builder_.AddImport(ArrayVector("stage2"), wasm_sig()); + byte code[] = {WASM_CALL_FUNCTION(stage2_index, WASM_GET_LOCAL(0))}; + AddExportedFunction(CStrVector("stage1"), code, sizeof(code)); + + cpp_sig_ = FuncType::make(vec<ValType*>::make(ValType::make(::wasm::I32)), + vec<ValType*>::make(ValType::make(::wasm::I32))); + stage2_ = Func::make(store(), cpp_sig_.get(), Stage2, this); + } + + void Compile() { + ZoneBuffer buffer(&zone_); + builder_.WriteTo(buffer); + size_t size = buffer.end() - buffer.begin(); + vec<byte_t> binary = vec<byte_t>::make( + size, reinterpret_cast<byte_t*>(const_cast<byte*>(buffer.begin()))); + + module_ = Module::make(store_.get(), binary); + DCHECK_NE(module_.get(), nullptr); + } + + own<Trap*> Run(Extern* imports[], Val args[], Val results[]) { + instance_ = Instance::make(store_.get(), module_.get(), imports); + DCHECK_NE(instance_.get(), nullptr); + exports_ = instance_->exports(); + Func* entry = GetExportedFunction(0); + return entry->call(args, results); + } + + void AddExportedFunction(Vector<const char> name, byte code[], + size_t code_size) { + WasmFunctionBuilder* fun = builder()->AddFunction(wasm_sig()); + fun->EmitCode(code, static_cast<uint32_t>(code_size)); + fun->Emit(kExprEnd); + builder()->AddExport(name, fun); + } + + Func* GetExportedFunction(size_t index) { + DCHECK_GT(exports_.size(), index); + Extern* exported = exports_[index]; + DCHECK_EQ(exported->kind(), ::wasm::EXTERN_FUNC); + Func* func = exported->func(); + DCHECK_NE(func, nullptr); + return func; + } + + WasmModuleBuilder* builder() { return &builder_; } + Store* store() { return store_.get(); } + Func* stage2() { return stage2_.get(); } + + FunctionSig* wasm_sig() { return &wasm_sig_; } + FuncType* cpp_sig() { return cpp_sig_.get(); } + + private: + AccountingAllocator allocator_; + Zone zone_; + WasmModuleBuilder builder_; + own<Engine*> engine_; + own<Store*> store_; + own<Module*> module_; + own<Instance*> instance_; + vec<Extern*> exports_; + own<Func*> stage2_; + own<FuncType*> cpp_sig_; + ValueType wasm_sig_types_[2] = {kWasmI32, kWasmI32}; + FunctionSig wasm_sig_; +}; + +own<Trap*> Stage2(void* env, const Val args[], Val results[]) { + printf("Stage2...\n"); + WasmCapiTest* self = reinterpret_cast<WasmCapiTest*>(env); + Func* stage3 = self->GetExportedFunction(1); + own<Trap*> result = stage3->call(args, results); + if (result) { + printf("Stage2: got exception: %s\n", result->message().get()); + } else { + printf("Stage2: call successful\n"); + } + return result; +} + +own<Trap*> Stage4_GC(void* env, const Val args[], Val results[]) { + printf("Stage4...\n"); + i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env); + isolate->heap()->PreciseCollectAllGarbage( + i::Heap::kNoGCFlags, i::GarbageCollectionReason::kTesting, + v8::kGCCallbackFlagForced); + results[0] = Val::i32(args[0].i32() + 1); + return nullptr; +} + +} // namespace + +TEST_F(WasmCapiTest, Trap) { + // Build the following function: + // int32 stage3_trap(int32 arg0) { unreachable(); } + byte code[] = {WASM_UNREACHABLE}; + AddExportedFunction(CStrVector("stage3_trap"), code, sizeof(code)); + Compile(); + + Extern* imports[] = {stage2()}; + Val args[] = {Val::i32(42)}; + Val results[1]; + own<Trap*> result = Run(imports, args, results); + EXPECT_NE(result, nullptr); + printf("Stage0: Got trap as expected: %s\n", result->message().get()); +} + +TEST_F(WasmCapiTest, GC) { + // Build the following function: + // int32 stage3_to4(int32 arg0) { return stage4(arg0); } + uint32_t stage4_index = + builder()->AddImport(ArrayVector("stage4"), wasm_sig()); + byte code[] = {WASM_CALL_FUNCTION(stage4_index, WASM_GET_LOCAL(0))}; + AddExportedFunction(CStrVector("stage3_to4"), code, sizeof(code)); + Compile(); + + i::Isolate* isolate = + reinterpret_cast<::wasm::StoreImpl*>(store())->i_isolate(); + own<Func*> stage4 = Func::make(store(), cpp_sig(), Stage4_GC, isolate); + EXPECT_EQ(cpp_sig()->params().size(), stage4->type()->params().size()); + EXPECT_EQ(cpp_sig()->results().size(), stage4->type()->results().size()); + Extern* imports[] = {stage2(), stage4.get()}; + Val args[] = {Val::i32(42)}; + Val results[1]; + own<Trap*> result = Run(imports, args, results); + EXPECT_EQ(result, nullptr); + EXPECT_EQ(43, results[0].i32()); +} + +} // namespace wasm +} // namespace internal +} // namespace v8 |