Commit 255048c5 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[api][wasm] Change ModuleCompiledCallback definition

This callback is not being used by now, so we can just change it
without the deprecation dance.
Instead of the WasmModuleObject, it now receives the new
CompiledWasmModule wrapper which contains a shared pointer to the
NativeModule. This is all that's needed for serialization.

Some classes are pulled out of WasmModuleObject to allow reuse.

R=adamk@chromium.org, mstarzinger@chromium.org
CC=​bbudge@chromium.org

Bug: chromium:912031
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng
Change-Id: Icedb64efa92e66bec45cf8742942a07ae22f59c8
Reviewed-on: https://chromium-review.googlesource.com/c/1363140Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Reviewed-by: 's avatarBill Budge <bbudge@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58142}
parent f1246644
......@@ -4253,24 +4253,97 @@ class V8_EXPORT Proxy : public Object {
static void CheckCast(Value* obj);
};
/**
* Points to an unowned continous buffer holding a known number of elements.
*
* This is similar to std::span (under consideration for C++20), but does not
* require advanced C++ support. In the (far) future, this may be replaced with
* or aliased to std::span.
*
* To facilitate future migration, this class exposes a subset of the interface
* implemented by std::span.
*/
template <typename T>
class V8_EXPORT MemorySpan {
public:
/** The default constructor creates an empty span. */
constexpr MemorySpan() = default;
constexpr MemorySpan(T* data, size_t size) : data_(data), size_(size) {}
/** Returns a pointer to the beginning of the buffer. */
constexpr T* data() const { return data_; }
/** Returns the number of elements that the buffer holds. */
constexpr size_t size() const { return size_; }
private:
T* data_ = nullptr;
size_t size_ = 0;
};
/**
* An owned byte buffer with associated size.
*/
struct OwnedBuffer {
std::unique_ptr<const uint8_t[]> buffer;
size_t size = 0;
OwnedBuffer(std::unique_ptr<const uint8_t[]> buffer, size_t size)
: buffer(std::move(buffer)), size(size) {}
OwnedBuffer() = default;
};
// Wrapper around a compiled WebAssembly module, which is potentially shared by
// different WasmModuleObjects.
class V8_EXPORT CompiledWasmModule {
public:
/**
* Serialize the compiled module. The serialized data does not include the
* wire bytes.
*/
OwnedBuffer Serialize();
/**
* Get the (wasm-encoded) wire bytes that were used to compile this module.
*/
MemorySpan<const uint8_t> GetWireBytesRef();
private:
explicit CompiledWasmModule(std::shared_ptr<internal::wasm::NativeModule>);
friend class Utils;
const std::shared_ptr<internal::wasm::NativeModule> native_module_;
};
// An instance of WebAssembly.Module.
class V8_EXPORT WasmModuleObject : public Object {
public:
typedef std::pair<std::unique_ptr<const uint8_t[]>, size_t> SerializedModule;
// TODO(clemensh): Remove after 7.3 branch.
V8_DEPRECATE_SOON("Use OwnedBuffer", typedef)
std::pair<std::unique_ptr<const uint8_t[]>, size_t> SerializedModule;
/**
* A unowned reference to a byte buffer.
* TODO(clemensh): Remove after 7.3 branch.
*/
struct BufferReference {
V8_DEPRECATE_SOON("Use MemorySpan<const uint8_t>", struct) BufferReference {
const uint8_t* start;
size_t size;
BufferReference(const uint8_t* start, size_t size)
: start(start), size(size) {}
// Implicit conversion to and from MemorySpan<const uint8_t>.
BufferReference(MemorySpan<const uint8_t> span) // NOLINT(runtime/explicit)
: start(span.data()), size(span.size()) {}
operator MemorySpan<const uint8_t>() const {
return MemorySpan<const uint8_t>{start, size};
}
};
/**
* An opaque, native heap object for transferring wasm modules. It
* supports move semantics, and does not support copy semantics.
* TODO(wasm): Merge this with CompiledWasmModule once code sharing is always
* enabled.
*/
class TransferrableModule final {
public:
......@@ -4282,7 +4355,6 @@ class V8_EXPORT WasmModuleObject : public Object {
private:
typedef std::shared_ptr<internal::wasm::NativeModule> SharedModule;
typedef std::pair<std::unique_ptr<const uint8_t[]>, size_t> OwnedBuffer;
friend class WasmModuleObject;
explicit TransferrableModule(SharedModule shared_module)
: shared_module_(std::move(shared_module)) {}
......@@ -4311,33 +4383,40 @@ class V8_EXPORT WasmModuleObject : public Object {
/**
* Get the wasm-encoded bytes that were used to compile this module.
*/
BufferReference GetWasmWireBytesRef();
V8_DEPRECATE_SOON("Use CompiledWasmModule::GetWireBytesRef()",
BufferReference GetWasmWireBytesRef());
/**
* Get the compiled module for this module object. The compiled module can be
* shared by several module objects.
*/
CompiledWasmModule GetCompiledModule();
/**
* Serialize the compiled module. The serialized data does not include the
* uncompiled bytes.
*/
SerializedModule Serialize();
V8_DEPRECATE_SOON("Use CompiledWasmModule::Serialize()",
SerializedModule Serialize());
/**
* If possible, deserialize the module, otherwise compile it from the provided
* uncompiled bytes.
*/
static MaybeLocal<WasmModuleObject> DeserializeOrCompile(
Isolate* isolate, BufferReference serialized_module,
BufferReference wire_bytes);
Isolate* isolate, MemorySpan<const uint8_t> serialized_module,
MemorySpan<const uint8_t> wire_bytes);
V8_INLINE static WasmModuleObject* Cast(Value* obj);
private:
static MaybeLocal<WasmModuleObject> Deserialize(
Isolate* isolate, BufferReference serialized_module,
BufferReference wire_bytes);
Isolate* isolate, MemorySpan<const uint8_t> serialized_module,
MemorySpan<const uint8_t> wire_bytes);
static MaybeLocal<WasmModuleObject> Compile(Isolate* isolate,
const uint8_t* start,
size_t length);
static BufferReference AsReference(
const TransferrableModule::OwnedBuffer& buff) {
return {buff.first.get(), buff.second};
static MemorySpan<const uint8_t> AsReference(const OwnedBuffer& buff) {
return {buff.buffer.get(), buff.size};
}
WasmModuleObject();
......@@ -4385,8 +4464,8 @@ class V8_EXPORT WasmStreaming final {
* Callback for module compiled notifications. |data| is the identifier
* passed to {SetModuleCompiledCallback}, |compiled_module| is the result.
*/
typedef void (*ModuleCompiledCallback)(
intptr_t data, Local<WasmModuleObject> compiled_module);
typedef void (*ModuleCompiledCallback)(intptr_t data,
CompiledWasmModule compiled_module);
/**
* Sets a callback for when compilation of the Wasm module has been completed
......
......@@ -7361,13 +7361,30 @@ MaybeLocal<Proxy> Proxy::New(Local<Context> context, Local<Object> local_target,
RETURN_ESCAPED(result);
}
WasmModuleObject::BufferReference WasmModuleObject::GetWasmWireBytesRef() {
i::Handle<i::WasmModuleObject> obj =
i::Handle<i::WasmModuleObject>::cast(Utils::OpenHandle(this));
i::Vector<const uint8_t> bytes_vec = obj->native_module()->wire_bytes();
CompiledWasmModule::CompiledWasmModule(
std::shared_ptr<internal::wasm::NativeModule> native_module)
: native_module_(std::move(native_module)) {
CHECK_NOT_NULL(native_module_);
}
OwnedBuffer CompiledWasmModule::Serialize() {
i::wasm::WasmSerializer wasm_serializer(native_module_.get());
size_t buffer_size = wasm_serializer.GetSerializedNativeModuleSize();
std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
if (!wasm_serializer.SerializeNativeModule({buffer.get(), buffer_size}))
return {};
return {std::move(buffer), buffer_size};
}
MemorySpan<const uint8_t> CompiledWasmModule::GetWireBytesRef() {
i::Vector<const uint8_t> bytes_vec = native_module_->wire_bytes();
return {bytes_vec.start(), bytes_vec.size()};
}
WasmModuleObject::BufferReference WasmModuleObject::GetWasmWireBytesRef() {
return GetCompiledModule().GetWireBytesRef();
}
WasmModuleObject::TransferrableModule
WasmModuleObject::GetTransferrableModule() {
if (i::FLAG_wasm_shared_code) {
......@@ -7375,16 +7392,24 @@ WasmModuleObject::GetTransferrableModule() {
i::Handle<i::WasmModuleObject>::cast(Utils::OpenHandle(this));
return TransferrableModule(obj->managed_native_module()->get());
} else {
WasmModuleObject::SerializedModule serialized_module = Serialize();
BufferReference wire_bytes_ref = GetWasmWireBytesRef();
size_t wire_size = wire_bytes_ref.size;
CompiledWasmModule compiled_module = GetCompiledModule();
OwnedBuffer serialized_module = compiled_module.Serialize();
MemorySpan<const uint8_t> wire_bytes_ref =
compiled_module.GetWireBytesRef();
size_t wire_size = wire_bytes_ref.size();
std::unique_ptr<uint8_t[]> wire_bytes_copy(new uint8_t[wire_size]);
memcpy(wire_bytes_copy.get(), wire_bytes_ref.start, wire_size);
memcpy(wire_bytes_copy.get(), wire_bytes_ref.data(), wire_size);
return TransferrableModule(std::move(serialized_module),
{std::move(wire_bytes_copy), wire_size});
}
}
CompiledWasmModule WasmModuleObject::GetCompiledModule() {
i::Handle<i::WasmModuleObject> obj =
i::Handle<i::WasmModuleObject>::cast(Utils::OpenHandle(this));
return Utils::Convert(obj->managed_native_module()->get());
}
MaybeLocal<WasmModuleObject> WasmModuleObject::FromTransferrableModule(
Isolate* isolate,
const WasmModuleObject::TransferrableModule& transferrable_module) {
......@@ -7402,25 +7427,19 @@ MaybeLocal<WasmModuleObject> WasmModuleObject::FromTransferrableModule(
}
WasmModuleObject::SerializedModule WasmModuleObject::Serialize() {
i::Handle<i::WasmModuleObject> obj =
i::Handle<i::WasmModuleObject>::cast(Utils::OpenHandle(this));
i::wasm::NativeModule* native_module = obj->native_module();
i::wasm::WasmSerializer wasm_serializer(native_module);
size_t buffer_size = wasm_serializer.GetSerializedNativeModuleSize();
std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
if (wasm_serializer.SerializeNativeModule({buffer.get(), buffer_size}))
return {std::move(buffer), buffer_size};
return {};
// TODO(clemensh): Deprecated; remove after M-73 branch.
OwnedBuffer serialized = GetCompiledModule().Serialize();
return {std::move(serialized.buffer), serialized.size};
}
MaybeLocal<WasmModuleObject> WasmModuleObject::Deserialize(
Isolate* isolate, WasmModuleObject::BufferReference serialized_module,
WasmModuleObject::BufferReference wire_bytes) {
Isolate* isolate, MemorySpan<const uint8_t> serialized_module,
MemorySpan<const uint8_t> wire_bytes) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::MaybeHandle<i::WasmModuleObject> maybe_module_object =
i::wasm::DeserializeNativeModule(
i_isolate, {serialized_module.start, serialized_module.size},
{wire_bytes.start, wire_bytes.size});
i_isolate, {serialized_module.data(), serialized_module.size()},
{wire_bytes.data(), wire_bytes.size()});
i::Handle<i::WasmModuleObject> module_object;
if (!maybe_module_object.ToHandle(&module_object)) {
return MaybeLocal<WasmModuleObject>();
......@@ -7430,14 +7449,14 @@ MaybeLocal<WasmModuleObject> WasmModuleObject::Deserialize(
}
MaybeLocal<WasmModuleObject> WasmModuleObject::DeserializeOrCompile(
Isolate* isolate, WasmModuleObject::BufferReference serialized_module,
WasmModuleObject::BufferReference wire_bytes) {
Isolate* isolate, MemorySpan<const uint8_t> serialized_module,
MemorySpan<const uint8_t> wire_bytes) {
MaybeLocal<WasmModuleObject> ret =
Deserialize(isolate, serialized_module, wire_bytes);
if (!ret.IsEmpty()) {
return ret;
}
return Compile(isolate, wire_bytes.start, wire_bytes.size);
return Compile(isolate, wire_bytes.data(), wire_bytes.size());
}
MaybeLocal<WasmModuleObject> WasmModuleObject::Compile(Isolate* isolate,
......
......@@ -231,22 +231,22 @@ class Utils {
static inline Local<ScriptOrModule> ScriptOrModuleToLocal(
v8::internal::Handle<v8::internal::Script> obj);
#define DECLARE_OPEN_HANDLE(From, To) \
static inline v8::internal::Handle<v8::internal::To> \
OpenHandle(const From* that, bool allow_empty_handle = false);
#define DECLARE_OPEN_HANDLE(From, To) \
static inline v8::internal::Handle<v8::internal::To> OpenHandle( \
const From* that, bool allow_empty_handle = false);
OPEN_HANDLE_LIST(DECLARE_OPEN_HANDLE)
OPEN_HANDLE_LIST(DECLARE_OPEN_HANDLE)
#undef DECLARE_OPEN_HANDLE
template <class From, class To>
static inline Local<To> Convert(v8::internal::Handle<From> obj);
template <class From, class To>
static inline Local<To> Convert(v8::internal::Handle<From> obj);
template <class T>
static inline v8::internal::Handle<v8::internal::Object> OpenPersistent(
const v8::Persistent<T>& persistent) {
return v8::internal::Handle<v8::internal::Object>(
reinterpret_cast<v8::internal::Address*>(persistent.val_));
template <class T>
static inline v8::internal::Handle<v8::internal::Object> OpenPersistent(
const v8::Persistent<T>& persistent) {
return v8::internal::Handle<v8::internal::Object>(
reinterpret_cast<v8::internal::Address*>(persistent.val_));
}
template <class T>
......@@ -260,11 +260,15 @@ static inline v8::internal::Handle<v8::internal::Object> OpenPersistent(
return OpenHandle(*handle);
}
static inline CompiledWasmModule Convert(
std::shared_ptr<i::wasm::NativeModule> native_module) {
return CompiledWasmModule{std::move(native_module)};
}
private:
static void ReportApiFailure(const char* location, const char* message);
};
template <class T>
inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) {
return reinterpret_cast<T*>(obj.location());
......
......@@ -70,7 +70,8 @@ bool IsWasmInstantiateAllowed(v8::Isolate* isolate,
}
v8::Local<v8::WasmModuleObject> module =
v8::Local<v8::WasmModuleObject>::Cast(module_or_bytes);
return static_cast<uint32_t>(module->GetWasmWireBytesRef().size) <=
return static_cast<uint32_t>(
module->GetCompiledModule().GetWireBytesRef().size()) <=
ctrls.MaxWasmBufferSize;
}
......
......@@ -65,8 +65,8 @@ class WasmStreaming::WasmStreamingImpl {
// Local<WasmModuleObject> here.
streaming_decoder_->SetModuleCompiledCallback(
[callback, data](i::Handle<i::WasmModuleObject> module_object) {
callback(data, Local<WasmModuleObject>::Cast(Utils::ToLocal(
i::Handle<i::JSObject>::cast(module_object))));
callback(data, Utils::Convert(
module_object->managed_native_module()->get()));
});
}
......
......@@ -57,11 +57,10 @@ void BuildTrivialModule(Zone* zone, ZoneBuffer* buffer) {
builder->WriteTo(*buffer);
}
bool TestModule(Isolate* isolate,
v8::WasmModuleObject::BufferReference wire_bytes) {
bool TestModule(Isolate* isolate, v8::MemorySpan<const uint8_t> wire_bytes) {
HandleScope scope(isolate);
v8::WasmModuleObject::BufferReference serialized_module(nullptr, 0);
v8::MemorySpan<const uint8_t> serialized_module;
MaybeLocal<v8::WasmModuleObject> module =
v8::WasmModuleObject::DeserializeOrCompile(
reinterpret_cast<v8::Isolate*>(isolate), serialized_module,
......@@ -76,8 +75,7 @@ TEST(PropertiesOfCodegenCallbacks) {
Zone zone(&allocator, ZONE_NAME);
ZoneBuffer buffer(&zone);
BuildTrivialModule(&zone, &buffer);
v8::WasmModuleObject::BufferReference wire_bytes = {buffer.begin(),
buffer.size()};
v8::MemorySpan<const uint8_t> wire_bytes = {buffer.begin(), buffer.size()};
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
testing::SetupIsolateForWasmModule(isolate);
......
......@@ -68,18 +68,18 @@ class WasmSerializationTest {
void InvalidateVersion() {
uint32_t* slot = reinterpret_cast<uint32_t*>(
const_cast<uint8_t*>(serialized_bytes_.start) +
const_cast<uint8_t*>(serialized_bytes_.data()) +
SerializedCodeData::kVersionHashOffset);
*slot = Version::Hash() + 1;
}
void InvalidateWireBytes() {
memset(const_cast<uint8_t*>(wire_bytes_.start), 0, wire_bytes_.size / 2);
memset(const_cast<uint8_t*>(wire_bytes_.data()), 0, wire_bytes_.size() / 2);
}
void InvalidateLength() {
uint32_t* slot = reinterpret_cast<uint32_t*>(
const_cast<uint8_t*>(serialized_bytes_.start) +
const_cast<uint8_t*>(serialized_bytes_.data()) +
SerializedCodeData::kPayloadLengthOffset);
*slot = 0u;
}
......@@ -102,9 +102,9 @@ class WasmSerializationTest {
DisallowHeapAllocation assume_no_gc;
Vector<const byte> deserialized_module_wire_bytes =
module_object->native_module()->wire_bytes();
CHECK_EQ(deserialized_module_wire_bytes.size(), wire_bytes_.size);
CHECK_EQ(memcmp(deserialized_module_wire_bytes.start(), wire_bytes_.start,
wire_bytes_.size),
CHECK_EQ(deserialized_module_wire_bytes.size(), wire_bytes_.size());
CHECK_EQ(memcmp(deserialized_module_wire_bytes.start(),
wire_bytes_.data(), wire_bytes_.size()),
0);
}
Handle<WasmInstanceObject> instance =
......@@ -159,18 +159,20 @@ class WasmSerializationTest {
v8::Utils::ToLocal(Handle<JSObject>::cast(module_object));
CHECK(v8_module_obj->IsWebAssemblyCompiledModule());
v8::Local<v8::WasmModuleObject> v8_compiled_module =
v8::Local<v8::WasmModuleObject> v8_module_object =
v8_module_obj.As<v8::WasmModuleObject>();
v8::WasmModuleObject::BufferReference uncompiled_bytes =
v8_compiled_module->GetWasmWireBytesRef();
uint8_t* bytes_copy = zone()->NewArray<uint8_t>(uncompiled_bytes.size);
memcpy(bytes_copy, uncompiled_bytes.start, uncompiled_bytes.size);
wire_bytes_ = {bytes_copy, uncompiled_bytes.size};
v8::CompiledWasmModule compiled_module =
v8_module_object->GetCompiledModule();
v8::MemorySpan<const uint8_t> uncompiled_bytes =
compiled_module.GetWireBytesRef();
uint8_t* bytes_copy = zone()->NewArray<uint8_t>(uncompiled_bytes.size());
memcpy(bytes_copy, uncompiled_bytes.data(), uncompiled_bytes.size());
wire_bytes_ = {bytes_copy, uncompiled_bytes.size()};
// keep alive data_ until the end
data_ = v8_compiled_module->Serialize();
data_ = compiled_module.Serialize();
}
serialized_bytes_ = {data_.first.get(), data_.second};
serialized_bytes_ = {data_.buffer.get(), data_.size};
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator =
......@@ -191,9 +193,9 @@ class WasmSerializationTest {
v8::internal::AccountingAllocator allocator_;
Zone zone_;
v8::WasmModuleObject::SerializedModule data_;
v8::WasmModuleObject::BufferReference wire_bytes_ = {nullptr, 0};
v8::WasmModuleObject::BufferReference serialized_bytes_ = {nullptr, 0};
v8::OwnedBuffer data_;
v8::MemorySpan<const uint8_t> wire_bytes_ = {nullptr, 0};
v8::MemorySpan<const uint8_t> serialized_bytes_ = {nullptr, 0};
v8::Isolate* current_isolate_v8_;
};
......
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