Commit 0202a040 authored by Deepti Gandluri's avatar Deepti Gandluri Committed by Commit Bot

[wasm] Module bytes can set shared attribute on memory

- Validate that atomic ops can only be called when shared memory is declared
- Throw Compile/Link erros on mismatch between declared, imported memory
- Test harness helpers for setting shared memory, tests

BUG=v8:6532

R=binji@chromium.org, bradnelson@chromium.org

Change-Id: I43fe3d04bb7e3e0a2cecca0528578f98844d2608
Reviewed-on: https://chromium-review.googlesource.com/665379
Commit-Queue: Brad Nelson <bradnelson@chromium.org>
Reviewed-by: 's avatarBrad Nelson <bradnelson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48019}
parent 70372dfc
...@@ -1155,6 +1155,14 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1155,6 +1155,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return true; return true;
} }
bool CheckHasSharedMemory() {
if (!VALIDATE(this->module_->has_shared_memory)) {
this->error(this->pc_ - 1, "Atomic opcodes used without shared memory");
return false;
}
return true;
}
// Decodes the body of a function. // Decodes the body of a function.
void DecodeFunctionBody() { void DecodeFunctionBody() {
TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n", TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n",
...@@ -1655,6 +1663,7 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1655,6 +1663,7 @@ class WasmFullDecoder : public WasmDecoder<validate> {
} }
case kAtomicPrefix: { case kAtomicPrefix: {
CHECK_PROTOTYPE_OPCODE(threads); CHECK_PROTOTYPE_OPCODE(threads);
if (!CheckHasSharedMemory()) break;
len++; len++;
byte atomic_index = byte atomic_index =
this->template read_u8<validate>(this->pc_ + 1, "atomic index"); this->template read_u8<validate>(this->pc_ + 1, "atomic index");
......
...@@ -1467,6 +1467,14 @@ int InstanceBuilder::ProcessImports(Handle<FixedArray> code_table, ...@@ -1467,6 +1467,14 @@ int InstanceBuilder::ProcessImports(Handle<FixedArray> code_table,
return -1; return -1;
} }
} }
if (module_->has_shared_memory != buffer->is_shared()) {
thrower_->LinkError(
"mismatch in shared state of memory, declared = %d, imported = "
"%d",
module_->has_shared_memory, buffer->is_shared());
return -1;
}
break; break;
} }
case kExternalGlobal: { case kExternalGlobal: {
......
...@@ -474,7 +474,8 @@ class ModuleDecoder : public Decoder { ...@@ -474,7 +474,8 @@ class ModuleDecoder : public Decoder {
consume_resizable_limits( consume_resizable_limits(
"memory", "pages", FLAG_wasm_max_mem_pages, "memory", "pages", FLAG_wasm_max_mem_pages,
&module_->initial_pages, &module_->has_maximum_pages, &module_->initial_pages, &module_->has_maximum_pages,
kSpecMaxWasmMemoryPages, &module_->maximum_pages); kSpecMaxWasmMemoryPages, &module_->maximum_pages,
&module_->has_shared_memory);
break; break;
} }
case kExternalGlobal: { case kExternalGlobal: {
...@@ -542,7 +543,7 @@ class ModuleDecoder : public Decoder { ...@@ -542,7 +543,7 @@ class ModuleDecoder : public Decoder {
consume_resizable_limits( consume_resizable_limits(
"memory", "pages", FLAG_wasm_max_mem_pages, &module_->initial_pages, "memory", "pages", FLAG_wasm_max_mem_pages, &module_->initial_pages,
&module_->has_maximum_pages, kSpecMaxWasmMemoryPages, &module_->has_maximum_pages, kSpecMaxWasmMemoryPages,
&module_->maximum_pages); &module_->maximum_pages, &module_->has_shared_memory);
} }
} }
...@@ -1082,12 +1083,30 @@ class ModuleDecoder : public Decoder { ...@@ -1082,12 +1083,30 @@ class ModuleDecoder : public Decoder {
void consume_resizable_limits(const char* name, const char* units, void consume_resizable_limits(const char* name, const char* units,
uint32_t max_initial, uint32_t* initial, uint32_t max_initial, uint32_t* initial,
bool* has_max, uint32_t max_maximum, bool* has_max, uint32_t max_maximum,
uint32_t* maximum) { uint32_t* maximum,
bool* has_shared_memory = nullptr) {
uint8_t flags = consume_u8("resizable limits flags"); uint8_t flags = consume_u8("resizable limits flags");
const byte* pos = pc(); const byte* pos = pc();
if (flags & 0xfe) {
errorf(pos - 1, "invalid %s limits flags", name); if (FLAG_experimental_wasm_threads) {
bool is_memory = (strcmp(name, "memory") == 0);
if (flags & 0xfc || (!is_memory && (flags & 0xfe))) {
errorf(pos - 1, "invalid %s limits flags", name);
}
if (flags == 3) {
DCHECK(has_shared_memory != nullptr);
*has_shared_memory = true;
} else if (flags == 2) {
errorf(pos - 1,
"%s limits flags should have maximum defined if shared is true",
name);
}
} else {
if (flags & 0xfe) {
errorf(pos - 1, "invalid %s limits flags", name);
}
} }
*initial = consume_u32v("initial size"); *initial = consume_u32v("initial size");
*has_max = false; *has_max = false;
if (*initial > max_initial) { if (*initial > max_initial) {
......
...@@ -26,6 +26,13 @@ const uint8_t kWasmAnyFunctionTypeForm = 0x70; ...@@ -26,6 +26,13 @@ const uint8_t kWasmAnyFunctionTypeForm = 0x70;
const uint8_t kResizableMaximumFlag = 1; const uint8_t kResizableMaximumFlag = 1;
const uint8_t kNoMaximumFlag = 0; const uint8_t kNoMaximumFlag = 0;
enum MemoryFlags : uint8_t {
kNoMaximum = 0,
kMaximum = 1,
kSharedNoMaximum = 2,
kSharedAndMaximum = 3
};
enum SectionCode : int8_t { enum SectionCode : int8_t {
kUnknownSectionCode = 0, // code for unknown sections kUnknownSectionCode = 0, // code for unknown sections
kTypeSectionCode = 1, // Function signature declarations kTypeSectionCode = 1, // Function signature declarations
......
...@@ -226,7 +226,8 @@ WasmModuleBuilder::WasmModuleBuilder(Zone* zone) ...@@ -226,7 +226,8 @@ WasmModuleBuilder::WasmModuleBuilder(Zone* zone)
start_function_index_(-1), start_function_index_(-1),
min_memory_size_(16), min_memory_size_(16),
max_memory_size_(0), max_memory_size_(0),
has_max_memory_size_(false) {} has_max_memory_size_(false),
has_shared_memory_(false) {}
WasmFunctionBuilder* WasmModuleBuilder::AddFunction(FunctionSig* sig) { WasmFunctionBuilder* WasmModuleBuilder::AddFunction(FunctionSig* sig) {
functions_.push_back(new (zone_) WasmFunctionBuilder(this)); functions_.push_back(new (zone_) WasmFunctionBuilder(this));
...@@ -325,6 +326,8 @@ void WasmModuleBuilder::SetMaxMemorySize(uint32_t value) { ...@@ -325,6 +326,8 @@ void WasmModuleBuilder::SetMaxMemorySize(uint32_t value) {
max_memory_size_ = value; max_memory_size_ = value;
} }
void WasmModuleBuilder::SetHasSharedMemory() { has_shared_memory_ = true; }
void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const { void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
// == Emit magic ============================================================= // == Emit magic =============================================================
buffer.write_u32(kWasmMagic); buffer.write_u32(kWasmMagic);
...@@ -396,8 +399,13 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const { ...@@ -396,8 +399,13 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
{ {
size_t start = EmitSection(kMemorySectionCode, buffer); size_t start = EmitSection(kMemorySectionCode, buffer);
buffer.write_u8(1); // memory count buffer.write_u8(1); // memory count
buffer.write_u8(has_max_memory_size_ ? kResizableMaximumFlag if (has_shared_memory_) {
: kNoMaximumFlag); buffer.write_u8(has_max_memory_size_ ? MemoryFlags::kSharedAndMaximum
: MemoryFlags::kSharedNoMaximum);
} else {
buffer.write_u8(has_max_memory_size_ ? MemoryFlags::kMaximum
: MemoryFlags::kNoMaximum);
}
buffer.write_u32v(min_memory_size_); buffer.write_u32v(min_memory_size_);
if (has_max_memory_size_) { if (has_max_memory_size_) {
buffer.write_u32v(max_memory_size_); buffer.write_u32v(max_memory_size_);
......
...@@ -236,6 +236,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject { ...@@ -236,6 +236,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
void AddExport(Vector<const char> name, WasmFunctionBuilder* builder); void AddExport(Vector<const char> name, WasmFunctionBuilder* builder);
void SetMinMemorySize(uint32_t value); void SetMinMemorySize(uint32_t value);
void SetMaxMemorySize(uint32_t value); void SetMaxMemorySize(uint32_t value);
void SetHasSharedMemory();
// Writing methods. // Writing methods.
void WriteTo(ZoneBuffer& buffer) const; void WriteTo(ZoneBuffer& buffer) const;
...@@ -295,6 +296,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject { ...@@ -295,6 +296,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
uint32_t min_memory_size_; uint32_t min_memory_size_;
uint32_t max_memory_size_; uint32_t max_memory_size_;
bool has_max_memory_size_; bool has_max_memory_size_;
bool has_shared_memory_;
}; };
inline FunctionSig* WasmFunctionBuilder::signature() { inline FunctionSig* WasmFunctionBuilder::signature() {
......
...@@ -187,10 +187,11 @@ struct V8_EXPORT_PRIVATE WasmModule { ...@@ -187,10 +187,11 @@ struct V8_EXPORT_PRIVATE WasmModule {
std::unique_ptr<Zone> signature_zone; std::unique_ptr<Zone> signature_zone;
uint32_t initial_pages = 0; // initial size of the memory in 64k pages uint32_t initial_pages = 0; // initial size of the memory in 64k pages
uint32_t maximum_pages = 0; // maximum size of the memory in 64k pages uint32_t maximum_pages = 0; // maximum size of the memory in 64k pages
bool has_shared_memory = false; // true if memory is a SharedArrayBuffer
bool has_maximum_pages = false; // true if there is a maximum memory size bool has_maximum_pages = false; // true if there is a maximum memory size
bool has_memory = false; // true if the memory was defined or imported bool has_memory = false; // true if the memory was defined or imported
bool mem_export = false; // true if the memory is exported bool mem_export = false; // true if the memory is exported
int start_function_index = -1; // start function, >= 0 if any int start_function_index = -1; // start function, >= 0 if any
std::vector<WasmGlobal> globals; std::vector<WasmGlobal> globals;
uint32_t globals_size = 0; uint32_t globals_size = 0;
......
...@@ -60,6 +60,7 @@ void RunU32BinOp(WasmOpcode wasm_op, Uint32BinOp expected_op) { ...@@ -60,6 +60,7 @@ void RunU32BinOp(WasmOpcode wasm_op, Uint32BinOp expected_op) {
EXPERIMENTAL_FLAG_SCOPE(threads); EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled); WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled);
uint32_t* memory = r.builder().AddMemoryElems<uint32_t>(8); uint32_t* memory = r.builder().AddMemoryElems<uint32_t>(8);
r.builder().SetHasSharedMemory();
BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0))); BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0)));
...@@ -84,6 +85,7 @@ WASM_EXEC_TEST(I32Exchange) { RunU32BinOp(kExprI32AtomicExchange, Exchange); } ...@@ -84,6 +85,7 @@ WASM_EXEC_TEST(I32Exchange) { RunU32BinOp(kExprI32AtomicExchange, Exchange); }
void RunU16BinOp(WasmOpcode wasm_op, Uint16BinOp expected_op) { void RunU16BinOp(WasmOpcode wasm_op, Uint16BinOp expected_op) {
EXPERIMENTAL_FLAG_SCOPE(threads); EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled); WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled);
r.builder().SetHasSharedMemory();
uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(8); uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(8);
BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0))); BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0)));
...@@ -111,6 +113,7 @@ WASM_EXEC_TEST(I32Exchange16U) { ...@@ -111,6 +113,7 @@ WASM_EXEC_TEST(I32Exchange16U) {
void RunU8BinOp(WasmOpcode wasm_op, Uint8BinOp expected_op) { void RunU8BinOp(WasmOpcode wasm_op, Uint8BinOp expected_op) {
EXPERIMENTAL_FLAG_SCOPE(threads); EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled); WasmRunner<uint32_t, uint32_t> r(kExecuteCompiled);
r.builder().SetHasSharedMemory();
uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(8); uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(8);
BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0))); BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_GET_LOCAL(0)));
...@@ -138,6 +141,7 @@ WASM_EXEC_TEST(I32Exchange8U) { ...@@ -138,6 +141,7 @@ WASM_EXEC_TEST(I32Exchange8U) {
WASM_EXEC_TEST(I32CompareExchange) { WASM_EXEC_TEST(I32CompareExchange) {
EXPERIMENTAL_FLAG_SCOPE(threads); EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t, uint32_t, uint32_t> r(kExecuteCompiled); WasmRunner<uint32_t, uint32_t, uint32_t> r(kExecuteCompiled);
r.builder().SetHasSharedMemory();
uint32_t* memory = r.builder().AddMemoryElems<uint32_t>(8); uint32_t* memory = r.builder().AddMemoryElems<uint32_t>(8);
BUILD(r, BUILD(r,
WASM_ATOMICS_TERNARY_OP(kExprI32AtomicCompareExchange, WASM_I32V_1(0), WASM_ATOMICS_TERNARY_OP(kExprI32AtomicCompareExchange, WASM_I32V_1(0),
...@@ -157,6 +161,7 @@ WASM_EXEC_TEST(I32CompareExchange) { ...@@ -157,6 +161,7 @@ WASM_EXEC_TEST(I32CompareExchange) {
WASM_EXEC_TEST(I32CompareExchange16U) { WASM_EXEC_TEST(I32CompareExchange16U) {
EXPERIMENTAL_FLAG_SCOPE(threads); EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t, uint32_t, uint32_t> r(kExecuteCompiled); WasmRunner<uint32_t, uint32_t, uint32_t> r(kExecuteCompiled);
r.builder().SetHasSharedMemory();
uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(8); uint16_t* memory = r.builder().AddMemoryElems<uint16_t>(8);
BUILD(r, WASM_ATOMICS_TERNARY_OP(kExprI32AtomicCompareExchange16U, BUILD(r, WASM_ATOMICS_TERNARY_OP(kExprI32AtomicCompareExchange16U,
WASM_I32V_1(0), WASM_GET_LOCAL(0), WASM_I32V_1(0), WASM_GET_LOCAL(0),
...@@ -176,6 +181,7 @@ WASM_EXEC_TEST(I32CompareExchange16U) { ...@@ -176,6 +181,7 @@ WASM_EXEC_TEST(I32CompareExchange16U) {
WASM_EXEC_TEST(I32CompareExchange8U) { WASM_EXEC_TEST(I32CompareExchange8U) {
EXPERIMENTAL_FLAG_SCOPE(threads); EXPERIMENTAL_FLAG_SCOPE(threads);
WasmRunner<uint32_t, uint32_t, uint32_t> r(kExecuteCompiled); WasmRunner<uint32_t, uint32_t, uint32_t> r(kExecuteCompiled);
r.builder().SetHasSharedMemory();
uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(8); uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(8);
BUILD(r, BUILD(r,
WASM_ATOMICS_TERNARY_OP(kExprI32AtomicCompareExchange8U, WASM_I32V_1(0), WASM_ATOMICS_TERNARY_OP(kExprI32AtomicCompareExchange8U, WASM_I32V_1(0),
......
...@@ -157,6 +157,8 @@ class TestingModuleBuilder { ...@@ -157,6 +157,8 @@ class TestingModuleBuilder {
test_module_.maximum_pages = maximum_pages; test_module_.maximum_pages = maximum_pages;
} }
void SetHasSharedMemory() { test_module_.has_shared_memory = true; }
uint32_t AddFunction(FunctionSig* sig, Handle<Code> code, const char* name); uint32_t AddFunction(FunctionSig* sig, Handle<Code> code, const char* name);
uint32_t AddJsFunction(FunctionSig* sig, const char* source, uint32_t AddJsFunction(FunctionSig* sig, const char* source,
......
...@@ -23,7 +23,7 @@ let memory = new WebAssembly.Memory({initial: 1, maximum: maxSize, shared: true} ...@@ -23,7 +23,7 @@ let memory = new WebAssembly.Memory({initial: 1, maximum: maxSize, shared: true}
function GetAtomicBinOpFunction(wasmExpression) { function GetAtomicBinOpFunction(wasmExpression) {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "imported_mem"); builder.addImportedMemory("m", "imported_mem", 0, maxSize, "shared");
builder.addFunction("main", kSig_i_ii) builder.addFunction("main", kSig_i_ii)
.addBody([ .addBody([
kExprGetLocal, 0, kExprGetLocal, 0,
...@@ -41,7 +41,7 @@ function GetAtomicBinOpFunction(wasmExpression) { ...@@ -41,7 +41,7 @@ function GetAtomicBinOpFunction(wasmExpression) {
function GetAtomicCmpExchangeFunction(wasmExpression) { function GetAtomicCmpExchangeFunction(wasmExpression) {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "imported_mem"); builder.addImportedMemory("m", "imported_mem", 0, maxSize, "shared");
builder.addFunction("main", kSig_i_iii) builder.addFunction("main", kSig_i_iii)
.addBody([ .addBody([
kExprGetLocal, 0, kExprGetLocal, 0,
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
// Flags: --experimental-wasm-threads // Flags: --experimental-wasm-threads
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
function assertMemoryIsValid(memory) { function assertMemoryIsValid(memory) {
assertSame(WebAssembly.Memory.prototype, memory.__proto__); assertSame(WebAssembly.Memory.prototype, memory.__proto__);
assertSame(WebAssembly.Memory, memory.constructor); assertSame(WebAssembly.Memory, memory.constructor);
...@@ -50,3 +53,51 @@ function assertMemoryIsValid(memory) { ...@@ -50,3 +53,51 @@ function assertMemoryIsValid(memory) {
assertThrows(() => new WebAssembly.Memory({initial: 0, shared: true}), assertThrows(() => new WebAssembly.Memory({initial: 0, shared: true}),
TypeError); TypeError);
})(); })();
(function TestCompileWithUndefinedShared() {
print("TestCompileWithUndefinedShared");
let memory = new WebAssembly.Memory({
initial: 0, maximum: 10, shared: true});
let builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "imported_mem", 0, undefined, "shared");
assertThrows(() => new WebAssembly.Module(builder.toBuffer()),
WebAssembly.CompileError);
})();
(function TestCompileAtomicOpUndefinedShared() {
print("TestCompileAtomicOpUndefinedShared");
let memory = new WebAssembly.Memory({
initial: 0, maximum: 10, shared: true});
let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_ii)
.addBody([
kExprGetLocal, 0,
kExprGetLocal, 1,
kAtomicPrefix,
kExprI32AtomicAdd]);
builder.addImportedMemory("m", "imported_mem");
assertThrows(() => new WebAssembly.Module(builder.toBuffer()),
WebAssembly.CompileError);
})();
(function TestInstantiateWithUndefinedShared() {
print("TestInstantiateWithUndefinedShared");
let memory = new WebAssembly.Memory({
initial: 0, maximum: 10, shared: true});
let builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "imported_mem");
let module = new WebAssembly.Module(builder.toBuffer());
assertThrows(() => new WebAssembly.Instance(module,
{m: {imported_mem: memory}}), WebAssembly.LinkError);
})();
(function TestInstantiateWithImportNotSharedDefined() {
print("TestInstantiateWithImportNotSharedDefined");
let memory = new WebAssembly.Memory({
initial: 0, maximum: 10, shared: false});
let builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "imported_mem", 0, 10, "shared");
let module = new WebAssembly.Module(builder.toBuffer());
assertThrows(() => new WebAssembly.Instance(module,
{m: {imported_mem: memory}}), WebAssembly.LinkError);
})();
...@@ -171,8 +171,8 @@ class WasmModuleBuilder { ...@@ -171,8 +171,8 @@ class WasmModuleBuilder {
return this; return this;
} }
addMemory(min, max, exp) { addMemory(min, max, exp, shared) {
this.memory = {min: min, max: max, exp: exp}; this.memory = {min: min, max: max, exp: exp, shared: shared};
return this; return this;
} }
...@@ -240,9 +240,9 @@ class WasmModuleBuilder { ...@@ -240,9 +240,9 @@ class WasmModuleBuilder {
return this.num_imported_globals++; return this.num_imported_globals++;
} }
addImportedMemory(module = "", name, initial = 0, maximum) { addImportedMemory(module = "", name, initial = 0, maximum, shared) {
let o = {module: module, name: name, kind: kExternalMemory, let o = {module: module, name: name, kind: kExternalMemory,
initial: initial, maximum: maximum}; initial: initial, maximum: maximum, shared: shared};
this.imports.push(o); this.imports.push(o);
return this; return this;
} }
...@@ -348,7 +348,12 @@ class WasmModuleBuilder { ...@@ -348,7 +348,12 @@ class WasmModuleBuilder {
section.emit_u8(imp.mutable); section.emit_u8(imp.mutable);
} else if (imp.kind == kExternalMemory) { } else if (imp.kind == kExternalMemory) {
var has_max = (typeof imp.maximum) != "undefined"; var has_max = (typeof imp.maximum) != "undefined";
section.emit_u8(has_max ? 1 : 0); // flags var is_shared = (typeof imp.shared) != "undefined";
if (is_shared) {
section.emit_u8(has_max ? 3 : 2); // flags
} else {
section.emit_u8(has_max ? 1 : 0); // flags
}
section.emit_u32v(imp.initial); // initial section.emit_u32v(imp.initial); // initial
if (has_max) section.emit_u32v(imp.maximum); // maximum if (has_max) section.emit_u32v(imp.maximum); // maximum
} else if (imp.kind == kExternalTable) { } else if (imp.kind == kExternalTable) {
...@@ -395,9 +400,16 @@ class WasmModuleBuilder { ...@@ -395,9 +400,16 @@ class WasmModuleBuilder {
binary.emit_section(kMemorySectionCode, section => { binary.emit_section(kMemorySectionCode, section => {
section.emit_u8(1); // one memory entry section.emit_u8(1); // one memory entry
const has_max = wasm.memory.max !== undefined; const has_max = wasm.memory.max !== undefined;
section.emit_u32v(has_max ? kResizableMaximumFlag : 0); const is_shared = wasm.memory.shared !== undefined;
// Emit flags (bit 0: reszeable max, bit 1: shared memory)
if (is_shared) {
section.emit_u8(has_max ? 3 : 2);
} else {
section.emit_u8(has_max ? 1 : 0);
}
section.emit_u32v(wasm.memory.min); section.emit_u32v(wasm.memory.min);
if (has_max) section.emit_u32v(wasm.memory.max); if (has_max) section.emit_u32v(wasm.memory.max);
if (wasm.memory.shared) section.emit_u8(1);
}); });
} }
......
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