Bug 1471500 - Complete initial implementation of the bulk-memory proposal. Part 5 of 10. r=bbouvier.

At run time, the implementation of {memory,table}.init needs to know the
actual bytes to be copied to complete the required initialisations, for
passive initialisers.  It seems simplest to compute them exactly at
instantiation time, and have the computed data owned by the instance.

This also means it is possible for that data to be released by
{memory,table}.drop, independently of all other instances.

This patch adds new types DataSegmentInit, ElemSegmentInit,
DataSegmentInitVector, and ElemSegmentInitVector to hold this data.  They are
explained in detail in a comment in WasmTypes.h.

For a data segment, the initialising values for a memory are merely bytes, but
for a table it is more complex -- a pair of (entry point, instance pointer).
This patch also adds a type WasmCallee to encapsulate that.

--HG--
extra : rebase_source : adaee69ee3662432bd2fc6e9924b8ce8093a7a46
This commit is contained in:
Julian Seward 2018-09-10 15:09:32 +02:00
Родитель 84c591be8c
Коммит 86b79103eb
3 изменённых файлов: 56 добавлений и 7 удалений

Просмотреть файл

@ -55,6 +55,8 @@ class Instance
const UniqueTlsData tlsData_;
GCPtrWasmMemoryObject memory_;
SharedTableVector tables_;
DataSegmentInitVector dataSegInitVec_;
ElemSegmentInitVector elemSegInitVec_;
bool enterFrameTrapsEnabled_;
// Internal helpers:
@ -97,6 +99,8 @@ class Instance
const Metadata& metadata() const { return code_->metadata(); }
bool isAsmJS() const { return metadata().isAsmJS(); }
const SharedTableVector& tables() const { return tables_; }
DataSegmentInitVector& dataSegInitVec() { return dataSegInitVec_; }
ElemSegmentInitVector& elemSegInitVec() { return elemSegInitVec_; }
SharedMem<uint8_t*> memoryBase() const;
WasmMemoryObject* memory() const;
size_t memoryMappedSize() const;

Просмотреть файл

@ -950,26 +950,26 @@ Module::instantiate(JSContext* cx,
return false;
ElemSegmentVector elemSegments;
for (const ElemSegment& eseg : code_->elemSegments()) {
for (const ElemSegment& seg : code_->elemSegments()) {
// This (debugging) code path is called only for tier 1.
MOZ_ASSERT(eseg.elemCodeRangeIndices2_.empty());
MOZ_ASSERT(seg.elemCodeRangeIndices2_.empty());
// ElemSegment doesn't have a (fallible) copy constructor,
// so we have to clone it "by hand".
ElemSegment clone;
clone.tableIndex = eseg.tableIndex;
clone.offset = eseg.offset;
clone.tableIndex = seg.tableIndex;
clone.offset = seg.offset;
MOZ_ASSERT(clone.elemFuncIndices.empty());
if (!clone.elemFuncIndices.appendAll(eseg.elemFuncIndices))
if (!clone.elemFuncIndices.appendAll(seg.elemFuncIndices))
return false;
MOZ_ASSERT(clone.elemCodeRangeIndices1_.empty());
if (!clone.elemCodeRangeIndices1_.appendAll(eseg.elemCodeRangeIndices1_))
if (!clone.elemCodeRangeIndices1_.appendAll(seg.elemCodeRangeIndices1_))
return false;
MOZ_ASSERT(clone.elemCodeRangeIndices2_.empty());
if (!clone.elemCodeRangeIndices2_.appendAll(eseg.elemCodeRangeIndices2_))
if (!clone.elemCodeRangeIndices2_.appendAll(seg.elemCodeRangeIndices2_))
return false;
if (!elemSegments.append(std::move(clone)))

Просмотреть файл

@ -1122,6 +1122,51 @@ struct DataSegment
typedef Vector<DataSegment, 0, SystemAllocPolicy> DataSegmentVector;
// A pairing of entry point and instance pointer, used for lazy table
// initialisation.
struct WasmCallee
{
WasmCallee() : instance(nullptr), entry(nullptr) {}
WasmCallee(const Instance* instance, void* entry)
: instance(instance),
entry(entry)
{}
// The instance associated with the code address.
const Instance* instance;
// The table entry code address.
void* entry;
};
// Support for passive data and element segments -- lazy initialisation.
//
// At instantiation time, we prepare the required initialising data for each
// passive segment, copying it into new memory. This is done separately for
// data segments and elem segments. We also create a vector of pointers to
// this copied data, with nullptr for entries corresponding to active
// segments. This vector has the same length as the vector of data/elem
// segments respectively in the originating module.
//
// The vector of pointers and the prepared data are owned by the instance
// that is constructed. We have to do this so that the initialising data is
// available at run time in the instance, in particular to
// Instance::{mem,table}{Init,Drop}.
//
// The final structures have type DataSegmentInitVector and
// ElemSegmentInitVector respectively.
typedef Vector<uint8_t, 0, SystemAllocPolicy> DataSegmentInit;
typedef Vector<WasmCallee, 0, SystemAllocPolicy> ElemSegmentInit;
// We store (unique) pointers rather than references to the initialising
// vectors in order that they can be incrementally freed as we execute
// {memory,table}.drop instructions.
typedef Vector<UniquePtr<DataSegmentInit>, 0, SystemAllocPolicy>
DataSegmentInitVector;
typedef Vector<UniquePtr<ElemSegmentInit>, 0, SystemAllocPolicy>
ElemSegmentInitVector;
// FuncTypeIdDesc describes a function type that can be used by call_indirect
// and table-entry prologues to structurally compare whether the caller and
// callee's signatures *structurally* match. To handle the general case, a