2018-07-05 09:17:35 +00:00
|
|
|
// Copyright 2018 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>
|
|
|
|
|
2019-05-22 07:55:37 +00:00
|
|
|
#include "src/execution/microtask-queue.h"
|
2019-05-23 08:51:46 +00:00
|
|
|
#include "src/objects/objects-inl.h"
|
2018-08-01 10:13:03 +00:00
|
|
|
#include "src/wasm/function-compiler.h"
|
2018-07-05 09:17:35 +00:00
|
|
|
#include "src/wasm/wasm-engine.h"
|
|
|
|
#include "src/wasm/wasm-module-builder.h"
|
|
|
|
#include "src/wasm/wasm-module.h"
|
|
|
|
#include "src/wasm/wasm-objects-inl.h"
|
|
|
|
|
|
|
|
#include "test/cctest/cctest.h"
|
|
|
|
#include "test/common/wasm/test-signatures.h"
|
|
|
|
#include "test/common/wasm/wasm-macro-gen.h"
|
|
|
|
#include "test/common/wasm/wasm-module-runner.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace wasm {
|
|
|
|
namespace test_wasm_shared_engine {
|
|
|
|
|
|
|
|
// Helper type definition representing a WebAssembly module shared between
|
|
|
|
// multiple Isolates with implicit reference counting.
|
|
|
|
using SharedModule = std::shared_ptr<NativeModule>;
|
|
|
|
|
2021-04-28 08:24:34 +00:00
|
|
|
// Helper class representing an Isolate that uses the process-wide (shared) wasm
|
|
|
|
// engine.
|
2018-07-05 09:17:35 +00:00
|
|
|
class SharedEngineIsolate {
|
|
|
|
public:
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineIsolate() : isolate_(v8::Isolate::Allocate()) {
|
2018-07-05 09:17:35 +00:00
|
|
|
v8::Isolate::CreateParams create_params;
|
|
|
|
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
|
|
|
v8::Isolate::Initialize(isolate_, create_params);
|
|
|
|
v8::HandleScope handle_scope(v8_isolate());
|
|
|
|
v8::Context::New(v8_isolate())->Enter();
|
|
|
|
testing::SetupIsolateForWasmModule(isolate());
|
|
|
|
zone_.reset(new Zone(isolate()->allocator(), ZONE_NAME));
|
|
|
|
}
|
|
|
|
~SharedEngineIsolate() {
|
|
|
|
zone_.reset();
|
|
|
|
isolate_->Dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
Zone* zone() const { return zone_.get(); }
|
|
|
|
v8::Isolate* v8_isolate() { return isolate_; }
|
|
|
|
Isolate* isolate() { return reinterpret_cast<Isolate*>(isolate_); }
|
|
|
|
|
|
|
|
Handle<WasmInstanceObject> CompileAndInstantiate(ZoneBuffer* buffer) {
|
|
|
|
ErrorThrower thrower(isolate(), "CompileAndInstantiate");
|
|
|
|
MaybeHandle<WasmInstanceObject> instance =
|
|
|
|
testing::CompileAndInstantiateForTesting(
|
|
|
|
isolate(), &thrower,
|
|
|
|
ModuleWireBytes(buffer->begin(), buffer->end()));
|
|
|
|
return instance.ToHandleChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
Handle<WasmInstanceObject> ImportInstance(SharedModule shared_module) {
|
2018-07-05 14:31:15 +00:00
|
|
|
Handle<WasmModuleObject> module_object =
|
2021-06-18 14:29:39 +00:00
|
|
|
GetWasmEngine()->ImportNativeModule(isolate(), shared_module, {});
|
2018-07-05 09:17:35 +00:00
|
|
|
ErrorThrower thrower(isolate(), "ImportInstance");
|
2021-06-18 14:29:39 +00:00
|
|
|
MaybeHandle<WasmInstanceObject> instance = GetWasmEngine()->SyncInstantiate(
|
|
|
|
isolate(), &thrower, module_object, {}, {});
|
2018-07-05 09:17:35 +00:00
|
|
|
return instance.ToHandleChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
SharedModule ExportInstance(Handle<WasmInstanceObject> instance) {
|
2018-12-11 10:37:32 +00:00
|
|
|
return instance->module_object().shared_native_module();
|
2018-07-05 09:17:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int32_t Run(Handle<WasmInstanceObject> instance) {
|
2020-08-11 08:48:31 +00:00
|
|
|
return testing::CallWasmFunctionForTesting(isolate(), instance, "main", 0,
|
|
|
|
nullptr);
|
2018-07-05 09:17:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
v8::Isolate* isolate_;
|
|
|
|
std::unique_ptr<Zone> zone_;
|
|
|
|
};
|
|
|
|
|
2018-07-26 13:08:04 +00:00
|
|
|
// Helper class representing a Thread running its own instance of an Isolate
|
|
|
|
// with a shared WebAssembly engine available at construction time.
|
|
|
|
class SharedEngineThread : public v8::base::Thread {
|
|
|
|
public:
|
2021-04-28 08:24:34 +00:00
|
|
|
explicit SharedEngineThread(
|
|
|
|
std::function<void(SharedEngineIsolate*)> callback)
|
|
|
|
: Thread(Options("SharedEngineThread")), callback_(callback) {}
|
2018-07-26 13:08:04 +00:00
|
|
|
|
2018-09-14 14:54:08 +00:00
|
|
|
void Run() override {
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineIsolate isolate;
|
2019-09-10 01:19:59 +00:00
|
|
|
callback_(&isolate);
|
2018-07-26 13:08:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2019-09-10 01:19:59 +00:00
|
|
|
std::function<void(SharedEngineIsolate*)> callback_;
|
2018-07-26 13:08:04 +00:00
|
|
|
};
|
|
|
|
|
2018-07-05 09:17:35 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
ZoneBuffer* BuildReturnConstantModule(Zone* zone, int constant) {
|
|
|
|
TestSignatures sigs;
|
2020-07-09 11:51:58 +00:00
|
|
|
ZoneBuffer* buffer = zone->New<ZoneBuffer>(zone);
|
|
|
|
WasmModuleBuilder* builder = zone->New<WasmModuleBuilder>(zone);
|
2018-07-05 09:17:35 +00:00
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
2021-06-17 15:43:55 +00:00
|
|
|
f->builder()->AddExport(base::CStrVector("main"), f);
|
2018-07-05 09:17:35 +00:00
|
|
|
byte code[] = {WASM_I32V_2(constant)};
|
|
|
|
f->EmitCode(code, sizeof(code));
|
|
|
|
f->Emit(kExprEnd);
|
2019-07-08 09:16:39 +00:00
|
|
|
builder->WriteTo(buffer);
|
2018-07-05 09:17:35 +00:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2018-07-31 09:41:11 +00:00
|
|
|
class MockInstantiationResolver : public InstantiationResultResolver {
|
|
|
|
public:
|
|
|
|
explicit MockInstantiationResolver(Handle<Object>* out_instance)
|
|
|
|
: out_instance_(out_instance) {}
|
2018-09-14 14:54:08 +00:00
|
|
|
void OnInstantiationSucceeded(Handle<WasmInstanceObject> result) override {
|
2018-10-31 22:52:56 +00:00
|
|
|
*out_instance_->location() = result->ptr();
|
2018-07-31 09:41:11 +00:00
|
|
|
}
|
2018-09-14 14:54:08 +00:00
|
|
|
void OnInstantiationFailed(Handle<Object> error_reason) override {
|
2018-07-31 09:41:11 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handle<Object>* out_instance_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MockCompilationResolver : public CompilationResultResolver {
|
|
|
|
public:
|
2019-09-10 01:19:59 +00:00
|
|
|
MockCompilationResolver(SharedEngineIsolate* isolate,
|
|
|
|
Handle<Object>* out_instance)
|
2018-07-31 09:41:11 +00:00
|
|
|
: isolate_(isolate), out_instance_(out_instance) {}
|
2018-09-14 14:54:08 +00:00
|
|
|
void OnCompilationSucceeded(Handle<WasmModuleObject> result) override {
|
2021-06-18 14:29:39 +00:00
|
|
|
GetWasmEngine()->AsyncInstantiate(
|
2019-09-10 01:19:59 +00:00
|
|
|
isolate_->isolate(),
|
2019-09-10 10:12:00 +00:00
|
|
|
std::make_unique<MockInstantiationResolver>(out_instance_), result, {});
|
2018-07-31 09:41:11 +00:00
|
|
|
}
|
2018-09-14 14:54:08 +00:00
|
|
|
void OnCompilationFailed(Handle<Object> error_reason) override {
|
2018-07-31 09:41:11 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2019-09-10 01:19:59 +00:00
|
|
|
SharedEngineIsolate* isolate_;
|
2018-07-31 09:41:11 +00:00
|
|
|
Handle<Object>* out_instance_;
|
|
|
|
};
|
|
|
|
|
2019-09-10 01:19:59 +00:00
|
|
|
void PumpMessageLoop(SharedEngineIsolate* isolate) {
|
2018-07-31 09:41:11 +00:00
|
|
|
v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(),
|
2019-09-10 01:19:59 +00:00
|
|
|
isolate->v8_isolate(),
|
2018-07-31 09:41:11 +00:00
|
|
|
platform::MessageLoopBehavior::kWaitForWork);
|
2019-09-10 01:19:59 +00:00
|
|
|
isolate->isolate()->default_microtask_queue()->RunMicrotasks(
|
|
|
|
isolate->isolate());
|
2018-07-31 09:41:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Handle<WasmInstanceObject> CompileAndInstantiateAsync(
|
2019-09-10 01:19:59 +00:00
|
|
|
SharedEngineIsolate* isolate, ZoneBuffer* buffer) {
|
2019-11-15 10:39:28 +00:00
|
|
|
Handle<Object> maybe_instance = handle(Smi::zero(), isolate->isolate());
|
2019-11-26 16:25:14 +00:00
|
|
|
auto enabled_features = WasmFeatures::FromIsolate(isolate->isolate());
|
2019-05-20 11:14:29 +00:00
|
|
|
constexpr const char* kAPIMethodName = "Test.CompileAndInstantiateAsync";
|
2021-06-18 14:29:39 +00:00
|
|
|
GetWasmEngine()->AsyncCompile(
|
2019-09-10 01:19:59 +00:00
|
|
|
isolate->isolate(), enabled_features,
|
2019-09-10 10:12:00 +00:00
|
|
|
std::make_unique<MockCompilationResolver>(isolate, &maybe_instance),
|
2019-05-20 11:14:29 +00:00
|
|
|
ModuleWireBytes(buffer->begin(), buffer->end()), true, kAPIMethodName);
|
2018-07-31 09:41:11 +00:00
|
|
|
while (!maybe_instance->IsWasmInstanceObject()) PumpMessageLoop(isolate);
|
|
|
|
Handle<WasmInstanceObject> instance =
|
|
|
|
Handle<WasmInstanceObject>::cast(maybe_instance);
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2018-07-05 09:17:35 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST(SharedEngineRunSeparated) {
|
|
|
|
{
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineIsolate isolate;
|
2018-07-05 09:17:35 +00:00
|
|
|
HandleScope scope(isolate.isolate());
|
|
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
|
|
|
|
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
|
|
|
|
CHECK_EQ(23, isolate.Run(instance));
|
|
|
|
}
|
|
|
|
{
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineIsolate isolate;
|
2018-07-05 09:17:35 +00:00
|
|
|
HandleScope scope(isolate.isolate());
|
|
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 42);
|
|
|
|
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
|
|
|
|
CHECK_EQ(42, isolate.Run(instance));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SharedEngineRunImported) {
|
|
|
|
SharedModule module;
|
|
|
|
{
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineIsolate isolate;
|
2018-07-05 09:17:35 +00:00
|
|
|
HandleScope scope(isolate.isolate());
|
|
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
|
|
|
|
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
|
2018-07-09 08:02:54 +00:00
|
|
|
module = isolate.ExportInstance(instance);
|
2018-07-05 09:17:35 +00:00
|
|
|
CHECK_EQ(23, isolate.Run(instance));
|
|
|
|
}
|
2018-07-09 08:02:54 +00:00
|
|
|
{
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineIsolate isolate;
|
2018-07-09 08:02:54 +00:00
|
|
|
HandleScope scope(isolate.isolate());
|
|
|
|
Handle<WasmInstanceObject> instance = isolate.ImportInstance(module);
|
|
|
|
CHECK_EQ(23, isolate.Run(instance));
|
|
|
|
}
|
2018-07-05 09:17:35 +00:00
|
|
|
}
|
|
|
|
|
2018-07-31 09:41:11 +00:00
|
|
|
TEST(SharedEngineRunThreadedBuildingSync) {
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineThread thread1([](SharedEngineIsolate* isolate) {
|
2019-09-10 01:19:59 +00:00
|
|
|
HandleScope scope(isolate->isolate());
|
|
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 23);
|
|
|
|
Handle<WasmInstanceObject> instance =
|
|
|
|
isolate->CompileAndInstantiate(buffer);
|
|
|
|
CHECK_EQ(23, isolate->Run(instance));
|
2018-07-26 13:08:04 +00:00
|
|
|
});
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineThread thread2([](SharedEngineIsolate* isolate) {
|
2019-09-10 01:19:59 +00:00
|
|
|
HandleScope scope(isolate->isolate());
|
|
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 42);
|
|
|
|
Handle<WasmInstanceObject> instance =
|
|
|
|
isolate->CompileAndInstantiate(buffer);
|
|
|
|
CHECK_EQ(42, isolate->Run(instance));
|
2018-07-26 13:08:04 +00:00
|
|
|
});
|
2019-07-29 13:09:02 +00:00
|
|
|
CHECK(thread1.Start());
|
|
|
|
CHECK(thread2.Start());
|
2018-07-26 13:08:04 +00:00
|
|
|
thread1.Join();
|
|
|
|
thread2.Join();
|
|
|
|
}
|
|
|
|
|
2018-07-31 09:41:11 +00:00
|
|
|
TEST(SharedEngineRunThreadedBuildingAsync) {
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineThread thread1([](SharedEngineIsolate* isolate) {
|
2019-09-10 01:19:59 +00:00
|
|
|
HandleScope scope(isolate->isolate());
|
|
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 23);
|
2018-07-31 09:41:11 +00:00
|
|
|
Handle<WasmInstanceObject> instance =
|
|
|
|
CompileAndInstantiateAsync(isolate, buffer);
|
2019-09-10 01:19:59 +00:00
|
|
|
CHECK_EQ(23, isolate->Run(instance));
|
2018-07-31 09:41:11 +00:00
|
|
|
});
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineThread thread2([](SharedEngineIsolate* isolate) {
|
2019-09-10 01:19:59 +00:00
|
|
|
HandleScope scope(isolate->isolate());
|
|
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 42);
|
2018-07-31 09:41:11 +00:00
|
|
|
Handle<WasmInstanceObject> instance =
|
|
|
|
CompileAndInstantiateAsync(isolate, buffer);
|
2019-09-10 01:19:59 +00:00
|
|
|
CHECK_EQ(42, isolate->Run(instance));
|
2018-07-31 09:41:11 +00:00
|
|
|
});
|
2019-07-29 13:09:02 +00:00
|
|
|
CHECK(thread1.Start());
|
|
|
|
CHECK(thread2.Start());
|
2018-07-31 09:41:11 +00:00
|
|
|
thread1.Join();
|
|
|
|
thread2.Join();
|
|
|
|
}
|
|
|
|
|
2018-07-26 13:08:04 +00:00
|
|
|
TEST(SharedEngineRunThreadedExecution) {
|
|
|
|
SharedModule module;
|
|
|
|
{
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineIsolate isolate;
|
2018-07-26 13:08:04 +00:00
|
|
|
HandleScope scope(isolate.isolate());
|
|
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
|
|
|
|
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
|
|
|
|
module = isolate.ExportInstance(instance);
|
|
|
|
}
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineThread thread1([module](SharedEngineIsolate* isolate) {
|
2019-09-10 01:19:59 +00:00
|
|
|
HandleScope scope(isolate->isolate());
|
|
|
|
Handle<WasmInstanceObject> instance = isolate->ImportInstance(module);
|
|
|
|
CHECK_EQ(23, isolate->Run(instance));
|
2018-07-26 13:08:04 +00:00
|
|
|
});
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineThread thread2([module](SharedEngineIsolate* isolate) {
|
2019-09-10 01:19:59 +00:00
|
|
|
HandleScope scope(isolate->isolate());
|
|
|
|
Handle<WasmInstanceObject> instance = isolate->ImportInstance(module);
|
|
|
|
CHECK_EQ(23, isolate->Run(instance));
|
2018-07-26 13:08:04 +00:00
|
|
|
});
|
2019-07-29 13:09:02 +00:00
|
|
|
CHECK(thread1.Start());
|
|
|
|
CHECK(thread2.Start());
|
2018-07-26 13:08:04 +00:00
|
|
|
thread1.Join();
|
|
|
|
thread2.Join();
|
|
|
|
}
|
|
|
|
|
2018-08-01 10:13:03 +00:00
|
|
|
TEST(SharedEngineRunThreadedTierUp) {
|
|
|
|
SharedModule module;
|
|
|
|
{
|
2021-04-28 08:24:34 +00:00
|
|
|
SharedEngineIsolate isolate;
|
2018-08-01 10:13:03 +00:00
|
|
|
HandleScope scope(isolate.isolate());
|
|
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
|
|
|
|
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
|
|
|
|
module = isolate.ExportInstance(instance);
|
|
|
|
}
|
|
|
|
constexpr int kNumberOfThreads = 5;
|
|
|
|
std::list<SharedEngineThread> threads;
|
|
|
|
for (int i = 0; i < kNumberOfThreads; ++i) {
|
2021-04-28 08:24:34 +00:00
|
|
|
threads.emplace_back([module](SharedEngineIsolate* isolate) {
|
2018-08-01 10:13:03 +00:00
|
|
|
constexpr int kNumberOfIterations = 100;
|
2019-09-10 01:19:59 +00:00
|
|
|
HandleScope scope(isolate->isolate());
|
|
|
|
Handle<WasmInstanceObject> instance = isolate->ImportInstance(module);
|
2018-08-01 10:13:03 +00:00
|
|
|
for (int j = 0; j < kNumberOfIterations; ++j) {
|
2019-09-10 01:19:59 +00:00
|
|
|
CHECK_EQ(23, isolate->Run(instance));
|
2018-08-01 10:13:03 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2021-04-28 08:24:34 +00:00
|
|
|
threads.emplace_back([module](SharedEngineIsolate* isolate) {
|
2019-09-10 01:19:59 +00:00
|
|
|
HandleScope scope(isolate->isolate());
|
|
|
|
Handle<WasmInstanceObject> instance = isolate->ImportInstance(module);
|
2019-11-26 16:25:14 +00:00
|
|
|
WasmFeatures detected = WasmFeatures::None();
|
2018-08-01 10:13:03 +00:00
|
|
|
WasmCompilationUnit::CompileWasmFunction(
|
2019-09-10 01:19:59 +00:00
|
|
|
isolate->isolate(), module.get(), &detected,
|
2019-04-03 15:37:47 +00:00
|
|
|
&module->module()->functions[0], ExecutionTier::kTurbofan);
|
2019-09-10 01:19:59 +00:00
|
|
|
CHECK_EQ(23, isolate->Run(instance));
|
2018-08-01 10:13:03 +00:00
|
|
|
});
|
2019-07-29 13:09:02 +00:00
|
|
|
for (auto& thread : threads) CHECK(thread.Start());
|
2018-08-01 10:13:03 +00:00
|
|
|
for (auto& thread : threads) thread.Join();
|
|
|
|
}
|
|
|
|
|
2018-07-05 09:17:35 +00:00
|
|
|
} // namespace test_wasm_shared_engine
|
|
|
|
} // namespace wasm
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|