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() {
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(obj->GetIsolate(), 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}))
......
......@@ -965,7 +965,7 @@ RUNTIME_FUNCTION(Runtime_SerializeWasmModule) {
CONVERT_ARG_HANDLE_CHECKED(WasmModuleObject, module_obj, 0);
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();
void* array_data = isolate->array_buffer_allocator()->Allocate(compiled_size);
Handle<JSArrayBuffer> array_buffer = isolate->factory()->NewJSArrayBuffer();
......
......@@ -897,7 +897,7 @@ Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) {
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();
CHECK_GE(std::numeric_limits<uint32_t>::max(), module_size);
WriteVarint<uint32_t>(static_cast<uint32_t>(module_size));
......
......@@ -197,13 +197,68 @@ constexpr size_t kCodeHeaderSize =
sizeof(size_t) + // protected instructions size
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
class V8_EXPORT_PRIVATE NativeModuleSerializer {
public:
NativeModuleSerializer() = delete;
NativeModuleSerializer(Isolate*, const NativeModule*,
Vector<WasmCode* const>);
NativeModuleSerializer(const NativeModule*, Vector<WasmCode* const>);
size_t Measure() const;
bool Write(Writer* writer);
......@@ -213,26 +268,19 @@ class V8_EXPORT_PRIVATE NativeModuleSerializer {
void WriteHeader(Writer* writer);
void WriteCode(const WasmCode*, Writer* writer);
Isolate* const isolate_;
const NativeModule* const native_module_;
Vector<WasmCode* const> code_table_;
bool write_called_;
// Reverse lookup tables for embedded addresses.
std::map<Address, uint32_t> wasm_stub_targets_lookup_;
std::map<Address, uint32_t> reference_table_lookup_;
DISALLOW_COPY_AND_ASSIGN(NativeModuleSerializer);
};
NativeModuleSerializer::NativeModuleSerializer(
Isolate* isolate, const NativeModule* module,
Vector<WasmCode* const> code_table)
: isolate_(isolate),
native_module_(module),
code_table_(code_table),
write_called_(false) {
DCHECK_NOT_NULL(isolate_);
const NativeModule* module, Vector<WasmCode* const> code_table)
: native_module_(module), code_table_(code_table), write_called_(false) {
DCHECK_NOT_NULL(native_module_);
// TODO(mtrofin): persist the export wrappers. Ideally, we'd only persist
// the unique ones, i.e. the cache.
......@@ -242,11 +290,6 @@ NativeModuleSerializer::NativeModuleSerializer(
->instruction_start();
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 {
......@@ -342,10 +385,9 @@ void NativeModuleSerializer::WriteCode(const WasmCode* code, Writer* writer) {
} break;
case RelocInfo::EXTERNAL_REFERENCE: {
Address orig_target = orig_iter.rinfo()->target_external_reference();
auto ref_iter = reference_table_lookup_.find(orig_target);
DCHECK(ref_iter != reference_table_lookup_.end());
uint32_t tag = ref_iter->second;
SetWasmCalleeTag(iter.rinfo(), tag);
uint32_t ext_ref_tag =
ExternalReferenceList::Get().tag_from_address(orig_target);
SetWasmCalleeTag(iter.rinfo(), ext_ref_tag);
} break;
case RelocInfo::INTERNAL_REFERENCE:
case RelocInfo::INTERNAL_REFERENCE_ENCODED: {
......@@ -376,20 +418,17 @@ bool NativeModuleSerializer::Write(Writer* writer) {
return true;
}
WasmSerializer::WasmSerializer(Isolate* isolate, NativeModule* native_module)
: isolate_(isolate),
native_module_(native_module),
WasmSerializer::WasmSerializer(NativeModule* native_module)
: native_module_(native_module),
code_table_(native_module->SnapshotCodeTable()) {}
size_t WasmSerializer::GetSerializedNativeModuleSize() const {
NativeModuleSerializer serializer(isolate_, native_module_,
VectorOf(code_table_));
NativeModuleSerializer serializer(native_module_, VectorOf(code_table_));
return kVersionSize + serializer.Measure();
}
bool WasmSerializer::SerializeNativeModule(Vector<byte> buffer) const {
NativeModuleSerializer serializer(isolate_, native_module_,
VectorOf(code_table_));
NativeModuleSerializer serializer(native_module_, VectorOf(code_table_));
size_t measured_size = kVersionSize + serializer.Measure();
if (buffer.size() < measured_size) return false;
......@@ -404,7 +443,7 @@ bool WasmSerializer::SerializeNativeModule(Vector<byte> buffer) const {
class V8_EXPORT_PRIVATE NativeModuleDeserializer {
public:
NativeModuleDeserializer() = delete;
NativeModuleDeserializer(Isolate*, NativeModule*);
explicit NativeModuleDeserializer(NativeModule*);
bool Read(Reader* reader);
......@@ -412,16 +451,14 @@ class V8_EXPORT_PRIVATE NativeModuleDeserializer {
bool ReadHeader(Reader* reader);
bool ReadCode(uint32_t fn_index, Reader* reader);
Isolate* const isolate_;
NativeModule* const native_module_;
bool read_called_;
DISALLOW_COPY_AND_ASSIGN(NativeModuleDeserializer);
};
NativeModuleDeserializer::NativeModuleDeserializer(Isolate* isolate,
NativeModule* native_module)
: isolate_(isolate), native_module_(native_module), read_called_(false) {}
NativeModuleDeserializer::NativeModuleDeserializer(NativeModule* native_module)
: native_module_(native_module), read_called_(false) {}
bool NativeModuleDeserializer::Read(Reader* reader) {
DCHECK(!read_called_);
......@@ -503,7 +540,7 @@ bool NativeModuleDeserializer::ReadCode(uint32_t fn_index, Reader* reader) {
}
case RelocInfo::EXTERNAL_REFERENCE: {
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);
break;
}
......@@ -564,7 +601,7 @@ MaybeHandle<WasmModuleObject> DeserializeNativeModule(
if (FLAG_wasm_lazy_compilation) {
native_module->SetLazyBuiltin(BUILTIN_CODE(isolate, WasmCompileLazy));
}
NativeModuleDeserializer deserializer(isolate, native_module);
NativeModuleDeserializer deserializer(native_module);
Reader reader(data + kVersionSize);
if (!deserializer.Read(&reader)) return {};
......
......@@ -16,7 +16,7 @@ namespace wasm {
// the module after that won't affect the serialized result.
class WasmSerializer {
public:
WasmSerializer(Isolate* isolate, NativeModule* native_module);
explicit WasmSerializer(NativeModule* native_module);
// Measure the required buffer size needed for serialization.
size_t GetSerializedNativeModuleSize() const;
......@@ -26,7 +26,6 @@ class WasmSerializer {
bool SerializeNativeModule(Vector<byte> buffer) const;
private:
Isolate* isolate_;
NativeModule* native_module_;
std::vector<WasmCode*> code_table_;
};
......@@ -35,7 +34,7 @@ class WasmSerializer {
// Checks the version header of the data against the current version.
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(
Isolate* isolate, Vector<const byte> data, Vector<const byte> wire_bytes);
......
......@@ -212,8 +212,7 @@ ZoneBuffer GetValidCompiledModuleBytes(Zone* zone, ZoneBuffer wire_bytes) {
// Serialize the NativeModule.
std::shared_ptr<NativeModule> native_module = tester.native_module();
CHECK(native_module);
i::wasm::WasmSerializer serializer(
reinterpret_cast<i::Isolate*>(CcTest::i_isolate()), native_module.get());
i::wasm::WasmSerializer serializer(native_module.get());
size_t size = serializer.GetSerializedNativeModuleSize();
std::vector<byte> buffer(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