Commit e42b547b authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Serialize without accessing any Isolate

We need to be able to serialize a NativeModule, which is not bound to
any Isolate. Hence we should not want to pass any Isolate to the
serializer. This CL removes the dependence by not using the
ExternalReferenceTable from the Isolate, but instead using its own
ExternalReferenceList for serialization and deserialization. This
ExternalReferenceList only contains isolate-independent external
references.

R=mstarzinger@chromium.org

Bug: chromium:912043, chromium:912031
Change-Id: Iea5abd95dce9c54e618255cc577b6b43f002ac5d
Reviewed-on: https://chromium-review.googlesource.com/c/1363135
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58099}
parent 9c2c8f15
...@@ -7402,7 +7402,7 @@ WasmModuleObject::SerializedModule WasmModuleObject::Serialize() { ...@@ -7402,7 +7402,7 @@ WasmModuleObject::SerializedModule WasmModuleObject::Serialize() {
i::Handle<i::WasmModuleObject> obj = i::Handle<i::WasmModuleObject> obj =
i::Handle<i::WasmModuleObject>::cast(Utils::OpenHandle(this)); i::Handle<i::WasmModuleObject>::cast(Utils::OpenHandle(this));
i::wasm::NativeModule* native_module = obj->native_module(); i::wasm::NativeModule* native_module = obj->native_module();
i::wasm::WasmSerializer wasm_serializer(obj->GetIsolate(), native_module); i::wasm::WasmSerializer wasm_serializer(native_module);
size_t buffer_size = wasm_serializer.GetSerializedNativeModuleSize(); size_t buffer_size = wasm_serializer.GetSerializedNativeModuleSize();
std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]); std::unique_ptr<uint8_t[]> buffer(new uint8_t[buffer_size]);
if (wasm_serializer.SerializeNativeModule({buffer.get(), buffer_size})) if (wasm_serializer.SerializeNativeModule({buffer.get(), buffer_size}))
......
...@@ -965,7 +965,7 @@ RUNTIME_FUNCTION(Runtime_SerializeWasmModule) { ...@@ -965,7 +965,7 @@ RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0); CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
wasm::NativeModule* native_module = module_obj->native_module(); wasm::NativeModule* native_module = module_obj->native_module();
wasm::WasmSerializer wasm_serializer(isolate, native_module); wasm::WasmSerializer wasm_serializer(native_module);
size_t compiled_size = wasm_serializer.GetSerializedNativeModuleSize(); size_t compiled_size = wasm_serializer.GetSerializedNativeModuleSize();
void* array_data = isolate->array_buffer_allocator()->Allocate(compiled_size); void* array_data = isolate->array_buffer_allocator()->Allocate(compiled_size);
Handle<JSArrayBuffer> array_buffer = isolate->factory()->NewJSArrayBuffer(); Handle<JSArrayBuffer> array_buffer = isolate->factory()->NewJSArrayBuffer();
......
...@@ -897,7 +897,7 @@ Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) { ...@@ -897,7 +897,7 @@ Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) {
memcpy(destination, wire_bytes.start(), wire_bytes.size()); memcpy(destination, wire_bytes.start(), wire_bytes.size());
} }
wasm::WasmSerializer wasm_serializer(isolate_, native_module); wasm::WasmSerializer wasm_serializer(native_module);
size_t module_size = wasm_serializer.GetSerializedNativeModuleSize(); size_t module_size = wasm_serializer.GetSerializedNativeModuleSize();
CHECK_GE(std::numeric_limits<uint32_t>::max(), module_size); CHECK_GE(std::numeric_limits<uint32_t>::max(), module_size);
WriteVarint<uint32_t>(static_cast<uint32_t>(module_size)); WriteVarint<uint32_t>(static_cast<uint32_t>(module_size));
......
...@@ -197,13 +197,68 @@ constexpr size_t kCodeHeaderSize = ...@@ -197,13 +197,68 @@ constexpr size_t kCodeHeaderSize =
sizeof(size_t) + // protected instructions size sizeof(size_t) + // protected instructions size
sizeof(WasmCode::Tier); // tier sizeof(WasmCode::Tier); // tier
// A List of all isolate-independent external references. This is used to create
// a tag from the Address of an external reference and vice versa.
class ExternalReferenceList {
public:
uint32_t tag_from_address(Address ext_ref_address) const {
auto tag_addr_less_than = [this](uint32_t tag, Address searched_addr) {
return external_reference_by_tag_[tag] < searched_addr;
};
auto it = std::lower_bound(std::begin(tags_ordered_by_address_),
std::end(tags_ordered_by_address_),
ext_ref_address, tag_addr_less_than);
DCHECK_NE(std::end(tags_ordered_by_address_), it);
uint32_t tag = *it;
DCHECK_EQ(address_from_tag(tag), ext_ref_address);
return tag;
}
Address address_from_tag(uint32_t tag) const {
DCHECK_GT(kNumExternalReferences, tag);
return external_reference_by_tag_[tag];
}
static const ExternalReferenceList& Get() {
static ExternalReferenceList list; // Lazily initialized.
return list;
}
private:
// Private constructor. There will only be a single instance of this object.
ExternalReferenceList() {
for (uint32_t i = 0; i < kNumExternalReferences; ++i) {
tags_ordered_by_address_[i] = i;
}
auto addr_by_tag_less_than = [this](uint32_t a, uint32_t b) {
return external_reference_by_tag_[a] < external_reference_by_tag_[b];
};
std::sort(std::begin(tags_ordered_by_address_),
std::end(tags_ordered_by_address_), addr_by_tag_less_than);
}
#define COUNT_EXTERNAL_REFERENCE(name, desc) +1
static constexpr uint32_t kNumExternalReferences =
EXTERNAL_REFERENCE_LIST(COUNT_EXTERNAL_REFERENCE);
#undef COUNT_EXTERNAL_REFERENCE
#define EXT_REF_ADDR(name, desc) ExternalReference::name().address(),
Address external_reference_by_tag_[kNumExternalReferences] = {
EXTERNAL_REFERENCE_LIST(EXT_REF_ADDR)};
#undef EXT_REF_ADDR
uint32_t tags_ordered_by_address_[kNumExternalReferences];
DISALLOW_COPY_AND_ASSIGN(ExternalReferenceList);
};
static_assert(std::is_trivially_destructible<ExternalReferenceList>::value,
"static destructors not allowed");
} // namespace } // namespace
class V8_EXPORT_PRIVATE NativeModuleSerializer { class V8_EXPORT_PRIVATE NativeModuleSerializer {
public: public:
NativeModuleSerializer() = delete; NativeModuleSerializer() = delete;
NativeModuleSerializer(Isolate*, const NativeModule*, NativeModuleSerializer(const NativeModule*, Vector<WasmCode* const>);
Vector<WasmCode* const>);
size_t Measure() const; size_t Measure() const;
bool Write(Writer* writer); bool Write(Writer* writer);
...@@ -213,26 +268,19 @@ class V8_EXPORT_PRIVATE NativeModuleSerializer { ...@@ -213,26 +268,19 @@ class V8_EXPORT_PRIVATE NativeModuleSerializer {
void WriteHeader(Writer* writer); void WriteHeader(Writer* writer);
void WriteCode(const WasmCode*, Writer* writer); void WriteCode(const WasmCode*, Writer* writer);
Isolate* const isolate_;
const NativeModule* const native_module_; const NativeModule* const native_module_;
Vector<WasmCode* const> code_table_; Vector<WasmCode* const> code_table_;
bool write_called_; bool write_called_;
// Reverse lookup tables for embedded addresses. // Reverse lookup tables for embedded addresses.
std::map<Address, uint32_t> wasm_stub_targets_lookup_; std::map<Address, uint32_t> wasm_stub_targets_lookup_;
std::map<Address, uint32_t> reference_table_lookup_;
DISALLOW_COPY_AND_ASSIGN(NativeModuleSerializer); DISALLOW_COPY_AND_ASSIGN(NativeModuleSerializer);
}; };
NativeModuleSerializer::NativeModuleSerializer( NativeModuleSerializer::NativeModuleSerializer(
Isolate* isolate, const NativeModule* module, const NativeModule* module, Vector<WasmCode* const> code_table)
Vector<WasmCode* const> code_table) : native_module_(module), code_table_(code_table), write_called_(false) {
: isolate_(isolate),
native_module_(module),
code_table_(code_table),
write_called_(false) {
DCHECK_NOT_NULL(isolate_);
DCHECK_NOT_NULL(native_module_); DCHECK_NOT_NULL(native_module_);
// TODO(mtrofin): persist the export wrappers. Ideally, we'd only persist // TODO(mtrofin): persist the export wrappers. Ideally, we'd only persist
// the unique ones, i.e. the cache. // the unique ones, i.e. the cache.
...@@ -242,11 +290,6 @@ NativeModuleSerializer::NativeModuleSerializer( ...@@ -242,11 +290,6 @@ NativeModuleSerializer::NativeModuleSerializer(
->instruction_start(); ->instruction_start();
wasm_stub_targets_lookup_.insert(std::make_pair(addr, i)); wasm_stub_targets_lookup_.insert(std::make_pair(addr, i));
} }
ExternalReferenceTable* table = isolate_->external_reference_table();
for (uint32_t i = 0; i < ExternalReferenceTable::kSize; ++i) {
Address addr = table->address(i);
reference_table_lookup_.insert(std::make_pair(addr, i));
}
} }
size_t NativeModuleSerializer::MeasureCode(const WasmCode* code) const { size_t NativeModuleSerializer::MeasureCode(const WasmCode* code) const {
...@@ -342,10 +385,9 @@ void NativeModuleSerializer::WriteCode(const WasmCode* code, Writer* writer) { ...@@ -342,10 +385,9 @@ void NativeModuleSerializer::WriteCode(const WasmCode* code, Writer* writer) {
} break; } break;
case RelocInfo::EXTERNAL_REFERENCE: { case RelocInfo::EXTERNAL_REFERENCE: {
Address orig_target = orig_iter.rinfo()->target_external_reference(); Address orig_target = orig_iter.rinfo()->target_external_reference();
auto ref_iter = reference_table_lookup_.find(orig_target); uint32_t ext_ref_tag =
DCHECK(ref_iter != reference_table_lookup_.end()); ExternalReferenceList::Get().tag_from_address(orig_target);
uint32_t tag = ref_iter->second; SetWasmCalleeTag(iter.rinfo(), ext_ref_tag);
SetWasmCalleeTag(iter.rinfo(), tag);
} break; } break;
case RelocInfo::INTERNAL_REFERENCE: case RelocInfo::INTERNAL_REFERENCE:
case RelocInfo::INTERNAL_REFERENCE_ENCODED: { case RelocInfo::INTERNAL_REFERENCE_ENCODED: {
...@@ -376,20 +418,17 @@ bool NativeModuleSerializer::Write(Writer* writer) { ...@@ -376,20 +418,17 @@ bool NativeModuleSerializer::Write(Writer* writer) {
return true; return true;
} }
WasmSerializer::WasmSerializer(Isolate* isolate, NativeModule* native_module) WasmSerializer::WasmSerializer(NativeModule* native_module)
: isolate_(isolate), : native_module_(native_module),
native_module_(native_module),
code_table_(native_module->SnapshotCodeTable()) {} code_table_(native_module->SnapshotCodeTable()) {}
size_t WasmSerializer::GetSerializedNativeModuleSize() const { size_t WasmSerializer::GetSerializedNativeModuleSize() const {
NativeModuleSerializer serializer(isolate_, native_module_, NativeModuleSerializer serializer(native_module_, VectorOf(code_table_));
VectorOf(code_table_));
return kVersionSize + serializer.Measure(); return kVersionSize + serializer.Measure();
} }
bool WasmSerializer::SerializeNativeModule(Vector<byte> buffer) const { bool WasmSerializer::SerializeNativeModule(Vector<byte> buffer) const {
NativeModuleSerializer serializer(isolate_, native_module_, NativeModuleSerializer serializer(native_module_, VectorOf(code_table_));
VectorOf(code_table_));
size_t measured_size = kVersionSize + serializer.Measure(); size_t measured_size = kVersionSize + serializer.Measure();
if (buffer.size() < measured_size) return false; if (buffer.size() < measured_size) return false;
...@@ -404,7 +443,7 @@ bool WasmSerializer::SerializeNativeModule(Vector<byte> buffer) const { ...@@ -404,7 +443,7 @@ bool WasmSerializer::SerializeNativeModule(Vector<byte> buffer) const {
class V8_EXPORT_PRIVATE NativeModuleDeserializer { class V8_EXPORT_PRIVATE NativeModuleDeserializer {
public: public:
NativeModuleDeserializer() = delete; NativeModuleDeserializer() = delete;
NativeModuleDeserializer(Isolate*, NativeModule*); explicit NativeModuleDeserializer(NativeModule*);
bool Read(Reader* reader); bool Read(Reader* reader);
...@@ -412,16 +451,14 @@ class V8_EXPORT_PRIVATE NativeModuleDeserializer { ...@@ -412,16 +451,14 @@ class V8_EXPORT_PRIVATE NativeModuleDeserializer {
bool ReadHeader(Reader* reader); bool ReadHeader(Reader* reader);
bool ReadCode(uint32_t fn_index, Reader* reader); bool ReadCode(uint32_t fn_index, Reader* reader);
Isolate* const isolate_;
NativeModule* const native_module_; NativeModule* const native_module_;
bool read_called_; bool read_called_;
DISALLOW_COPY_AND_ASSIGN(NativeModuleDeserializer); DISALLOW_COPY_AND_ASSIGN(NativeModuleDeserializer);
}; };
NativeModuleDeserializer::NativeModuleDeserializer(Isolate* isolate, NativeModuleDeserializer::NativeModuleDeserializer(NativeModule* native_module)
NativeModule* native_module) : native_module_(native_module), read_called_(false) {}
: isolate_(isolate), native_module_(native_module), read_called_(false) {}
bool NativeModuleDeserializer::Read(Reader* reader) { bool NativeModuleDeserializer::Read(Reader* reader) {
DCHECK(!read_called_); DCHECK(!read_called_);
...@@ -503,7 +540,7 @@ bool NativeModuleDeserializer::ReadCode(uint32_t fn_index, Reader* reader) { ...@@ -503,7 +540,7 @@ bool NativeModuleDeserializer::ReadCode(uint32_t fn_index, Reader* reader) {
} }
case RelocInfo::EXTERNAL_REFERENCE: { case RelocInfo::EXTERNAL_REFERENCE: {
uint32_t tag = GetWasmCalleeTag(iter.rinfo()); uint32_t tag = GetWasmCalleeTag(iter.rinfo());
Address address = isolate_->external_reference_table()->address(tag); Address address = ExternalReferenceList::Get().address_from_tag(tag);
iter.rinfo()->set_target_external_reference(address, SKIP_ICACHE_FLUSH); iter.rinfo()->set_target_external_reference(address, SKIP_ICACHE_FLUSH);
break; break;
} }
...@@ -564,7 +601,7 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule( ...@@ -564,7 +601,7 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
if (FLAG_wasm_lazy_compilation) { if (FLAG_wasm_lazy_compilation) {
native_module->SetLazyBuiltin(BUILTIN_CODE(isolate, WasmCompileLazy)); native_module->SetLazyBuiltin(BUILTIN_CODE(isolate, WasmCompileLazy));
} }
NativeModuleDeserializer deserializer(isolate, native_module); NativeModuleDeserializer deserializer(native_module);
Reader reader(data + kVersionSize); Reader reader(data + kVersionSize);
if (!deserializer.Read(&reader)) return {}; if (!deserializer.Read(&reader)) return {};
......
...@@ -16,7 +16,7 @@ namespace wasm { ...@@ -16,7 +16,7 @@ namespace wasm {
// the module after that won't affect the serialized result. // the module after that won't affect the serialized result.
class WasmSerializer { class WasmSerializer {
public: public:
WasmSerializer(Isolate* isolate, NativeModule* native_module); explicit WasmSerializer(NativeModule* native_module);
// Measure the required buffer size needed for serialization. // Measure the required buffer size needed for serialization.
size_t GetSerializedNativeModuleSize() const; size_t GetSerializedNativeModuleSize() const;
...@@ -26,7 +26,6 @@ class WasmSerializer { ...@@ -26,7 +26,6 @@ class WasmSerializer {
bool SerializeNativeModule(Vector<byte> buffer) const; bool SerializeNativeModule(Vector<byte> buffer) const;
private: private:
Isolate* isolate_;
NativeModule* native_module_; NativeModule* native_module_;
std::vector<WasmCode*> code_table_; std::vector<WasmCode*> code_table_;
}; };
...@@ -35,7 +34,7 @@ class WasmSerializer { ...@@ -35,7 +34,7 @@ class WasmSerializer {
// Checks the version header of the data against the current version. // Checks the version header of the data against the current version.
bool IsSupportedVersion(Vector<const byte> data); bool IsSupportedVersion(Vector<const byte> data);
// Deserializes the given data to create a compiled Wasm module. // Deserializes the given data to create a Wasm module object.
MaybeHandle<WasmModuleObject> DeserializeNativeModule( MaybeHandle<WasmModuleObject> DeserializeNativeModule(
Isolate* isolate, Vector<const byte> data, Vector<const byte> wire_bytes); Isolate* isolate, Vector<const byte> data, Vector<const byte> wire_bytes);
......
...@@ -212,8 +212,7 @@ ZoneBuffer GetValidCompiledModuleBytes(Zone* zone, ZoneBuffer wire_bytes) { ...@@ -212,8 +212,7 @@ ZoneBuffer GetValidCompiledModuleBytes(Zone* zone, ZoneBuffer wire_bytes) {
// Serialize the NativeModule. // Serialize the NativeModule.
std::shared_ptr<NativeModule> native_module = tester.native_module(); std::shared_ptr<NativeModule> native_module = tester.native_module();
CHECK(native_module); CHECK(native_module);
i::wasm::WasmSerializer serializer( i::wasm::WasmSerializer serializer(native_module.get());
reinterpret_cast<i::Isolate*>(CcTest::i_isolate()), native_module.get());
size_t size = serializer.GetSerializedNativeModuleSize(); size_t size = serializer.GetSerializedNativeModuleSize();
std::vector<byte> buffer(size); std::vector<byte> buffer(size);
CHECK(serializer.SerializeNativeModule({buffer.data(), size})); CHECK(serializer.SerializeNativeModule({buffer.data(), size}));
......
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