| // Copyright 2020 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 "src/execution/isolate.h" |
| #include "src/wasm/streaming-decoder.h" |
| #include "src/wasm/wasm-engine.h" |
| #include "src/wasm/wasm-objects-inl.h" |
| #include "src/wasm/wasm-serialization.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace wasm { |
| |
| class V8_EXPORT_PRIVATE SyncStreamingDecoder : public StreamingDecoder { |
| public: |
| SyncStreamingDecoder(Isolate* isolate, const WasmFeatures& enabled, |
| Handle<Context> context, |
| const char* api_method_name_for_errors, |
| std::shared_ptr<CompilationResultResolver> resolver) |
| : isolate_(isolate), |
| enabled_(enabled), |
| context_(context), |
| api_method_name_for_errors_(api_method_name_for_errors), |
| resolver_(resolver) {} |
| |
| // The buffer passed into OnBytesReceived is owned by the caller. |
| void OnBytesReceived(Vector<const uint8_t> bytes) override { |
| buffer_.emplace_back(bytes.size()); |
| CHECK_EQ(buffer_.back().size(), bytes.size()); |
| std::memcpy(buffer_.back().data(), bytes.data(), bytes.size()); |
| buffer_size_ += bytes.size(); |
| } |
| |
| void Finish() override { |
| // We copy all received chunks into one byte buffer. |
| auto bytes = std::make_unique<uint8_t[]>(buffer_size_); |
| uint8_t* destination = bytes.get(); |
| for (auto& chunk : buffer_) { |
| std::memcpy(destination, chunk.data(), chunk.size()); |
| destination += chunk.size(); |
| } |
| CHECK_EQ(destination - bytes.get(), buffer_size_); |
| |
| // Check if we can deserialize the module from cache. |
| if (deserializing()) { |
| HandleScope scope(isolate_); |
| SaveAndSwitchContext saved_context(isolate_, *context_); |
| |
| MaybeHandle<WasmModuleObject> module_object = DeserializeNativeModule( |
| isolate_, compiled_module_bytes_, |
| Vector<const uint8_t>(bytes.get(), buffer_size_), url()); |
| |
| if (!module_object.is_null()) { |
| Handle<WasmModuleObject> module = module_object.ToHandleChecked(); |
| resolver_->OnCompilationSucceeded(module); |
| return; |
| } |
| } |
| |
| // Compile the received bytes synchronously. |
| ModuleWireBytes wire_bytes(bytes.get(), bytes.get() + buffer_size_); |
| ErrorThrower thrower(isolate_, api_method_name_for_errors_); |
| MaybeHandle<WasmModuleObject> module_object = |
| isolate_->wasm_engine()->SyncCompile(isolate_, enabled_, &thrower, |
| wire_bytes); |
| if (thrower.error()) { |
| resolver_->OnCompilationFailed(thrower.Reify()); |
| return; |
| } |
| Handle<WasmModuleObject> module = module_object.ToHandleChecked(); |
| if (module_compiled_callback_) { |
| module_compiled_callback_(module->shared_native_module()); |
| } |
| resolver_->OnCompilationSucceeded(module); |
| } |
| |
| void Abort() override { |
| // Abort is fully handled by the API, we only clear the buffer. |
| buffer_.clear(); |
| } |
| |
| void NotifyCompilationEnded() override { buffer_.clear(); } |
| |
| void NotifyNativeModuleCreated( |
| const std::shared_ptr<NativeModule>&) override { |
| // This function is only called from the {AsyncCompileJob}. |
| UNREACHABLE(); |
| } |
| |
| private: |
| Isolate* isolate_; |
| const WasmFeatures enabled_; |
| Handle<Context> context_; |
| const char* api_method_name_for_errors_; |
| std::shared_ptr<CompilationResultResolver> resolver_; |
| |
| std::vector<std::vector<uint8_t>> buffer_; |
| size_t buffer_size_ = 0; |
| }; |
| |
| std::unique_ptr<StreamingDecoder> StreamingDecoder::CreateSyncStreamingDecoder( |
| Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context, |
| const char* api_method_name_for_errors, |
| std::shared_ptr<CompilationResultResolver> resolver) { |
| return std::make_unique<SyncStreamingDecoder>(isolate, enabled, context, |
| api_method_name_for_errors, |
| std::move(resolver)); |
| } |
| } // namespace wasm |
| } // namespace internal |
| } // namespace v8 |