dbb13d615b
Even though we provide a --wasm-max-code-space flag (defaulting to {kMaxWasmCodeMB}, we still had checks in place that the actual committed code space is not bigger than that constant. This CL fixes that by always comparing against the value of the flag. This will allow us to specify a code space limit which is larger than the default. This is useful when debugging larger Wasm apps which exceed the limit, but are not meant to be shipped that way. Drive-by: Remove a dead use of the {kMaxWasmCodeMemory} constant. R=ecmziegler@chromium.org Bug: chromium:1117033, chromium:1114093, chromium:1107649, chromium:1111266 Change-Id: I2684446230a8a6f0a27ad963dd6f36e5764b25e0 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2376810 Reviewed-by: Emanuel Ziegler <ecmziegler@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/master@{#69611}
367 lines
13 KiB
C++
367 lines
13 KiB
C++
// 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>
|
|
|
|
#include "src/execution/microtask-queue.h"
|
|
#include "src/objects/objects-inl.h"
|
|
#include "src/wasm/function-compiler.h"
|
|
#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 class representing a WebAssembly engine that is capable of being
|
|
// shared between multiple Isolates, sharing the underlying generated code.
|
|
class SharedEngine {
|
|
public:
|
|
~SharedEngine() {
|
|
// Ensure no remaining uses exist.
|
|
CHECK(wasm_engine_.unique());
|
|
}
|
|
|
|
WasmEngine* engine() const { return wasm_engine_.get(); }
|
|
WasmCodeManager* code_manager() const { return engine()->code_manager(); }
|
|
|
|
int NumberOfExportedEngineUses() const {
|
|
// This class holds one implicit use itself, which we discount.
|
|
return static_cast<int>(wasm_engine_.use_count()) - 1;
|
|
}
|
|
|
|
std::shared_ptr<WasmEngine> ExportEngineForSharing() { return wasm_engine_; }
|
|
|
|
private:
|
|
std::shared_ptr<WasmEngine> wasm_engine_ = std::make_unique<WasmEngine>();
|
|
};
|
|
|
|
// Helper type definition representing a WebAssembly module shared between
|
|
// multiple Isolates with implicit reference counting.
|
|
using SharedModule = std::shared_ptr<NativeModule>;
|
|
|
|
// Helper class representing an Isolate based on a given shared WebAssembly
|
|
// engine available at construction time.
|
|
class SharedEngineIsolate {
|
|
public:
|
|
explicit SharedEngineIsolate(SharedEngine* engine)
|
|
: isolate_(v8::Isolate::Allocate()) {
|
|
isolate()->SetWasmEngine(engine->ExportEngineForSharing());
|
|
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) {
|
|
Handle<WasmModuleObject> module_object =
|
|
isolate()->wasm_engine()->ImportNativeModule(isolate(), shared_module,
|
|
{});
|
|
ErrorThrower thrower(isolate(), "ImportInstance");
|
|
MaybeHandle<WasmInstanceObject> instance =
|
|
isolate()->wasm_engine()->SyncInstantiate(isolate(), &thrower,
|
|
module_object, {}, {});
|
|
return instance.ToHandleChecked();
|
|
}
|
|
|
|
SharedModule ExportInstance(Handle<WasmInstanceObject> instance) {
|
|
return instance->module_object().shared_native_module();
|
|
}
|
|
|
|
int32_t Run(Handle<WasmInstanceObject> instance) {
|
|
return testing::CallWasmFunctionForTesting(isolate(), instance, "main", 0,
|
|
nullptr);
|
|
}
|
|
|
|
private:
|
|
v8::Isolate* isolate_;
|
|
std::unique_ptr<Zone> zone_;
|
|
};
|
|
|
|
// 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:
|
|
SharedEngineThread(SharedEngine* engine,
|
|
std::function<void(SharedEngineIsolate*)> callback)
|
|
: Thread(Options("SharedEngineThread")),
|
|
engine_(engine),
|
|
callback_(callback) {}
|
|
|
|
void Run() override {
|
|
SharedEngineIsolate isolate(engine_);
|
|
callback_(&isolate);
|
|
}
|
|
|
|
private:
|
|
SharedEngine* engine_;
|
|
std::function<void(SharedEngineIsolate*)> callback_;
|
|
};
|
|
|
|
namespace {
|
|
|
|
ZoneBuffer* BuildReturnConstantModule(Zone* zone, int constant) {
|
|
TestSignatures sigs;
|
|
ZoneBuffer* buffer = zone->New<ZoneBuffer>(zone);
|
|
WasmModuleBuilder* builder = zone->New<WasmModuleBuilder>(zone);
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
f->builder()->AddExport(CStrVector("main"), f);
|
|
byte code[] = {WASM_I32V_2(constant)};
|
|
f->EmitCode(code, sizeof(code));
|
|
f->Emit(kExprEnd);
|
|
builder->WriteTo(buffer);
|
|
return buffer;
|
|
}
|
|
|
|
class MockInstantiationResolver : public InstantiationResultResolver {
|
|
public:
|
|
explicit MockInstantiationResolver(Handle<Object>* out_instance)
|
|
: out_instance_(out_instance) {}
|
|
void OnInstantiationSucceeded(Handle<WasmInstanceObject> result) override {
|
|
*out_instance_->location() = result->ptr();
|
|
}
|
|
void OnInstantiationFailed(Handle<Object> error_reason) override {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
private:
|
|
Handle<Object>* out_instance_;
|
|
};
|
|
|
|
class MockCompilationResolver : public CompilationResultResolver {
|
|
public:
|
|
MockCompilationResolver(SharedEngineIsolate* isolate,
|
|
Handle<Object>* out_instance)
|
|
: isolate_(isolate), out_instance_(out_instance) {}
|
|
void OnCompilationSucceeded(Handle<WasmModuleObject> result) override {
|
|
isolate_->isolate()->wasm_engine()->AsyncInstantiate(
|
|
isolate_->isolate(),
|
|
std::make_unique<MockInstantiationResolver>(out_instance_), result, {});
|
|
}
|
|
void OnCompilationFailed(Handle<Object> error_reason) override {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
private:
|
|
SharedEngineIsolate* isolate_;
|
|
Handle<Object>* out_instance_;
|
|
};
|
|
|
|
void PumpMessageLoop(SharedEngineIsolate* isolate) {
|
|
v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(),
|
|
isolate->v8_isolate(),
|
|
platform::MessageLoopBehavior::kWaitForWork);
|
|
isolate->isolate()->default_microtask_queue()->RunMicrotasks(
|
|
isolate->isolate());
|
|
}
|
|
|
|
Handle<WasmInstanceObject> CompileAndInstantiateAsync(
|
|
SharedEngineIsolate* isolate, ZoneBuffer* buffer) {
|
|
Handle<Object> maybe_instance = handle(Smi::zero(), isolate->isolate());
|
|
auto enabled_features = WasmFeatures::FromIsolate(isolate->isolate());
|
|
constexpr const char* kAPIMethodName = "Test.CompileAndInstantiateAsync";
|
|
isolate->isolate()->wasm_engine()->AsyncCompile(
|
|
isolate->isolate(), enabled_features,
|
|
std::make_unique<MockCompilationResolver>(isolate, &maybe_instance),
|
|
ModuleWireBytes(buffer->begin(), buffer->end()), true, kAPIMethodName);
|
|
while (!maybe_instance->IsWasmInstanceObject()) PumpMessageLoop(isolate);
|
|
Handle<WasmInstanceObject> instance =
|
|
Handle<WasmInstanceObject>::cast(maybe_instance);
|
|
return instance;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(SharedEngineUseCount) {
|
|
SharedEngine engine;
|
|
CHECK_EQ(0, engine.NumberOfExportedEngineUses());
|
|
{
|
|
SharedEngineIsolate isolate(&engine);
|
|
CHECK_EQ(1, engine.NumberOfExportedEngineUses());
|
|
}
|
|
CHECK_EQ(0, engine.NumberOfExportedEngineUses());
|
|
{
|
|
SharedEngineIsolate isolate1(&engine);
|
|
CHECK_EQ(1, engine.NumberOfExportedEngineUses());
|
|
SharedEngineIsolate isolate2(&engine);
|
|
CHECK_EQ(2, engine.NumberOfExportedEngineUses());
|
|
}
|
|
CHECK_EQ(0, engine.NumberOfExportedEngineUses());
|
|
}
|
|
|
|
TEST(SharedEngineRunSeparated) {
|
|
SharedEngine engine;
|
|
{
|
|
SharedEngineIsolate isolate(&engine);
|
|
HandleScope scope(isolate.isolate());
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
|
|
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
|
|
CHECK_EQ(23, isolate.Run(instance));
|
|
}
|
|
{
|
|
SharedEngineIsolate isolate(&engine);
|
|
HandleScope scope(isolate.isolate());
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 42);
|
|
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
|
|
CHECK_EQ(42, isolate.Run(instance));
|
|
}
|
|
}
|
|
|
|
TEST(SharedEngineRunImported) {
|
|
SharedEngine engine;
|
|
SharedModule module;
|
|
{
|
|
SharedEngineIsolate isolate(&engine);
|
|
HandleScope scope(isolate.isolate());
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
|
|
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
|
|
module = isolate.ExportInstance(instance);
|
|
CHECK_EQ(23, isolate.Run(instance));
|
|
}
|
|
{
|
|
SharedEngineIsolate isolate(&engine);
|
|
HandleScope scope(isolate.isolate());
|
|
Handle<WasmInstanceObject> instance = isolate.ImportInstance(module);
|
|
CHECK_EQ(23, isolate.Run(instance));
|
|
}
|
|
}
|
|
|
|
TEST(SharedEngineRunThreadedBuildingSync) {
|
|
SharedEngine engine;
|
|
SharedEngineThread thread1(&engine, [](SharedEngineIsolate* isolate) {
|
|
HandleScope scope(isolate->isolate());
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 23);
|
|
Handle<WasmInstanceObject> instance =
|
|
isolate->CompileAndInstantiate(buffer);
|
|
CHECK_EQ(23, isolate->Run(instance));
|
|
});
|
|
SharedEngineThread thread2(&engine, [](SharedEngineIsolate* isolate) {
|
|
HandleScope scope(isolate->isolate());
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 42);
|
|
Handle<WasmInstanceObject> instance =
|
|
isolate->CompileAndInstantiate(buffer);
|
|
CHECK_EQ(42, isolate->Run(instance));
|
|
});
|
|
CHECK(thread1.Start());
|
|
CHECK(thread2.Start());
|
|
thread1.Join();
|
|
thread2.Join();
|
|
}
|
|
|
|
TEST(SharedEngineRunThreadedBuildingAsync) {
|
|
SharedEngine engine;
|
|
SharedEngineThread thread1(&engine, [](SharedEngineIsolate* isolate) {
|
|
HandleScope scope(isolate->isolate());
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 23);
|
|
Handle<WasmInstanceObject> instance =
|
|
CompileAndInstantiateAsync(isolate, buffer);
|
|
CHECK_EQ(23, isolate->Run(instance));
|
|
});
|
|
SharedEngineThread thread2(&engine, [](SharedEngineIsolate* isolate) {
|
|
HandleScope scope(isolate->isolate());
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate->zone(), 42);
|
|
Handle<WasmInstanceObject> instance =
|
|
CompileAndInstantiateAsync(isolate, buffer);
|
|
CHECK_EQ(42, isolate->Run(instance));
|
|
});
|
|
CHECK(thread1.Start());
|
|
CHECK(thread2.Start());
|
|
thread1.Join();
|
|
thread2.Join();
|
|
}
|
|
|
|
TEST(SharedEngineRunThreadedExecution) {
|
|
SharedEngine engine;
|
|
SharedModule module;
|
|
{
|
|
SharedEngineIsolate isolate(&engine);
|
|
HandleScope scope(isolate.isolate());
|
|
ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
|
|
Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
|
|
module = isolate.ExportInstance(instance);
|
|
}
|
|
SharedEngineThread thread1(&engine, [module](SharedEngineIsolate* isolate) {
|
|
HandleScope scope(isolate->isolate());
|
|
Handle<WasmInstanceObject> instance = isolate->ImportInstance(module);
|
|
CHECK_EQ(23, isolate->Run(instance));
|
|
});
|
|
SharedEngineThread thread2(&engine, [module](SharedEngineIsolate* isolate) {
|
|
HandleScope scope(isolate->isolate());
|
|
Handle<WasmInstanceObject> instance = isolate->ImportInstance(module);
|
|
CHECK_EQ(23, isolate->Run(instance));
|
|
});
|
|
CHECK(thread1.Start());
|
|
CHECK(thread2.Start());
|
|
thread1.Join();
|
|
thread2.Join();
|
|
}
|
|
|
|
TEST(SharedEngineRunThreadedTierUp) {
|
|
SharedEngine engine;
|
|
SharedModule module;
|
|
{
|
|
SharedEngineIsolate isolate(&engine);
|
|
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) {
|
|
threads.emplace_back(&engine, [module](SharedEngineIsolate* isolate) {
|
|
constexpr int kNumberOfIterations = 100;
|
|
HandleScope scope(isolate->isolate());
|
|
Handle<WasmInstanceObject> instance = isolate->ImportInstance(module);
|
|
for (int j = 0; j < kNumberOfIterations; ++j) {
|
|
CHECK_EQ(23, isolate->Run(instance));
|
|
}
|
|
});
|
|
}
|
|
threads.emplace_back(&engine, [module](SharedEngineIsolate* isolate) {
|
|
HandleScope scope(isolate->isolate());
|
|
Handle<WasmInstanceObject> instance = isolate->ImportInstance(module);
|
|
WasmFeatures detected = WasmFeatures::None();
|
|
WasmCompilationUnit::CompileWasmFunction(
|
|
isolate->isolate(), module.get(), &detected,
|
|
&module->module()->functions[0], ExecutionTier::kTurbofan);
|
|
CHECK_EQ(23, isolate->Run(instance));
|
|
});
|
|
for (auto& thread : threads) CHECK(thread.Start());
|
|
for (auto& thread : threads) thread.Join();
|
|
}
|
|
|
|
} // namespace test_wasm_shared_engine
|
|
} // namespace wasm
|
|
} // namespace internal
|
|
} // namespace v8
|