Bug 1310949: Factor out DecodeMemorySection and properly render it; r=luke

MozReview-Commit-ID: D6WDtpzCXeX

--HG--
extra : rebase_source : 430c6ab76db1cff541f75bae7a02e4aa9a334096
This commit is contained in:
Benjamin Bouvier 2016-10-21 16:14:12 +02:00
Родитель f053c45f0d
Коммит d61d3482c4
9 изменённых файлов: 293 добавлений и 150 удалений

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

@ -649,15 +649,15 @@ class AstImport : public AstNode
DefinitionKind kind_;
AstRef funcSig_;
Limits resizable_;
Limits limits_;
AstGlobal global_;
public:
AstImport(AstName name, AstName module, AstName field, AstRef funcSig)
: name_(name), module_(module), field_(field), kind_(DefinitionKind::Function), funcSig_(funcSig)
{}
AstImport(AstName name, AstName module, AstName field, DefinitionKind kind, Limits resizable)
: name_(name), module_(module), field_(field), kind_(kind), resizable_(resizable)
AstImport(AstName name, AstName module, AstName field, DefinitionKind kind, Limits limits)
: name_(name), module_(module), field_(field), kind_(kind), limits_(limits)
{}
AstImport(AstName name, AstName module, AstName field, AstGlobal global)
: name_(name), module_(module), field_(field), kind_(DefinitionKind::Global), global_(global)
@ -672,9 +672,9 @@ class AstImport : public AstNode
MOZ_ASSERT(kind_ == DefinitionKind::Function);
return funcSig_;
}
Limits resizable() const {
Limits limits() const {
MOZ_ASSERT(kind_ == DefinitionKind::Memory || kind_ == DefinitionKind::Table);
return resizable_;
return limits_;
}
const AstGlobal& global() const {
MOZ_ASSERT(kind_ == DefinitionKind::Global);
@ -750,6 +750,17 @@ class AstStartFunc : public AstNode
}
};
struct AstResizable
{
Limits limits;
bool imported;
AstResizable(Limits limits, bool imported)
: limits(limits),
imported(imported)
{}
};
class AstModule : public AstNode
{
public:
@ -758,6 +769,7 @@ class AstModule : public AstNode
typedef AstVector<AstExport*> ExportVector;
typedef AstVector<AstSig*> SigVector;
typedef AstVector<AstName> NameVector;
typedef AstVector<AstResizable> AstResizableVector;
private:
typedef AstHashMap<AstSig*, uint32_t, AstSig> SigMap;
@ -767,8 +779,8 @@ class AstModule : public AstNode
SigMap sigMap_;
ImportVector imports_;
NameVector funcImportNames_;
Maybe<Limits> table_;
Maybe<Limits> memory_;
AstResizableVector tables_;
AstResizableVector memories_;
ExportVector exports_;
Maybe<AstStartFunc> startFunc_;
FuncVector funcs_;
@ -783,6 +795,8 @@ class AstModule : public AstNode
sigMap_(lifo),
imports_(lifo),
funcImportNames_(lifo),
tables_(lifo),
memories_(lifo),
exports_(lifo),
funcs_(lifo),
dataSegments_(lifo),
@ -792,29 +806,23 @@ class AstModule : public AstNode
bool init() {
return sigMap_.init();
}
bool setMemory(Limits memory) {
if (memory_)
return false;
memory_.emplace(memory);
return true;
bool addMemory(Limits memory) {
return memories_.append(AstResizable(memory, false));
}
bool hasMemory() const {
return !!memory_;
return !!memories_.length();
}
const Limits& memory() const {
return *memory_;
const AstResizableVector& memories() const {
return memories_;
}
bool setTable(Limits table) {
if (table_)
return false;
table_.emplace(table);
return true;
bool addTable(Limits table) {
return tables_.append(AstResizable(table, false));
}
bool hasTable() const {
return !!table_;
return !!tables_.length();
}
const Limits& table() const {
return *table_;
const AstResizableVector& tables() const {
return tables_;
}
bool append(AstDataSegment* seg) {
return dataSegments_.append(seg);
@ -869,9 +877,21 @@ class AstModule : public AstNode
return funcs_;
}
bool append(AstImport* imp) {
if (imp->kind() == DefinitionKind::Function) {
switch (imp->kind()) {
case DefinitionKind::Function:
if (!funcImportNames_.append(imp->name()))
return false;
break;
case DefinitionKind::Table:
if (!tables_.append(AstResizable(imp->limits(), true)))
return false;
break;
case DefinitionKind::Memory:
if (!memories_.append(AstResizable(imp->limits(), true)))
return false;
break;
case DefinitionKind::Global:
break;
}
return imports_.append(imp);

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

@ -18,11 +18,15 @@
#include "asmjs/WasmBinaryFormat.h"
#include "mozilla/CheckedInt.h"
#include "jsprf.h"
using namespace js;
using namespace js::wasm;
using mozilla::CheckedInt;
bool
wasm::DecodePreamble(Decoder& d)
{
@ -268,6 +272,63 @@ wasm::DecodeDataSection(Decoder& d, bool usesMemory, uint32_t minMemoryByteLengt
return true;
}
bool
wasm::DecodeMemoryLimits(Decoder& d, bool hasMemory, Limits* memory)
{
if (hasMemory)
return d.fail("already have default memory");
if (!DecodeLimits(d, memory))
return false;
CheckedInt<uint32_t> initialBytes = memory->initial;
initialBytes *= PageSize;
if (!initialBytes.isValid() || initialBytes.value() > uint32_t(INT32_MAX))
return d.fail("initial memory size too big");
memory->initial = initialBytes.value();
if (memory->maximum) {
CheckedInt<uint32_t> maximumBytes = *memory->maximum;
maximumBytes *= PageSize;
if (!maximumBytes.isValid())
return d.fail("maximum memory size too big");
memory->maximum = Some(maximumBytes.value());
}
return true;
}
bool
wasm::DecodeMemorySection(Decoder& d, bool hasMemory, Limits* memory, bool *present)
{
*present = false;
uint32_t sectionStart, sectionSize;
if (!d.startSection(SectionId::Memory, &sectionStart, &sectionSize, "memory"))
return false;
if (sectionStart == Decoder::NotStarted)
return true;
*present = true;
uint32_t numMemories;
if (!d.readVarU32(&numMemories))
return d.fail("failed to read number of memories");
if (numMemories != 1)
return d.fail("the number of memories must be exactly one");
if (!DecodeMemoryLimits(d, hasMemory, memory))
return false;
if (!d.finishSection(sectionStart, sectionSize, "memory"))
return false;
return true;
}
bool
wasm::DecodeUnknownSections(Decoder& d)
{

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

@ -55,6 +55,12 @@ MOZ_MUST_USE bool
DecodeDataSection(Decoder& d, bool usesMemory, uint32_t minMemoryByteLength,
const GlobalDescVector& globals, DataSegmentVector* segments);
MOZ_MUST_USE bool
DecodeMemoryLimits(Decoder& d, bool hasMemory, Limits* memory);
MOZ_MUST_USE bool
DecodeMemorySection(Decoder& d, bool hasMemory, Limits* memory, bool* present);
} // namespace wasm
} // namespace js

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

@ -1573,9 +1573,12 @@ AstDecodeTableSection(AstDecodeContext& c)
if (table.initial > MaxTableElems)
return c.d.fail("too many table elements");
if (!c.module().setTable(table))
if (c.module().hasTable())
return c.d.fail("already have a table");
if (!c.module().addTable(table))
return false;
if (!c.d.finishSection(sectionStart, sectionSize, "table"))
return false;
@ -1670,6 +1673,9 @@ AstDecodeImport(AstDecodeContext& c, uint32_t importIndex, AstImport** import)
break;
}
case uint32_t(DefinitionKind::Table): {
if (c.module().hasTable())
return c.d.fail("already have default table");
AstName importName;
if (!AstDecodeGenerateName(c, AstName(u"table"), importIndex, &importName))
return false;
@ -1688,7 +1694,7 @@ AstDecodeImport(AstDecodeContext& c, uint32_t importIndex, AstImport** import)
return false;
Limits memory;
if (!DecodeLimits(c.d, &memory))
if (!DecodeMemoryLimits(c.d, c.module().hasMemory(), &memory))
return false;
*import = new(c.lifo) AstImport(importName, moduleName, fieldName,
@ -1738,27 +1744,16 @@ AstDecodeImportSection(AstDecodeContext& c)
static bool
AstDecodeMemorySection(AstDecodeContext& c)
{
uint32_t sectionStart, sectionSize;
if (!c.d.startSection(SectionId::Memory, &sectionStart, &sectionSize, "memory"))
return false;
if (sectionStart == Decoder::NotStarted)
return true;
uint32_t numMemories;
if (!c.d.readVarU32(&numMemories))
return c.d.fail("failed to read number of memories");
if (numMemories != 1)
return c.d.fail("the number of memories must be exactly one");
bool present;
Limits memory;
if (!DecodeLimits(c.d, &memory))
if (!DecodeMemorySection(c.d, c.module().hasMemory(), &memory, &present))
return false;
if (!c.d.finishSection(sectionStart, sectionSize, "memory"))
return false;
if (present) {
if (!c.module().addMemory(memory))
return false;
}
c.module().setMemory(memory);
return true;
}
@ -2031,7 +2026,10 @@ AstDecodeDataSection(AstDecodeContext &c)
{
DataSegmentVector segments;
bool hasMemory = c.module().hasMemory();
uint32_t memByteLength = hasMemory ? c.module().memory().initial * PageSize : 0;
MOZ_ASSERT(c.module().memories().length() <= 1, "at most one memory in MVP");
uint32_t memByteLength = hasMemory ? c.module().memories()[0].limits.initial : 0;
if (!DecodeDataSection(c.d, hasMemory, memByteLength, c.globalDescs(), &segments))
return false;

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

@ -1757,23 +1757,29 @@ PrintCodeSection(WasmPrintContext& c, const AstModule::FuncVector& funcs, const
return true;
}
static bool
PrintDataSection(WasmPrintContext& c, const AstModule& module)
{
if (!module.hasMemory())
return true;
MOZ_ASSERT(module.memories().length() == 1, "NYI: several memories");
if (!PrintIndent(c))
return false;
if (!c.buffer.append("memory "))
return false;
if (!PrintInt32(c, module.memory().initial))
const Limits& memory = module.memories()[0].limits;
MOZ_ASSERT(memory.initial % PageSize == 0);
if (!PrintInt32(c, memory.initial / PageSize))
return false;
if (module.memory().maximum) {
if (memory.maximum) {
MOZ_ASSERT(*memory.maximum % PageSize == 0);
if (!c.buffer.append(", "))
return false;
if (!PrintInt32(c, *module.memory().maximum))
if (!PrintInt32(c, *memory.maximum / PageSize))
return false;
}

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

@ -1296,6 +1296,42 @@ RenderGlobalSection(WasmRenderContext& c, const AstModule& module)
return true;
}
static bool
RenderLimits(WasmRenderContext& c, const Limits& limits)
{
if (!RenderInt32(c, limits.initial))
return false;
if (limits.maximum) {
if (!c.buffer.append(" "))
return false;
if (!RenderInt32(c, *limits.maximum))
return false;
}
return true;
}
static bool
RenderResizableMemory(WasmRenderContext& c, Limits memory)
{
if (!c.buffer.append("(memory "))
return false;
MOZ_ASSERT(memory.initial % PageSize == 0);
memory.initial /= PageSize;
if (memory.maximum) {
MOZ_ASSERT(*memory.maximum % PageSize == 0);
*memory.maximum /= PageSize;
}
if (!RenderLimits(c, memory))
return false;
return c.buffer.append(")");
}
static bool
RenderImport(WasmRenderContext& c, AstImport& import, const AstModule& module)
{
@ -1334,7 +1370,8 @@ RenderImport(WasmRenderContext& c, AstImport& import, const AstModule& module)
break;
}
case DefinitionKind::Memory: {
// TODO next patch
if (!RenderResizableMemory(c, import.limits()))
return false;
break;
}
case DefinitionKind::Global: {
@ -1371,14 +1408,13 @@ RenderExport(WasmRenderContext& c, AstExport& export_,
return false;
if (!c.buffer.append("\" "))
return false;
if (export_.kind() == DefinitionKind::Memory) {
if (!c.buffer.append("memory"))
return false;
} else {
switch (export_.kind()) {
case DefinitionKind::Function: {
uint32_t index = export_.ref().index();
AstName name = index < funcImportNames.length()
? funcImportNames[index]
: funcs[index - funcImportNames.length()]->name();
? funcImportNames[index]
: funcs[index - funcImportNames.length()]->name();
if (name.empty()) {
if (!RenderInt32(c, index))
return false;
@ -1386,7 +1422,27 @@ RenderExport(WasmRenderContext& c, AstExport& export_,
if (!RenderName(c, name))
return false;
}
break;
}
case DefinitionKind::Table: {
if (!c.buffer.append("table"))
return false;
break;
}
case DefinitionKind::Memory: {
if (!c.buffer.append("memory"))
return false;
break;
}
case DefinitionKind::Global: {
if (!c.buffer.append("global"))
return false;
if (!RenderRef(c, export_.ref()))
return false;
break;
}
}
return c.buffer.append(")\n");
}
@ -1493,30 +1549,28 @@ RenderCodeSection(WasmRenderContext& c, const AstModule::FuncVector& funcs, cons
}
static bool
RenderDataSection(WasmRenderContext& c, const AstModule& module)
RenderMemorySection(WasmRenderContext& c, const AstModule& module)
{
if (!module.hasMemory())
return true;
if (!RenderIndent(c))
return false;
if (!c.buffer.append("(memory "))
return false;
if (!RenderInt32(c, module.memory().initial))
return false;
Maybe<uint32_t> memMax = module.memory().maximum;
if (memMax) {
if (!c.buffer.append(" "))
for (const AstResizable& memory : module.memories()) {
if (memory.imported)
continue;
if (!RenderIndent(c))
return false;
if (!RenderInt32(c, *memMax))
if (!RenderResizableMemory(c, memory.limits))
return false;
if (!c.buffer.append("\n"))
return false;
}
if (!c.buffer.append(")\n"))
return false;
return true;
}
static bool
RenderDataSection(WasmRenderContext& c, const AstModule& module)
{
uint32_t numSegments = module.dataSegments().length();
if (!numSegments)
return true;
@ -1565,6 +1619,9 @@ RenderModule(WasmRenderContext& c, AstModule& module)
if (!RenderCodeSection(c, module.funcs(), module.sigs()))
return false;
if (!RenderMemorySection(c, module))
return false;
if (!RenderDataSection(c, module))
return false;

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

@ -18,8 +18,6 @@
#include "asmjs/WasmCompile.h"
#include "mozilla/CheckedInt.h"
#include "jsprf.h"
#include "asmjs/WasmBinaryFormat.h"
@ -31,7 +29,6 @@ using namespace js;
using namespace js::jit;
using namespace js::wasm;
using mozilla::CheckedInt;
using mozilla::IsNaN;
namespace {
@ -569,33 +566,15 @@ DecodeName(Decoder& d)
}
static bool
DecodeResizableMemory(Decoder& d, ModuleGeneratorData* init)
DecodeMemoryLimits(Decoder& d, ModuleGeneratorData* init)
{
if (UsesMemory(init->memoryUsage))
return d.fail("already have default memory");
Limits limits;
if (!DecodeLimits(d, &limits))
Limits memory;
if (!DecodeMemoryLimits(d, UsesMemory(init->memoryUsage), &memory))
return false;
init->memoryUsage = MemoryUsage::Unshared;
CheckedInt<uint32_t> initialBytes = limits.initial;
initialBytes *= PageSize;
if (!initialBytes.isValid() || initialBytes.value() > uint32_t(INT32_MAX))
return d.fail("initial memory size too big");
init->minMemoryLength = initialBytes.value();
if (limits.maximum) {
CheckedInt<uint32_t> maximumBytes = *limits.maximum;
maximumBytes *= PageSize;
if (!maximumBytes.isValid())
return d.fail("maximum memory size too big");
init->maxMemoryLength = Some(maximumBytes.value());
}
init->minMemoryLength = memory.initial;
init->maxMemoryLength = memory.maximum;
return true;
}
@ -671,7 +650,7 @@ DecodeImport(Decoder& d, ModuleGeneratorData* init, ImportVector* imports)
break;
}
case DefinitionKind::Memory: {
if (!DecodeResizableMemory(d, init))
if (!DecodeMemoryLimits(d, init))
return false;
break;
}
@ -746,26 +725,18 @@ DecodeTableSection(Decoder& d, ModuleGeneratorData* init, Uint32Vector* oldElems
}
static bool
DecodeMemorySection(Decoder& d, ModuleGeneratorData* init, bool* exported)
DecodeMemorySection(Decoder& d, ModuleGeneratorData* init)
{
uint32_t sectionStart, sectionSize;
if (!d.startSection(SectionId::Memory, &sectionStart, &sectionSize, "memory"))
return false;
if (sectionStart == Decoder::NotStarted)
return true;
uint32_t numMemories;
if (!d.readVarU32(&numMemories))
return d.fail("failed to read number of memories");
if (numMemories != 1)
return d.fail("the number of memories must be exactly one");
if (!DecodeResizableMemory(d, init))
bool present;
Limits memory;
if (!DecodeMemorySection(d, UsesMemory(init->memoryUsage), &memory, &present))
return false;
if (!d.finishSection(sectionStart, sectionSize, "memory"))
return false;
if (present) {
init->memoryUsage = MemoryUsage::Unshared;
init->minMemoryLength = memory.initial;
init->maxMemoryLength = memory.maximum;
}
return true;
}
@ -893,7 +864,7 @@ DecodeExport(Decoder& d, ModuleGenerator& mg, CStringSet* dupSet)
}
static bool
DecodeExportSection(Decoder& d, bool memoryExported, ModuleGenerator& mg)
DecodeExportSection(Decoder& d, ModuleGenerator& mg)
{
uint32_t sectionStart, sectionSize;
if (!d.startSection(SectionId::Export, &sectionStart, &sectionSize, "export"))
@ -1213,8 +1184,7 @@ wasm::Compile(const ShareableBytes& bytecode, const CompileArgs& args, UniqueCha
if (!DecodeTableSection(d, init.get(), &oldElems))
return nullptr;
bool memoryExported = false;
if (!DecodeMemorySection(d, init.get(), &memoryExported))
if (!::DecodeMemorySection(d, init.get()))
return nullptr;
if (!DecodeGlobalSection(d, init.get()))
@ -1224,7 +1194,7 @@ wasm::Compile(const ShareableBytes& bytecode, const CompileArgs& args, UniqueCha
if (!mg.init(Move(init), args))
return nullptr;
if (!DecodeExportSection(d, memoryExported, mg))
if (!DecodeExportSection(d, mg))
return nullptr;
if (!DecodeStartSection(d, mg))

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

@ -2735,7 +2735,7 @@ ParseDataSegment(WasmParseContext& c)
}
static bool
ParseLimits(WasmParseContext& c, Limits* resizable)
ParseLimits(WasmParseContext& c, Limits* limits)
{
WasmToken initial;
if (!c.ts.match(WasmToken::Index, &initial, c.error))
@ -2747,7 +2747,7 @@ ParseLimits(WasmParseContext& c, Limits* resizable)
maximum.emplace(token.index());
Limits r = { initial.index(), maximum };
*resizable = r;
*limits = r;
return true;
}
@ -2805,7 +2805,7 @@ ParseMemory(WasmParseContext& c, WasmToken token, AstModule* module)
}
Limits memory = { uint32_t(pages), Some(uint32_t(pages)) };
if (!module->setMemory(memory))
if (!module->addMemory(memory))
return false;
if (!c.ts.match(WasmToken::CloseParen, c.error))
@ -2818,12 +2818,7 @@ ParseMemory(WasmParseContext& c, WasmToken token, AstModule* module)
if (!ParseLimits(c, &memory))
return false;
if (!module->setMemory(memory)) {
c.ts.generateError(token, c.error);
return false;
}
return true;
return module->addMemory(memory);
}
static bool
@ -3084,11 +3079,7 @@ ParseTable(WasmParseContext& c, WasmToken token, AstModule* module)
Limits table;
if (!ParseTableSig(c, &table))
return false;
if (!module->setTable(table)) {
c.ts.generateError(token, c.error);
return false;
}
return true;
return module->addTable(table);
}
// Or: anyfunc (elem 1 2 ...)
@ -3116,10 +3107,8 @@ ParseTable(WasmParseContext& c, WasmToken token, AstModule* module)
return false;
Limits r = { numElements, Some(numElements) };
if (!module->setTable(r)) {
c.ts.generateError(token, c.error);
if (!module->addTable(r))
return false;
}
auto* zero = new(c.lifo) AstConst(Val(uint32_t(0)));
if (!zero)
@ -4371,11 +4360,11 @@ EncodeImport(Encoder& e, AstImport& imp)
return false;
break;
case DefinitionKind::Table:
if (!EncodeTableLimits(e, imp.resizable()))
if (!EncodeTableLimits(e, imp.limits()))
return false;
break;
case DefinitionKind::Memory:
if (!EncodeLimits(e, imp.resizable()))
if (!EncodeLimits(e, imp.limits()))
return false;
break;
}
@ -4408,21 +4397,28 @@ EncodeImportSection(Encoder& e, AstModule& module)
static bool
EncodeMemorySection(Encoder& e, AstModule& module)
{
if (!module.hasMemory())
size_t numOwnMemories = 0;
for (const AstResizable& memory : module.memories()) {
if (!memory.imported)
numOwnMemories++;
}
if (!numOwnMemories)
return true;
size_t offset;
if (!e.startSection(SectionId::Memory, &offset))
return false;
uint32_t numMemories = 1;
if (!e.writeVarU32(numMemories))
if (!e.writeVarU32(numOwnMemories))
return false;
const Limits& memory = module.memory();
if (!EncodeLimits(e, memory))
return false;
for (const AstResizable& memory : module.memories()) {
if (memory.imported)
continue;
if (!EncodeLimits(e, memory.limits))
return false;
}
e.finishSection(offset);
return true;
@ -4505,20 +4501,28 @@ EncodeExportSection(Encoder& e, AstModule& module)
static bool
EncodeTableSection(Encoder& e, AstModule& module)
{
if (!module.hasTable())
size_t numOwnTables = 0;
for (const AstResizable& table : module.tables()) {
if (!table.imported)
numOwnTables++;
}
if (!numOwnTables)
return true;
size_t offset;
if (!e.startSection(SectionId::Table, &offset))
return false;
uint32_t numTables = 1;
if (!e.writeVarU32(numTables))
if (!e.writeVarU32(numOwnTables))
return false;
const Limits& table = module.table();
if (!EncodeTableLimits(e, table))
return false;
for (const AstResizable& table : module.tables()) {
if (table.imported)
continue;
if (!EncodeTableLimits(e, table.limits))
return false;
}
e.finishSection(offset);
return true;

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

@ -42,3 +42,24 @@ wasmFullPass(`(module
(export "run" $get)
)`, 13 + 42 + 37 + 42, { globals: {x: 42} });
// Memory.
wasmFullPass(`(module
(memory (export "memory") 1 2)
(data (i32.const 0) "\\00\\01\\02\\03\\04\\05")
(func (export "run") (result i32)
i32.const 1
i32.load offset=2
)
)`, 0x050403);
let memory = new WebAssembly.Memory({ initial: 1, maximum: 2 });
wasmFullPass(`(module
(memory (import "" "memory") 1 2)
(data (i32.const 0) "\\00\\01\\02\\03\\04\\05")
(func (export "run") (result i32)
i32.const 1
i32.load offset=2
)
(export "mem" memory)
)`, 0x050403, {"": {memory}});