| // 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 <memory> |
| |
| #include "include/v8.h" |
| #include "src/api/api-inl.h" |
| #include "src/handles/global-handles.h" |
| #include "test/cctest/cctest.h" |
| |
| namespace { |
| |
| bool wasm_streaming_callback_got_called = false; |
| bool wasm_streaming_data_got_collected = false; |
| |
| void WasmStreamingTestFinalizer(const v8::WeakCallbackInfo<void>& data) { |
| CHECK(!wasm_streaming_data_got_collected); |
| wasm_streaming_data_got_collected = true; |
| i::GlobalHandles::Destroy(reinterpret_cast<i::Address*>(data.GetParameter())); |
| } |
| |
| void WasmStreamingCallbackTestCallbackIsCalled( |
| const v8::FunctionCallbackInfo<v8::Value>& args) { |
| CHECK(!wasm_streaming_callback_got_called); |
| wasm_streaming_callback_got_called = true; |
| |
| i::Handle<i::Object> global_handle = |
| reinterpret_cast<i::Isolate*>(args.GetIsolate()) |
| ->global_handles() |
| ->Create(*v8::Utils::OpenHandle(*args.Data())); |
| i::GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(), |
| WasmStreamingTestFinalizer, |
| v8::WeakCallbackType::kParameter); |
| } |
| |
| void WasmStreamingCallbackTestOnBytesReceived( |
| const v8::FunctionCallbackInfo<v8::Value>& args) { |
| std::shared_ptr<v8::WasmStreaming> streaming = |
| v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data()); |
| |
| // The first bytes of the WebAssembly magic word. |
| const uint8_t bytes[]{0x00, 0x61, 0x73}; |
| streaming->OnBytesReceived(bytes, arraysize(bytes)); |
| } |
| |
| void WasmStreamingCallbackTestFinishWithSuccess( |
| const v8::FunctionCallbackInfo<v8::Value>& args) { |
| std::shared_ptr<v8::WasmStreaming> streaming = |
| v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data()); |
| // The bytes of a minimal WebAssembly module. |
| const uint8_t bytes[]{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00}; |
| streaming->OnBytesReceived(bytes, arraysize(bytes)); |
| streaming->Finish(); |
| } |
| |
| void WasmStreamingCallbackTestFinishWithFailure( |
| const v8::FunctionCallbackInfo<v8::Value>& args) { |
| std::shared_ptr<v8::WasmStreaming> streaming = |
| v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data()); |
| streaming->Finish(); |
| } |
| |
| void WasmStreamingCallbackTestAbortWithReject( |
| const v8::FunctionCallbackInfo<v8::Value>& args) { |
| std::shared_ptr<v8::WasmStreaming> streaming = |
| v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data()); |
| streaming->Abort(v8::Object::New(args.GetIsolate())); |
| } |
| |
| void WasmStreamingCallbackTestAbortNoReject( |
| const v8::FunctionCallbackInfo<v8::Value>& args) { |
| std::shared_ptr<v8::WasmStreaming> streaming = |
| v8::WasmStreaming::Unpack(args.GetIsolate(), args.Data()); |
| streaming->Abort({}); |
| } |
| |
| void TestWasmStreaming(v8::WasmStreamingCallback callback, |
| v8::Promise::PromiseState expected_state) { |
| CcTest::isolate()->SetWasmStreamingCallback(callback); |
| LocalContext env; |
| v8::Isolate* isolate = env->GetIsolate(); |
| v8::HandleScope scope(isolate); |
| |
| // Call {WebAssembly.compileStreaming} with {null} as parameter. The parameter |
| // is only really processed by the embedder, so for this test the value is |
| // irrelevant. |
| v8::Local<v8::Promise> promise = v8::Local<v8::Promise>::Cast( |
| CompileRun("WebAssembly.compileStreaming(null)")); |
| |
| EmptyMessageQueues(isolate); |
| CHECK_EQ(expected_state, promise->State()); |
| } |
| |
| } // namespace |
| |
| TEST(WasmStreamingCallback) { |
| TestWasmStreaming(WasmStreamingCallbackTestCallbackIsCalled, |
| v8::Promise::kPending); |
| CHECK(wasm_streaming_callback_got_called); |
| CcTest::CollectAllAvailableGarbage(); |
| CHECK(wasm_streaming_data_got_collected); |
| } |
| |
| TEST(WasmStreamingOnBytesReceived) { |
| TestWasmStreaming(WasmStreamingCallbackTestOnBytesReceived, |
| v8::Promise::kPending); |
| } |
| |
| TEST(WasmStreamingFinishWithSuccess) { |
| TestWasmStreaming(WasmStreamingCallbackTestFinishWithSuccess, |
| v8::Promise::kFulfilled); |
| } |
| |
| TEST(WasmStreamingFinishWithFailure) { |
| TestWasmStreaming(WasmStreamingCallbackTestFinishWithFailure, |
| v8::Promise::kRejected); |
| } |
| |
| TEST(WasmStreamingAbortWithReject) { |
| TestWasmStreaming(WasmStreamingCallbackTestAbortWithReject, |
| v8::Promise::kRejected); |
| } |
| |
| TEST(WasmStreamingAbortWithoutReject) { |
| TestWasmStreaming(WasmStreamingCallbackTestAbortNoReject, |
| v8::Promise::kPending); |
| } |
| |
| namespace { |
| |
| bool wasm_threads_enabled_value = false; |
| bool wasm_simd_enabled_value = false; |
| |
| bool MockWasmThreadsEnabledCallback(v8::Local<v8::Context>) { |
| return wasm_threads_enabled_value; |
| } |
| |
| bool MockWasmSimdEnabledCallback(v8::Local<v8::Context>) { |
| return wasm_simd_enabled_value; |
| } |
| |
| } // namespace |
| |
| TEST(TestSetWasmThreadsEnabledCallback) { |
| LocalContext env; |
| v8::Isolate* isolate = env->GetIsolate(); |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| v8::HandleScope scope(isolate); |
| v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate()); |
| i::Handle<i::Context> i_context = v8::Utils::OpenHandle(*context); |
| |
| // {Isolate::AreWasmThreadsEnabled} calls the callback set by the embedder if |
| // such a callback exists. Otherwise it returns |
| // {FLAG_experimental_wasm_threads}. First we test that the flag is returned |
| // correctly if no callback is set. Then we test that the flag is ignored if |
| // the callback is set. |
| |
| i::FLAG_experimental_wasm_threads = false; |
| CHECK(!i_isolate->AreWasmThreadsEnabled(i_context)); |
| |
| i::FLAG_experimental_wasm_threads = true; |
| CHECK(i_isolate->AreWasmThreadsEnabled(i_context)); |
| |
| isolate->SetWasmThreadsEnabledCallback(MockWasmThreadsEnabledCallback); |
| wasm_threads_enabled_value = false; |
| CHECK(!i_isolate->AreWasmThreadsEnabled(i_context)); |
| |
| wasm_threads_enabled_value = true; |
| i::FLAG_experimental_wasm_threads = false; |
| CHECK(i_isolate->AreWasmThreadsEnabled(i_context)); |
| } |
| |
| TEST(TestSetWasmSimdEnabledCallback) { |
| LocalContext env; |
| v8::Isolate* isolate = env->GetIsolate(); |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| v8::HandleScope scope(isolate); |
| v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate()); |
| i::Handle<i::Context> i_context = v8::Utils::OpenHandle(*context); |
| |
| // {Isolate::IsWasmSimdEnabled} calls the callback set by the embedder if |
| // such a callback exists. Otherwise it returns |
| // {FLAG_experimental_wasm_simd}. First we test that the flag is returned |
| // correctly if no callback is set. Then we test that the flag is ignored if |
| // the callback is set. |
| |
| i::FLAG_experimental_wasm_simd = false; |
| CHECK(!i_isolate->IsWasmSimdEnabled(i_context)); |
| |
| i::FLAG_experimental_wasm_simd = true; |
| CHECK(i_isolate->IsWasmSimdEnabled(i_context)); |
| |
| isolate->SetWasmSimdEnabledCallback(MockWasmSimdEnabledCallback); |
| wasm_simd_enabled_value = false; |
| CHECK(!i_isolate->IsWasmSimdEnabled(i_context)); |
| |
| wasm_simd_enabled_value = true; |
| i::FLAG_experimental_wasm_simd = false; |
| CHECK(i_isolate->IsWasmSimdEnabled(i_context)); |
| } |