Revert "[wasm] Implement the new API for WebAssembly.instantiateStreaming"
This reverts commit b556c9eaa6
.
Reason for revert: Flakes in layout tests: https://crbug.com/870187
Original change's description:
> [wasm] Implement the new API for WebAssembly.instantiateStreaming
>
> This is the second V8 CL to refactor WebAssembly.instantiateStreaming to
> make it spec compliant again. The design doc where the whole change is
> discussed is available in the tracking bug. The tracking bug also
> references prototype implementations of the whole change, which includes
> the changes in this CL.
>
> R=mstarzinger@chromium.org
>
> Bug: chromium:860637
> Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
> Change-Id: I776c0f24959ab5663727d3dfee0248a9b0642a42
> Reviewed-on: https://chromium-review.googlesource.com/1143187
> Commit-Queue: Andreas Haas <ahaas@chromium.org>
> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#54834}
TBR=mstarzinger@chromium.org,ahaas@chromium.org
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: chromium:860637
Change-Id: Icbf2603143068a49c61de162aa7185a753703e5d
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/1160261
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54872}
This commit is contained in:
parent
05c8d57a72
commit
fea9300d9f
38
src/api.cc
38
src/api.cc
@ -7778,23 +7778,55 @@ class AsyncCompilationResolver : public i::wasm::CompilationResultResolver {
|
||||
};
|
||||
|
||||
WasmModuleObjectBuilderStreaming::WasmModuleObjectBuilderStreaming(
|
||||
Isolate* isolate) {
|
||||
USE(isolate_);
|
||||
Isolate* isolate)
|
||||
: isolate_(isolate) {
|
||||
MaybeLocal<Promise::Resolver> maybe_resolver =
|
||||
Promise::Resolver::New(isolate->GetCurrentContext());
|
||||
Local<Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
|
||||
promise_.Reset(isolate, resolver->GetPromise());
|
||||
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
streaming_decoder_ = i_isolate->wasm_engine()->StartStreamingCompilation(
|
||||
i_isolate, handle(i_isolate->context(), i_isolate),
|
||||
base::make_unique<AsyncCompilationResolver>(isolate, GetPromise()));
|
||||
}
|
||||
|
||||
Local<Promise> WasmModuleObjectBuilderStreaming::GetPromise() { return {}; }
|
||||
Local<Promise> WasmModuleObjectBuilderStreaming::GetPromise() {
|
||||
return promise_.Get(isolate_);
|
||||
}
|
||||
|
||||
void WasmModuleObjectBuilderStreaming::OnBytesReceived(const uint8_t* bytes,
|
||||
size_t size) {
|
||||
streaming_decoder_->OnBytesReceived(i::Vector<const uint8_t>(bytes, size));
|
||||
}
|
||||
|
||||
void WasmModuleObjectBuilderStreaming::Finish() {
|
||||
streaming_decoder_->Finish();
|
||||
}
|
||||
|
||||
void WasmModuleObjectBuilderStreaming::Abort(MaybeLocal<Value> exception) {
|
||||
Local<Promise> promise = GetPromise();
|
||||
// The promise has already been resolved, e.g. because of a compilation
|
||||
// error.
|
||||
if (promise->State() != v8::Promise::kPending) return;
|
||||
streaming_decoder_->Abort();
|
||||
|
||||
// If no exception value is provided, we do not reject the promise. This can
|
||||
// happen when streaming compilation gets aborted when no script execution is
|
||||
// allowed anymore, e.g. when a browser tab gets refreshed.
|
||||
if (exception.IsEmpty()) return;
|
||||
|
||||
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
|
||||
i::HandleScope scope(i_isolate);
|
||||
Local<Context> context =
|
||||
Utils::ToLocal(handle(i_isolate->context(), i_isolate));
|
||||
auto maybe = resolver->Reject(context, exception.ToLocalChecked());
|
||||
CHECK_IMPLIES(!maybe.FromMaybe(false), i_isolate->has_scheduled_exception());
|
||||
}
|
||||
|
||||
WasmModuleObjectBuilderStreaming::~WasmModuleObjectBuilderStreaming() {
|
||||
promise_.Reset();
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -2095,7 +2095,7 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
|
||||
AsyncCompileJob::AsyncCompileJob(
|
||||
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
|
||||
Handle<Context> context,
|
||||
std::shared_ptr<CompilationResultResolver> resolver)
|
||||
std::unique_ptr<CompilationResultResolver> resolver)
|
||||
: isolate_(isolate),
|
||||
async_counters_(isolate->async_counters()),
|
||||
bytes_copy_(std::move(bytes_copy)),
|
||||
|
@ -79,7 +79,7 @@ class AsyncCompileJob {
|
||||
public:
|
||||
explicit AsyncCompileJob(Isolate* isolate, std::unique_ptr<byte[]> bytes_copy,
|
||||
size_t length, Handle<Context> context,
|
||||
std::shared_ptr<CompilationResultResolver> resolver);
|
||||
std::unique_ptr<CompilationResultResolver> resolver);
|
||||
~AsyncCompileJob();
|
||||
|
||||
void Start();
|
||||
@ -139,14 +139,14 @@ class AsyncCompileJob {
|
||||
|
||||
Isolate* isolate_;
|
||||
const std::shared_ptr<Counters> async_counters_;
|
||||
// Copy of the module wire bytes, moved into the {native_module_} on its
|
||||
// Copy of the module wire bytes, moved into the {native_module_} on it's
|
||||
// creation.
|
||||
std::unique_ptr<byte[]> bytes_copy_;
|
||||
// Reference to the wire bytes (hold in {bytes_copy_} or as part of
|
||||
// {native_module_}).
|
||||
ModuleWireBytes wire_bytes_;
|
||||
Handle<Context> native_context_;
|
||||
std::shared_ptr<CompilationResultResolver> resolver_;
|
||||
std::unique_ptr<CompilationResultResolver> resolver_;
|
||||
std::shared_ptr<const WasmModule> module_;
|
||||
|
||||
std::vector<DeferredHandles*> deferred_handles_;
|
||||
|
@ -83,10 +83,7 @@ void StreamingDecoder::Finish() {
|
||||
|
||||
void StreamingDecoder::Abort() {
|
||||
TRACE_STREAMING("Abort\n");
|
||||
if (ok()) {
|
||||
ok_ = false;
|
||||
processor_->OnAbort();
|
||||
}
|
||||
if (ok()) processor_->OnAbort();
|
||||
}
|
||||
|
||||
// An abstract class to share code among the states which decode VarInts. This
|
||||
|
@ -110,7 +110,7 @@ void WasmEngine::AsyncInstantiate(
|
||||
}
|
||||
|
||||
void WasmEngine::AsyncCompile(
|
||||
Isolate* isolate, std::shared_ptr<CompilationResultResolver> resolver,
|
||||
Isolate* isolate, std::unique_ptr<CompilationResultResolver> resolver,
|
||||
const ModuleWireBytes& bytes, bool is_shared) {
|
||||
if (!FLAG_wasm_async_compilation) {
|
||||
// Asynchronous compilation disabled; fall back on synchronous compilation.
|
||||
@ -156,7 +156,7 @@ void WasmEngine::AsyncCompile(
|
||||
|
||||
std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
|
||||
Isolate* isolate, Handle<Context> context,
|
||||
std::shared_ptr<CompilationResultResolver> resolver) {
|
||||
std::unique_ptr<CompilationResultResolver> resolver) {
|
||||
AsyncCompileJob* job =
|
||||
CreateAsyncCompileJob(isolate, std::unique_ptr<byte[]>(nullptr), 0,
|
||||
context, std::move(resolver));
|
||||
@ -210,7 +210,7 @@ CodeTracer* WasmEngine::GetCodeTracer() {
|
||||
AsyncCompileJob* WasmEngine::CreateAsyncCompileJob(
|
||||
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
|
||||
Handle<Context> context,
|
||||
std::shared_ptr<CompilationResultResolver> resolver) {
|
||||
std::unique_ptr<CompilationResultResolver> resolver) {
|
||||
AsyncCompileJob* job = new AsyncCompileJob(
|
||||
isolate, std::move(bytes_copy), length, context, std::move(resolver));
|
||||
// Pass ownership to the unique_ptr in {jobs_}.
|
||||
|
@ -75,7 +75,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
||||
// The {is_shared} flag indicates if the bytes backing the module could
|
||||
// be shared across threads, i.e. could be concurrently modified.
|
||||
void AsyncCompile(Isolate* isolate,
|
||||
std::shared_ptr<CompilationResultResolver> resolver,
|
||||
std::unique_ptr<CompilationResultResolver> resolver,
|
||||
const ModuleWireBytes& bytes, bool is_shared);
|
||||
|
||||
// Begin an asynchronous instantiation of the given WASM module.
|
||||
@ -86,7 +86,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
||||
|
||||
std::shared_ptr<StreamingDecoder> StartStreamingCompilation(
|
||||
Isolate* isolate, Handle<Context> context,
|
||||
std::shared_ptr<CompilationResultResolver> resolver);
|
||||
std::unique_ptr<CompilationResultResolver> resolver);
|
||||
|
||||
// Exports the sharable parts of the given module object so that they can be
|
||||
// transferred to a different Context/Isolate using the same engine.
|
||||
@ -142,7 +142,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
||||
AsyncCompileJob* CreateAsyncCompileJob(
|
||||
Isolate* isolate, std::unique_ptr<byte[]> bytes_copy, size_t length,
|
||||
Handle<Context> context,
|
||||
std::shared_ptr<CompilationResultResolver> resolver);
|
||||
std::unique_ptr<CompilationResultResolver> resolver);
|
||||
|
||||
std::unique_ptr<WasmCodeManager> code_manager_;
|
||||
WasmMemoryTracker memory_tracker_;
|
||||
|
@ -29,37 +29,11 @@ namespace v8 {
|
||||
|
||||
class WasmStreaming::WasmStreamingImpl {
|
||||
public:
|
||||
WasmStreamingImpl(
|
||||
Isolate* isolate,
|
||||
std::shared_ptr<internal::wasm::CompilationResultResolver> resolver)
|
||||
: isolate_(isolate), resolver_(std::move(resolver)) {
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
|
||||
streaming_decoder_ = i_isolate->wasm_engine()->StartStreamingCompilation(
|
||||
i_isolate, handle(i_isolate->context(), i_isolate), resolver_);
|
||||
}
|
||||
void OnBytesReceived(const uint8_t* bytes, size_t size) {}
|
||||
|
||||
void OnBytesReceived(const uint8_t* bytes, size_t size) {
|
||||
streaming_decoder_->OnBytesReceived(i::Vector<const uint8_t>(bytes, size));
|
||||
}
|
||||
void Finish() { streaming_decoder_->Finish(); }
|
||||
void Finish() {}
|
||||
|
||||
void Abort(MaybeLocal<Value> exception) {
|
||||
i::HandleScope scope(reinterpret_cast<i::Isolate*>(isolate_));
|
||||
streaming_decoder_->Abort();
|
||||
|
||||
// If no exception value is provided, we do not reject the promise. This can
|
||||
// happen when streaming compilation gets aborted when no script execution
|
||||
// is allowed anymore, e.g. when a browser tab gets refreshed.
|
||||
if (exception.IsEmpty()) return;
|
||||
|
||||
resolver_->OnCompilationFailed(
|
||||
Utils::OpenHandle(*exception.ToLocalChecked()));
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_ = nullptr;
|
||||
std::shared_ptr<internal::wasm::StreamingDecoder> streaming_decoder_;
|
||||
std::shared_ptr<internal::wasm::CompilationResultResolver> resolver_;
|
||||
void Abort(MaybeLocal<Value> exception) {}
|
||||
};
|
||||
|
||||
WasmStreaming::WasmStreaming(std::unique_ptr<WasmStreamingImpl> impl)
|
||||
@ -202,6 +176,30 @@ i::MaybeHandle<i::JSReceiver> GetValueAsImports(Local<Value> arg,
|
||||
return i::Handle<i::JSReceiver>::cast(v8::Utils::OpenHandle(*obj));
|
||||
}
|
||||
|
||||
void WebAssemblyCompileStreaming(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
|
||||
if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
|
||||
// Manually create a promise and reject it.
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context));
|
||||
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
|
||||
return_value.Set(resolver->GetPromise());
|
||||
ScheduledErrorThrower thrower(i_isolate, "WebAssembly.compileStreaming()");
|
||||
thrower.CompileError("Wasm code generation disallowed by embedder");
|
||||
auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify()));
|
||||
CHECK_IMPLIES(!maybe.FromMaybe(false),
|
||||
i_isolate->has_scheduled_exception());
|
||||
return;
|
||||
}
|
||||
|
||||
MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
|
||||
DCHECK_NOT_NULL(i_isolate->wasm_compile_streaming_callback());
|
||||
i_isolate->wasm_compile_streaming_callback()(args);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// This class resolves the result of WebAssembly.compile. It just places the
|
||||
// compilation result in the supplied {promise}.
|
||||
@ -215,8 +213,6 @@ class AsyncCompilationResolver : public i::wasm::CompilationResultResolver {
|
||||
}
|
||||
|
||||
void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result) override {
|
||||
if (finished_) return;
|
||||
finished_ = true;
|
||||
i::MaybeHandle<i::Object> promise_result =
|
||||
i::JSPromise::Resolve(promise_, result);
|
||||
CHECK_EQ(promise_result.is_null(),
|
||||
@ -224,8 +220,6 @@ class AsyncCompilationResolver : public i::wasm::CompilationResultResolver {
|
||||
}
|
||||
|
||||
void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
|
||||
if (finished_) return;
|
||||
finished_ = true;
|
||||
i::MaybeHandle<i::Object> promise_result =
|
||||
i::JSPromise::Reject(promise_, error_reason);
|
||||
CHECK_EQ(promise_result.is_null(),
|
||||
@ -233,7 +227,6 @@ class AsyncCompilationResolver : public i::wasm::CompilationResultResolver {
|
||||
}
|
||||
|
||||
private:
|
||||
bool finished_ = false;
|
||||
i::Handle<i::JSPromise> promise_;
|
||||
};
|
||||
|
||||
@ -357,8 +350,6 @@ class AsyncInstantiateCompileResultResolver
|
||||
}
|
||||
|
||||
void OnCompilationSucceeded(i::Handle<i::WasmModuleObject> result) override {
|
||||
if (finished_) return;
|
||||
finished_ = true;
|
||||
isolate_->wasm_engine()->AsyncInstantiate(
|
||||
isolate_,
|
||||
base::make_unique<InstantiateBytesResultResolver>(isolate_, promise_,
|
||||
@ -367,15 +358,12 @@ class AsyncInstantiateCompileResultResolver
|
||||
}
|
||||
|
||||
void OnCompilationFailed(i::Handle<i::Object> error_reason) override {
|
||||
if (finished_) return;
|
||||
finished_ = true;
|
||||
i::MaybeHandle<i::Object> promise_result =
|
||||
i::JSPromise::Reject(promise_, error_reason);
|
||||
CHECK_EQ(promise_result.is_null(), isolate_->has_pending_exception());
|
||||
}
|
||||
|
||||
private:
|
||||
bool finished_ = false;
|
||||
i::Isolate* isolate_;
|
||||
i::Handle<i::JSPromise> promise_;
|
||||
i::MaybeHandle<i::JSReceiver> maybe_imports_;
|
||||
@ -402,7 +390,7 @@ void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
|
||||
return_value.Set(promise);
|
||||
|
||||
std::shared_ptr<i::wasm::CompilationResultResolver> resolver(
|
||||
std::unique_ptr<i::wasm::CompilationResultResolver> resolver(
|
||||
new AsyncCompilationResolver(i_isolate, Utils::OpenHandle(*promise)));
|
||||
|
||||
bool is_shared = false;
|
||||
@ -416,61 +404,6 @@ void WebAssemblyCompile(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
is_shared);
|
||||
}
|
||||
|
||||
// WebAssembly.compileStreaming(Promise<Response>) -> Promise
|
||||
void WebAssemblyCompileStreaming(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
|
||||
HandleScope scope(isolate);
|
||||
ScheduledErrorThrower thrower(i_isolate, "WebAssembly.compile()");
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
|
||||
// Create and assign the return value of this function.
|
||||
ASSIGN(Promise::Resolver, result_resolver, Promise::Resolver::New(context));
|
||||
Local<Promise> promise = result_resolver->GetPromise();
|
||||
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
|
||||
return_value.Set(promise);
|
||||
|
||||
// Prepare the CompilationResultResolver for the compilation.
|
||||
auto resolver = std::make_shared<AsyncCompilationResolver>(
|
||||
i_isolate, Utils::OpenHandle(*promise));
|
||||
|
||||
if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
|
||||
thrower.CompileError("Wasm code generation disallowed by embedder");
|
||||
resolver->OnCompilationFailed(thrower.Reify());
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate the streaming decoder in a Managed so we can pass it to the
|
||||
// embedder.
|
||||
i::Handle<i::Managed<WasmStreaming>> data =
|
||||
i::Managed<WasmStreaming>::Allocate(
|
||||
i_isolate, 0,
|
||||
base::make_unique<WasmStreaming::WasmStreamingImpl>(isolate,
|
||||
resolver));
|
||||
|
||||
DCHECK_NOT_NULL(i_isolate->wasm_streaming_callback());
|
||||
ASSIGN(
|
||||
v8::Function, compile_callback,
|
||||
v8::Function::New(context, i_isolate->wasm_streaming_callback(),
|
||||
Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
|
||||
|
||||
// The parameter may be of type {Response} or of type {Promise<Response>}.
|
||||
// Treat either case of parameter as Promise.resolve(parameter)
|
||||
// as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments
|
||||
|
||||
// Ending with:
|
||||
// return Promise.resolve(parameter).then(compile_callback);
|
||||
ASSIGN(Promise::Resolver, input_resolver, Promise::Resolver::New(context));
|
||||
if (!input_resolver->Resolve(context, args[0]).IsJust()) return;
|
||||
|
||||
// We do not have any use of the result here. The {compile_callback} will
|
||||
// start streaming compilation, which will eventually resolve the promise we
|
||||
// set as result value.
|
||||
USE(input_resolver->GetPromise()->Then(context, compile_callback));
|
||||
}
|
||||
|
||||
// WebAssembly.validate(bytes) -> bool
|
||||
void WebAssemblyValidate(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
@ -630,6 +563,40 @@ MaybeLocal<Value> WebAssemblyInstantiateImpl(Isolate* isolate,
|
||||
return Utils::ToLocal(instance_object.ToHandleChecked());
|
||||
}
|
||||
|
||||
void WebAssemblyInstantiateCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
DCHECK_GE(args.Length(), 1);
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
MicrotasksScope does_not_run_microtasks(isolate,
|
||||
MicrotasksScope::kDoNotRunMicrotasks);
|
||||
|
||||
HandleScope scope(args.GetIsolate());
|
||||
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
Local<Value> module = args[0];
|
||||
|
||||
const uint8_t* instance_str = reinterpret_cast<const uint8_t*>("instance");
|
||||
const uint8_t* module_str = reinterpret_cast<const uint8_t*>("module");
|
||||
Local<Value> instance;
|
||||
if (!WebAssemblyInstantiateImpl(isolate, module, args.Data())
|
||||
.ToLocal(&instance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Local<Object> ret = Object::New(isolate);
|
||||
Local<String> instance_name =
|
||||
String::NewFromOneByte(isolate, instance_str,
|
||||
NewStringType::kInternalized)
|
||||
.ToLocalChecked();
|
||||
Local<String> module_name =
|
||||
String::NewFromOneByte(isolate, module_str, NewStringType::kInternalized)
|
||||
.ToLocalChecked();
|
||||
|
||||
CHECK(ret->CreateDataProperty(context, instance_name, instance).IsJust());
|
||||
CHECK(ret->CreateDataProperty(context, module_name, module).IsJust());
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
|
||||
// new WebAssembly.Instance(module, imports) -> WebAssembly.Instance
|
||||
void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
@ -667,76 +634,27 @@ void WebAssemblyInstantiateStreaming(
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
i_isolate->CountUsage(
|
||||
v8::Isolate::UseCounterFeature::kWebAssemblyInstantiation);
|
||||
|
||||
// we use i_isolate in DCHECKS in the ASSIGN statements.
|
||||
USE(i_isolate);
|
||||
MicrotasksScope runs_microtasks(isolate, MicrotasksScope::kRunMicrotasks);
|
||||
HandleScope scope(isolate);
|
||||
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
ScheduledErrorThrower thrower(i_isolate,
|
||||
"WebAssembly.instantiateStreaming()");
|
||||
ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context));
|
||||
Local<Value> first_arg_value = args[0];
|
||||
|
||||
// Create and assign the return value of this function.
|
||||
ASSIGN(Promise::Resolver, result_resolver, Promise::Resolver::New(context));
|
||||
Local<Promise> promise = result_resolver->GetPromise();
|
||||
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
|
||||
return_value.Set(promise);
|
||||
ASSIGN(Function, compileStreaming,
|
||||
Function::New(context, WebAssemblyCompileStreaming));
|
||||
ASSIGN(Value, compile_retval,
|
||||
compileStreaming->Call(context, args.Holder(), 1, &first_arg_value));
|
||||
Local<Promise> module_promise = Local<Promise>::Cast(compile_retval);
|
||||
|
||||
// Create an InstantiateResultResolver in case there is an issue with the
|
||||
// passed parameters.
|
||||
std::unique_ptr<i::wasm::InstantiationResultResolver> resolver(
|
||||
new InstantiateModuleResultResolver(i_isolate,
|
||||
Utils::OpenHandle(*promise)));
|
||||
|
||||
if (!i::wasm::IsWasmCodegenAllowed(i_isolate, i_isolate->native_context())) {
|
||||
thrower.CompileError("Wasm code generation disallowed by embedder");
|
||||
resolver->OnInstantiationFailed(thrower.Reify());
|
||||
return;
|
||||
}
|
||||
|
||||
// If args.Length < 2, this will be undefined - see FunctionCallbackInfo.
|
||||
Local<Value> ffi = args[1];
|
||||
i::MaybeHandle<i::JSReceiver> maybe_imports =
|
||||
GetValueAsImports(ffi, &thrower);
|
||||
|
||||
if (thrower.error()) {
|
||||
resolver->OnInstantiationFailed(thrower.Reify());
|
||||
return;
|
||||
}
|
||||
|
||||
// We start compilation now, we have no use for the
|
||||
// {InstantiationResultResolver}.
|
||||
resolver.reset();
|
||||
|
||||
std::shared_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
|
||||
new AsyncInstantiateCompileResultResolver(
|
||||
i_isolate, Utils::OpenHandle(*promise), maybe_imports));
|
||||
|
||||
// Allocate the streaming decoder in a Managed so we can pass it to the
|
||||
// embedder.
|
||||
i::Handle<i::Managed<WasmStreaming>> data =
|
||||
i::Managed<WasmStreaming>::Allocate(
|
||||
i_isolate, 0,
|
||||
base::make_unique<WasmStreaming::WasmStreamingImpl>(
|
||||
isolate, compilation_resolver));
|
||||
|
||||
DCHECK_NOT_NULL(i_isolate->wasm_streaming_callback());
|
||||
ASSIGN(
|
||||
v8::Function, compile_callback,
|
||||
v8::Function::New(context, i_isolate->wasm_streaming_callback(),
|
||||
Utils::ToLocal(i::Handle<i::Object>::cast(data)), 1));
|
||||
|
||||
// The parameter may be of type {Response} or of type {Promise<Response>}.
|
||||
// Treat either case of parameter as Promise.resolve(parameter)
|
||||
// as per https://www.w3.org/2001/tag/doc/promises-guide#resolve-arguments
|
||||
|
||||
// Ending with:
|
||||
// return Promise.resolve(parameter).then(compile_callback);
|
||||
ASSIGN(Promise::Resolver, input_resolver, Promise::Resolver::New(context));
|
||||
if (!input_resolver->Resolve(context, args[0]).IsJust()) return;
|
||||
|
||||
// We do not have any use of the result here. The {compile_callback} will
|
||||
// start streaming compilation, which will eventually resolve the promise we
|
||||
// set as result value.
|
||||
USE(input_resolver->GetPromise()->Then(context, compile_callback));
|
||||
DCHECK(!module_promise.IsEmpty());
|
||||
Local<Value> data = args[1];
|
||||
ASSIGN(Function, instantiate_impl,
|
||||
Function::New(context, WebAssemblyInstantiateCallback, data));
|
||||
ASSIGN(Promise, result, module_promise->Then(context, instantiate_impl));
|
||||
args.GetReturnValue().Set(result);
|
||||
}
|
||||
|
||||
// WebAssembly.instantiate(module, imports) -> WebAssembly.Instance
|
||||
@ -802,7 +720,7 @@ void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
// {InstantiationResultResolver}.
|
||||
resolver.reset();
|
||||
|
||||
std::shared_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
|
||||
std::unique_ptr<i::wasm::CompilationResultResolver> compilation_resolver(
|
||||
new AsyncInstantiateCompileResultResolver(
|
||||
i_isolate, Utils::OpenHandle(*promise), maybe_imports));
|
||||
|
||||
@ -1470,7 +1388,7 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
|
||||
InstallFunc(isolate, webassembly, "validate", WebAssemblyValidate, 1);
|
||||
InstallFunc(isolate, webassembly, "instantiate", WebAssemblyInstantiate, 1);
|
||||
|
||||
if (isolate->wasm_streaming_callback() != nullptr) {
|
||||
if (isolate->wasm_compile_streaming_callback() != nullptr) {
|
||||
InstallFunc(isolate, webassembly, "compileStreaming",
|
||||
WebAssemblyCompileStreaming, 1);
|
||||
InstallFunc(isolate, webassembly, "instantiateStreaming",
|
||||
|
@ -59,7 +59,6 @@
|
||||
#include "src/unicode-inl.h"
|
||||
#include "src/utils.h"
|
||||
#include "src/vm-state.h"
|
||||
#include "src/wasm/wasm-js.h"
|
||||
#include "test/cctest/heap/heap-tester.h"
|
||||
#include "test/cctest/heap/heap-utils.h"
|
||||
|
||||
@ -28257,123 +28256,22 @@ TEST(PersistentValueMap) {
|
||||
map.Set("key", value);
|
||||
}
|
||||
|
||||
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::JSObject** p = reinterpret_cast<i::JSObject**>(data.GetParameter());
|
||||
i::GlobalHandles::Destroy(reinterpret_cast<i::Object**>(p));
|
||||
}
|
||||
|
||||
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);
|
||||
TEST(WasmStreamingAbort) {
|
||||
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());
|
||||
v8::WasmModuleObjectBuilderStreaming streaming(isolate);
|
||||
streaming.Abort(v8::Object::New(isolate));
|
||||
CHECK_EQ(streaming.GetPromise()->State(), v8::Promise::kRejected);
|
||||
}
|
||||
|
||||
} // 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);
|
||||
TEST(WasmStreamingAbortNoReject) {
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::WasmModuleObjectBuilderStreaming streaming(isolate);
|
||||
streaming.Abort({});
|
||||
CHECK_EQ(streaming.GetPromise()->State(), v8::Promise::kPending);
|
||||
}
|
||||
|
||||
enum class AtomicsWaitCallbackAction {
|
||||
|
@ -114,7 +114,7 @@ class StreamTester {
|
||||
|
||||
stream_ = i_isolate->wasm_engine()->StartStreamingCompilation(
|
||||
i_isolate, v8::Utils::OpenHandle(*context),
|
||||
std::make_shared<TestResolver>(&state_));
|
||||
base::make_unique<TestResolver>(&state_));
|
||||
}
|
||||
|
||||
std::shared_ptr<StreamingDecoder> stream() { return stream_; }
|
||||
|
@ -69,7 +69,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
|
||||
bool done = false;
|
||||
i_isolate->wasm_engine()->AsyncCompile(
|
||||
i_isolate, std::make_shared<AsyncFuzzerResolver>(i_isolate, &done),
|
||||
i_isolate, base::make_unique<AsyncFuzzerResolver>(i_isolate, &done),
|
||||
ModuleWireBytes(data, data + size), false);
|
||||
|
||||
// Wait for the promise to resolve.
|
||||
|
Loading…
Reference in New Issue
Block a user