Commit 8a95da24 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm] Reimplement WebAssembly.instantiate without desugaring

At the moment, WebAssembly.instantiate(bytes) is implemented by
desugaring it to WebAssembly.compile(bytes).then(WebAssembly.instantiate).
The problem is that the {then} in this snippet is observable. With this
CL I introduce a CompilationResultResolver which allows to do the
desugaring internally and thereby make the {then} unobservable.
Unfortunately the result of WebAssembly.instantiate(bytes) is different
than the result of WebAssembly.instantiate(module). Therefore I also
introduced an InstantiationResultResolver for symmetry with
WebAssembly.compile.

R=mstarzinger@chromium.org
Bug: chromium:837417

Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: I2d98e03d65f2ada19041d5a9e2df5da91b24ccca
Reviewed-on: https://chromium-review.googlesource.com/1059783
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53347}
parent bedcef5c
...@@ -7516,6 +7516,38 @@ MaybeLocal<WasmCompiledModule> WasmCompiledModule::Compile(Isolate* isolate, ...@@ -7516,6 +7516,38 @@ MaybeLocal<WasmCompiledModule> WasmCompiledModule::Compile(Isolate* isolate,
Utils::ToLocal(maybe_compiled.ToHandleChecked())); Utils::ToLocal(maybe_compiled.ToHandleChecked()));
} }
// Resolves the result of streaming compilation.
// TODO(ahaas): Refactor the streaming compilation API so that this class can
// move to wasm-js.cc.
class AsyncCompilationResolver : public i::wasm::CompilationResultResolver {
public:
AsyncCompilationResolver(Isolate* isolate, Handle<Promise> promise)
: promise_(
reinterpret_cast<i::Isolate*>(isolate)->global_handles()->Create(
*Utils::OpenHandle(*promise))) {}
~AsyncCompilationResolver() {
i::GlobalHandles::Destroy(i::Handle<i::Object>::cast(promise_).location());
}
void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result) override {
i::MaybeHandle<i::Object> promise_result =
i::JSPromise::Resolve(promise_, result);
CHECK_EQ(promise_result.is_null(),
promise_->GetIsolate()->has_pending_exception());
}
void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
i::MaybeHandle<i::Object> promise_result =
i::JSPromise::Reject(promise_, error_reason);
CHECK_EQ(promise_result.is_null(),
promise_->GetIsolate()->has_pending_exception());
}
private:
i::Handle<i::JSPromise> promise_;
};
WasmModuleObjectBuilderStreaming::WasmModuleObjectBuilderStreaming( WasmModuleObjectBuilderStreaming::WasmModuleObjectBuilderStreaming(
Isolate* isolate) Isolate* isolate)
: isolate_(isolate) { : isolate_(isolate) {
...@@ -7524,10 +7556,10 @@ WasmModuleObjectBuilderStreaming::WasmModuleObjectBuilderStreaming( ...@@ -7524,10 +7556,10 @@ WasmModuleObjectBuilderStreaming::WasmModuleObjectBuilderStreaming(
Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked(); Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
promise_.Reset(isolate, resolver->GetPromise()); promise_.Reset(isolate, resolver->GetPromise());
i::Handle<i::JSPromise> promise = Utils::OpenHandle(*GetPromise());
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
streaming_decoder_ = i_isolate->wasm_engine()->StartStreamingCompilation( streaming_decoder_ = i_isolate->wasm_engine()->StartStreamingCompilation(
i_isolate, handle(i_isolate->context()), promise); i_isolate, handle(i_isolate->context()),
base::make_unique<AsyncCompilationResolver>(isolate, GetPromise()));
} }
Local<Promise> WasmModuleObjectBuilderStreaming::GetPromise() { Local<Promise> WasmModuleObjectBuilderStreaming::GetPromise() {
......
...@@ -2717,21 +2717,21 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) { ...@@ -2717,21 +2717,21 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
} }
} }
AsyncCompileJob::AsyncCompileJob(Isolate* isolate, AsyncCompileJob::AsyncCompileJob(
std::unique_ptr<byte[]> bytes_copy, Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
size_t length, Handle<Context> context, Handle<Context> context,
Handle<JSPromise> promise) std::unique_ptr<CompilationResultResolver> resolver)
: isolate_(isolate), : isolate_(isolate),
async_counters_(isolate->async_counters()), async_counters_(isolate->async_counters()),
bytes_copy_(std::move(bytes_copy)), bytes_copy_(std::move(bytes_copy)),
wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length) { wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
resolver_(std::move(resolver)) {
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
v8::Platform* platform = V8::GetCurrentPlatform(); v8::Platform* platform = V8::GetCurrentPlatform();
foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate); foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate);
// The handles for the context and promise must be deferred. // The handles for the context and promise must be deferred.
DeferredHandleScope deferred(isolate); DeferredHandleScope deferred(isolate);
context_ = Handle<Context>(*context); context_ = Handle<Context>(*context);
module_promise_ = Handle<JSPromise>(*promise);
deferred_handles_.push_back(deferred.Detach()); deferred_handles_.push_back(deferred.Detach());
} }
...@@ -2861,15 +2861,11 @@ void AsyncCompileJob::AsyncCompileFailed(Handle<Object> error_reason) { ...@@ -2861,15 +2861,11 @@ void AsyncCompileJob::AsyncCompileFailed(Handle<Object> error_reason) {
// {job} keeps the {this} pointer alive. // {job} keeps the {this} pointer alive.
std::shared_ptr<AsyncCompileJob> job = std::shared_ptr<AsyncCompileJob> job =
isolate_->wasm_engine()->RemoveCompileJob(this); isolate_->wasm_engine()->RemoveCompileJob(this);
MaybeHandle<Object> promise_result = resolver_->OnCompilationFailed(error_reason);
JSPromise::Reject(module_promise_, error_reason);
CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
} }
void AsyncCompileJob::AsyncCompileSucceeded(Handle<Object> result) { void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
MaybeHandle<Object> promise_result = resolver_->OnCompilationSucceeded(result);
JSPromise::Resolve(module_promise_, result);
CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
} }
// A closure to run a compilation step (either as foreground or background // A closure to run a compilation step (either as foreground or background
......
...@@ -27,6 +27,7 @@ class Vector; ...@@ -27,6 +27,7 @@ class Vector;
namespace wasm { namespace wasm {
class CompilationResultResolver;
class CompilationState; class CompilationState;
class ErrorThrower; class ErrorThrower;
class ModuleCompiler; class ModuleCompiler;
...@@ -85,7 +86,7 @@ class AsyncCompileJob { ...@@ -85,7 +86,7 @@ class AsyncCompileJob {
public: public:
explicit AsyncCompileJob(Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, explicit AsyncCompileJob(Isolate* isolate, std::unique_ptr<byte[]> bytes_copy,
size_t length, Handle<Context> context, size_t length, Handle<Context> context,
Handle<JSPromise> promise); std::unique_ptr<CompilationResultResolver> resolver);
void Start(); void Start();
...@@ -118,7 +119,7 @@ class AsyncCompileJob { ...@@ -118,7 +119,7 @@ class AsyncCompileJob {
void AsyncCompileFailed(Handle<Object> error_reason); void AsyncCompileFailed(Handle<Object> error_reason);
void AsyncCompileSucceeded(Handle<Object> result); void AsyncCompileSucceeded(Handle<WasmModuleObject> result);
void StartForegroundTask(); void StartForegroundTask();
...@@ -148,7 +149,7 @@ class AsyncCompileJob { ...@@ -148,7 +149,7 @@ class AsyncCompileJob {
std::unique_ptr<byte[]> bytes_copy_; std::unique_ptr<byte[]> bytes_copy_;
ModuleWireBytes wire_bytes_; ModuleWireBytes wire_bytes_;
Handle<Context> context_; Handle<Context> context_;
Handle<JSPromise> module_promise_; std::unique_ptr<CompilationResultResolver> resolver_;
std::unique_ptr<WasmModule> module_; std::unique_ptr<WasmModule> module_;
std::vector<DeferredHandles*> deferred_handles_; std::vector<DeferredHandles*> deferred_handles_;
......
...@@ -60,24 +60,23 @@ MaybeHandle<WasmInstanceObject> WasmEngine::SyncInstantiate( ...@@ -60,24 +60,23 @@ MaybeHandle<WasmInstanceObject> WasmEngine::SyncInstantiate(
memory); memory);
} }
void WasmEngine::AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise, void WasmEngine::AsyncInstantiate(
Handle<WasmModuleObject> module_object, Isolate* isolate, std::unique_ptr<InstantiationResultResolver> resolver,
MaybeHandle<JSReceiver> imports) { Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports) {
ErrorThrower thrower(isolate, nullptr); ErrorThrower thrower(isolate, nullptr);
MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate( MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null()); isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null());
if (thrower.error()) { if (thrower.error()) {
MaybeHandle<Object> result = JSPromise::Reject(promise, thrower.Reify()); resolver->OnInstantiationFailed(thrower.Reify());
CHECK_EQ(result.is_null(), isolate->has_pending_exception());
return; return;
} }
Handle<WasmInstanceObject> instance = instance_object.ToHandleChecked(); Handle<WasmInstanceObject> instance = instance_object.ToHandleChecked();
MaybeHandle<Object> result = JSPromise::Resolve(promise, instance); resolver->OnInstantiationSucceeded(instance);
CHECK_EQ(result.is_null(), isolate->has_pending_exception());
} }
void WasmEngine::AsyncCompile(Isolate* isolate, Handle<JSPromise> promise, void WasmEngine::AsyncCompile(
const ModuleWireBytes& bytes, bool is_shared) { Isolate* isolate, std::unique_ptr<CompilationResultResolver> resolver,
const ModuleWireBytes& bytes, bool is_shared) {
if (!FLAG_wasm_async_compilation) { if (!FLAG_wasm_async_compilation) {
// Asynchronous compilation disabled; fall back on synchronous compilation. // Asynchronous compilation disabled; fall back on synchronous compilation.
ErrorThrower thrower(isolate, "WasmCompile"); ErrorThrower thrower(isolate, "WasmCompile");
...@@ -94,21 +93,18 @@ void WasmEngine::AsyncCompile(Isolate* isolate, Handle<JSPromise> promise, ...@@ -94,21 +93,18 @@ void WasmEngine::AsyncCompile(Isolate* isolate, Handle<JSPromise> promise,
module_object = SyncCompile(isolate, &thrower, bytes); module_object = SyncCompile(isolate, &thrower, bytes);
} }
if (thrower.error()) { if (thrower.error()) {
MaybeHandle<Object> result = JSPromise::Reject(promise, thrower.Reify()); resolver->OnCompilationFailed(thrower.Reify());
CHECK_EQ(result.is_null(), isolate->has_pending_exception());
return; return;
} }
Handle<WasmModuleObject> module = module_object.ToHandleChecked(); Handle<WasmModuleObject> module = module_object.ToHandleChecked();
MaybeHandle<Object> result = JSPromise::Resolve(promise, module); resolver->OnCompilationSucceeded(module);
CHECK_EQ(result.is_null(), isolate->has_pending_exception());
return; return;
} }
if (FLAG_wasm_test_streaming) { if (FLAG_wasm_test_streaming) {
std::shared_ptr<StreamingDecoder> streaming_decoder = std::shared_ptr<StreamingDecoder> streaming_decoder =
isolate->wasm_engine() isolate->wasm_engine()->StartStreamingCompilation(
->StartStreamingCompilation(isolate, handle(isolate->context()), isolate, handle(isolate->context()), std::move(resolver));
promise);
streaming_decoder->OnBytesReceived(bytes.module_bytes()); streaming_decoder->OnBytesReceived(bytes.module_bytes());
streaming_decoder->Finish(); streaming_decoder->Finish();
return; return;
...@@ -120,14 +116,16 @@ void WasmEngine::AsyncCompile(Isolate* isolate, Handle<JSPromise> promise, ...@@ -120,14 +116,16 @@ void WasmEngine::AsyncCompile(Isolate* isolate, Handle<JSPromise> promise,
AsyncCompileJob* job = AsyncCompileJob* job =
CreateAsyncCompileJob(isolate, std::move(copy), bytes.length(), CreateAsyncCompileJob(isolate, std::move(copy), bytes.length(),
handle(isolate->context()), promise); handle(isolate->context()), std::move(resolver));
job->Start(); job->Start();
} }
std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation( std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
Isolate* isolate, Handle<Context> context, Handle<JSPromise> promise) { Isolate* isolate, Handle<Context> context,
AsyncCompileJob* job = CreateAsyncCompileJob( std::unique_ptr<CompilationResultResolver> resolver) {
isolate, std::unique_ptr<byte[]>(nullptr), 0, context, promise); AsyncCompileJob* job =
CreateAsyncCompileJob(isolate, std::unique_ptr<byte[]>(nullptr), 0,
context, std::move(resolver));
return job->CreateStreamingDecoder(); return job->CreateStreamingDecoder();
} }
...@@ -141,9 +139,10 @@ void WasmEngine::Unregister(CancelableTaskManager* task_manager) { ...@@ -141,9 +139,10 @@ void WasmEngine::Unregister(CancelableTaskManager* task_manager) {
AsyncCompileJob* WasmEngine::CreateAsyncCompileJob( AsyncCompileJob* WasmEngine::CreateAsyncCompileJob(
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length, Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
Handle<Context> context, Handle<JSPromise> promise) { Handle<Context> context,
AsyncCompileJob* job = new AsyncCompileJob(isolate, std::move(bytes_copy), std::unique_ptr<CompilationResultResolver> resolver) {
length, context, promise); AsyncCompileJob* job = new AsyncCompileJob(
isolate, std::move(bytes_copy), length, context, std::move(resolver));
// Pass ownership to the unique_ptr in {jobs_}. // Pass ownership to the unique_ptr in {jobs_}.
jobs_[job] = std::unique_ptr<AsyncCompileJob>(job); jobs_[job] = std::unique_ptr<AsyncCompileJob>(job);
return job; return job;
......
...@@ -21,6 +21,20 @@ namespace wasm { ...@@ -21,6 +21,20 @@ namespace wasm {
class ErrorThrower; class ErrorThrower;
struct ModuleWireBytes; struct ModuleWireBytes;
class V8_EXPORT_PRIVATE CompilationResultResolver {
public:
virtual void OnCompilationSucceeded(Handle<WasmModuleObject> result) = 0;
virtual void OnCompilationFailed(Handle<Object> error_reason) = 0;
virtual ~CompilationResultResolver() {}
};
class V8_EXPORT_PRIVATE InstantiationResultResolver {
public:
virtual void OnInstantiationSucceeded(Handle<WasmInstanceObject> result) = 0;
virtual void OnInstantiationFailed(Handle<Object> error_reason) = 0;
virtual ~InstantiationResultResolver() {}
};
// The central data structure that represents an engine instance capable of // The central data structure that represents an engine instance capable of
// loading, instantiating, and executing WASM code. // loading, instantiating, and executing WASM code.
class V8_EXPORT_PRIVATE WasmEngine { class V8_EXPORT_PRIVATE WasmEngine {
...@@ -54,20 +68,22 @@ class V8_EXPORT_PRIVATE WasmEngine { ...@@ -54,20 +68,22 @@ class V8_EXPORT_PRIVATE WasmEngine {
MaybeHandle<JSArrayBuffer> memory); MaybeHandle<JSArrayBuffer> memory);
// Begin an asynchronous compilation of the given bytes that represent an // Begin an asynchronous compilation of the given bytes that represent an
// encoded WASM module, placing the result in the supplied {promise}. // encoded WASM module.
// The {is_shared} flag indicates if the bytes backing the module could // The {is_shared} flag indicates if the bytes backing the module could
// be shared across threads, i.e. could be concurrently modified. // be shared across threads, i.e. could be concurrently modified.
void AsyncCompile(Isolate* isolate, Handle<JSPromise> promise, void AsyncCompile(Isolate* isolate,
std::unique_ptr<CompilationResultResolver> resolver,
const ModuleWireBytes& bytes, bool is_shared); const ModuleWireBytes& bytes, bool is_shared);
// Begin an asynchronous instantiation of the given WASM module, placing the // Begin an asynchronous instantiation of the given WASM module.
// result in the supplied {promise}. void AsyncInstantiate(Isolate* isolate,
void AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise, std::unique_ptr<InstantiationResultResolver> resolver,
Handle<WasmModuleObject> module_object, Handle<WasmModuleObject> module_object,
MaybeHandle<JSReceiver> imports); MaybeHandle<JSReceiver> imports);
std::shared_ptr<StreamingDecoder> StartStreamingCompilation( std::shared_ptr<StreamingDecoder> StartStreamingCompilation(
Isolate* isolate, Handle<Context> context, Handle<JSPromise> promise); Isolate* isolate, Handle<Context> context,
std::unique_ptr<CompilationResultResolver> resolver);
WasmCodeManager* code_manager() const { return code_manager_.get(); } WasmCodeManager* code_manager() const { return code_manager_.get(); }
...@@ -94,10 +110,10 @@ class V8_EXPORT_PRIVATE WasmEngine { ...@@ -94,10 +110,10 @@ class V8_EXPORT_PRIVATE WasmEngine {
void TearDown(); void TearDown();
private: private:
AsyncCompileJob* CreateAsyncCompileJob(Isolate* isolate, AsyncCompileJob* CreateAsyncCompileJob(
std::unique_ptr<byte[]> bytes_copy, Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
size_t length, Handle<Context> context, Handle<Context> context,
Handle<JSPromise> promise); std::unique_ptr<CompilationResultResolver> resolver);
// We use an AsyncCompileJob as the key for itself so that we can delete the // We use an AsyncCompileJob as the key for itself so that we can delete the
// job from the map when it is finished. // job from the map when it is finished.
......
This diff is collapsed.
...@@ -82,24 +82,39 @@ class MockPlatform final : public TestPlatform { ...@@ -82,24 +82,39 @@ class MockPlatform final : public TestPlatform {
namespace { namespace {
enum class CompilationState {
kPending,
kFinished,
kFailed,
};
class TestResolver : public i::wasm::CompilationResultResolver {
public:
explicit TestResolver(CompilationState* state) : state_(state) {}
void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> module) override {
*state_ = CompilationState::kFinished;
}
void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
*state_ = CompilationState::kFailed;
}
private:
CompilationState* state_;
};
class StreamTester { class StreamTester {
public: public:
StreamTester() : zone_(&allocator_, "StreamTester") { StreamTester() : zone_(&allocator_, "StreamTester") {
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
i::Isolate* i_isolate = CcTest::i_isolate(); i::Isolate* i_isolate = CcTest::i_isolate();
// Create the promise for the streaming compilation.
v8::Local<v8::Context> context = isolate->GetCurrentContext(); v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<Promise::Resolver> resolver;
CHECK(Promise::Resolver::New(context).ToLocal(&resolver));
CHECK(!i_isolate->has_scheduled_exception());
promise_ = resolver->GetPromise();
i::Handle<i::JSPromise> i_promise = v8::Utils::OpenHandle(*promise_); stream_ = i_isolate->wasm_engine()->StartStreamingCompilation(
i_isolate, v8::Utils::OpenHandle(*context),
stream_ = i_isolate->wasm_engine() base::make_unique<TestResolver>(&state_));
->StartStreamingCompilation(
i_isolate, v8::Utils::OpenHandle(*context), i_promise);
} }
std::shared_ptr<StreamingDecoder> stream() { return stream_; } std::shared_ptr<StreamingDecoder> stream() { return stream_; }
...@@ -109,15 +124,11 @@ class StreamTester { ...@@ -109,15 +124,11 @@ class StreamTester {
static_cast<MockPlatform*>(i::V8::GetCurrentPlatform())->ExecuteTasks(); static_cast<MockPlatform*>(i::V8::GetCurrentPlatform())->ExecuteTasks();
} }
bool IsPromiseFulfilled() { bool IsPromiseFulfilled() { return state_ == CompilationState::kFinished; }
return promise_->State() == v8::Promise::kFulfilled;
}
bool IsPromiseRejected() { bool IsPromiseRejected() { return state_ == CompilationState::kFailed; }
return promise_->State() == v8::Promise::kRejected;
}
bool IsPromisePending() { return promise_->State() == v8::Promise::kPending; } bool IsPromisePending() { return state_ == CompilationState::kPending; }
void OnBytesReceived(const uint8_t* start, size_t length) { void OnBytesReceived(const uint8_t* start, size_t length) {
stream_->OnBytesReceived(Vector<const uint8_t>(start, length)); stream_->OnBytesReceived(Vector<const uint8_t>(start, length));
...@@ -130,7 +141,7 @@ class StreamTester { ...@@ -130,7 +141,7 @@ class StreamTester {
private: private:
AccountingAllocator allocator_; AccountingAllocator allocator_;
Zone zone_; Zone zone_;
v8::Local<v8::Promise> promise_; CompilationState state_ = CompilationState::kPending;
std::shared_ptr<StreamingDecoder> stream_; std::shared_ptr<StreamingDecoder> stream_;
}; };
} // namespace } // namespace
......
...@@ -25,42 +25,24 @@ class WasmModuleObject; ...@@ -25,42 +25,24 @@ class WasmModuleObject;
namespace wasm { namespace wasm {
namespace fuzzer { namespace fuzzer {
#define ASSIGN(type, var, expr) \ class AsyncFuzzerResolver : public i::wasm::CompilationResultResolver {
v8::Local<type> var; \ public:
do { \ AsyncFuzzerResolver(i::Isolate* isolate, bool* done)
if (!expr.ToLocal(&var)) { \ : isolate_(isolate), done_(done) {}
DCHECK(i_isolate->has_scheduled_exception()); \
return 0; \ void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> module) override {
} else { \ *done_ = true;
DCHECK(!i_isolate->has_scheduled_exception()); \ InterpretAndExecuteModule(isolate_, module);
} \ }
} while (false)
namespace {
// We need this helper function because we cannot use
// Handle<WasmModuleObject>::cast here. To use this function we would have to
// mark it with V8_EXPORT_PRIVATE, which is quite ugly in this case.
Handle<WasmModuleObject> ToWasmModuleObjectUnchecked(Handle<Object> that) {
return handle(reinterpret_cast<WasmModuleObject*>(*that));
}
}
void InstantiateCallback(const FunctionCallbackInfo<Value>& args) {
DCHECK_GE(args.Length(), 1);
v8::Isolate* isolate = args.GetIsolate();
MicrotasksScope does_not_run_microtasks(
isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::HandleScope scope(isolate);
Local<v8::Value> module = args[0];
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
*done_ = true;
}
Handle<WasmModuleObject> module_obj = private:
ToWasmModuleObjectUnchecked(Utils::OpenHandle(v8::Object::Cast(*module))); i::Isolate* isolate_;
InterpretAndExecuteModule(i_isolate, module_obj); bool* done_;
} };
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FlagScope<bool> turn_on_async_compile( FlagScope<bool> turn_on_async_compile(
...@@ -85,32 +67,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ...@@ -85,32 +67,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
TryCatch try_catch(isolate); TryCatch try_catch(isolate);
testing::SetupIsolateForWasmModule(i_isolate); testing::SetupIsolateForWasmModule(i_isolate);
// Get the promise for async compilation. bool done = false;
ASSIGN(Promise::Resolver, resolver, i_isolate->wasm_engine()->AsyncCompile(
Promise::Resolver::New(support->GetContext())); i_isolate, base::make_unique<AsyncFuzzerResolver>(i_isolate, &done),
Local<Promise> promise = resolver->GetPromise(); ModuleWireBytes(data, data + size), false);
i_isolate->wasm_engine()->AsyncCompile(i_isolate, Utils::OpenHandle(*promise),
ModuleWireBytes(data, data + size),
false);
ASSIGN(Function, instantiate_impl,
Function::New(support->GetContext(), &InstantiateCallback,
Undefined(isolate)));
ASSIGN(Promise, result,
promise->Then(support->GetContext(), instantiate_impl));
// Wait for the promise to resolve. // Wait for the promise to resolve.
while (result->State() == Promise::kPending) { while (!done) {
support->PumpMessageLoop(platform::MessageLoopBehavior::kWaitForWork); support->PumpMessageLoop(platform::MessageLoopBehavior::kWaitForWork);
isolate->RunMicrotasks(); isolate->RunMicrotasks();
} }
return 0; return 0;
} }
#undef ASSIGN
} // namespace fuzzer } // namespace fuzzer
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
......
...@@ -8,16 +8,11 @@ load('test/mjsunit/wasm/wasm-module-builder.js'); ...@@ -8,16 +8,11 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
const builder = new WasmModuleBuilder(); const builder = new WasmModuleBuilder();
builder.addMemory(16, 32); builder.addMemory(16, 32);
builder.addFunction("test", kSig_i_v).addBody([ builder.addFunction("test", kSig_i_v).addBody([
kExprI32Const, 12, // i32.const 0 kExprI32Const, 12, // i32.const 12
]); ]);
WebAssembly.Module.prototype.then = resolve => resolve( WebAssembly.Module.prototype.then = resolve => {
String.fromCharCode(null, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41)); assertUnreachable();
};
// WebAssembly.instantiate should not actually throw a TypeError in this case. WebAssembly.instantiate(builder.toBuffer());
// However, this is a workaround for
assertPromiseResult(
WebAssembly.instantiate(builder.toBuffer()), assertUnreachable,
exception => {
assertInstanceof(exception, TypeError);
});
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