Skip to content

Commit 21e08ee

Browse files
authored
Add shared memories (#1069)
Begin to implement wasm threading proposal in https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md This PR just has shared memory attribute with wast and binary support.
1 parent bf37733 commit 21e08ee

21 files changed

Lines changed: 112 additions & 43 deletions

auto_update_tests.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from scripts.test.support import run_command, split_wast
66
from scripts.test.shared import (
7-
ASM2WASM, S2WASM, WASM_SHELL, WASM_OPT, WASM_AS, WASM_DIS, WASM_CTOR_EVAL)
7+
ASM2WASM, MOZJS, S2WASM, WASM_SHELL, WASM_OPT, WASM_AS, WASM_DIS, WASM_CTOR_EVAL)
88

99
print '[ processing and updating testcases... ]\n'
1010

@@ -199,6 +199,7 @@
199199
print '..', t
200200
t = os.path.join('test', t)
201201
cmd = WASM_DIS + [t]
202+
if os.path.isfile(t + '.map'): cmd += ['--source-map', t + '.map']
202203
actual = run_command(cmd)
203204

204205
open(t + '.fromBinary', 'w').write(actual)
@@ -223,18 +224,19 @@
223224
with open(out, 'w') as o: o.write(actual)
224225
with open(out + '.stdout', 'w') as o: o.write(stdout)
225226

226-
print '\n[ checking binaryen.js testcases... ]\n'
227-
228-
for s in sorted(os.listdir(os.path.join('test', 'binaryen.js'))):
229-
if not s.endswith('.js'): continue
230-
print s
231-
f = open('a.js', 'w')
232-
f.write(open(os.path.join('bin', 'binaryen.js')).read())
233-
f.write(open(os.path.join('test', 'binaryen.js', s)).read())
234-
f.close()
235-
cmd = ['mozjs', 'a.js']
236-
out = run_command(cmd, stderr=subprocess.STDOUT)
237-
open(os.path.join('test', 'binaryen.js', s + '.txt'), 'w').write(out)
227+
if MOZJS:
228+
print '\n[ checking binaryen.js testcases... ]\n'
229+
230+
for s in sorted(os.listdir(os.path.join('test', 'binaryen.js'))):
231+
if not s.endswith('.js'): continue
232+
print s
233+
f = open('a.js', 'w')
234+
f.write(open(os.path.join('bin', 'binaryen.js')).read())
235+
f.write(open(os.path.join('test', 'binaryen.js', s)).read())
236+
f.close()
237+
cmd = [MOZJS, 'a.js']
238+
out = run_command(cmd, stderr=subprocess.STDOUT)
239+
with open(os.path.join('test', 'binaryen.js', s + '.txt'), 'w') as o: o.write(out)
238240

239241
print '\n[ checking wasm-ctor-eval... ]\n'
240242

scripts/test/s2wasm.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def test_s2wasm():
2929
os.path.join(options.binaryen_test, 'dot_s', 'basics.s'),
3030
'--import-memory']
3131
output = run_command(cmd)
32-
fail_if_not_contained(output, '(import "env" "memory" (memory $0 1))')
32+
fail_if_not_contained(
33+
output, '(import "env" "memory" (memory $0 1))')
3334

3435
for dot_s_dir in ['dot_s', 'llvm_autogenerated']:
3536
dot_s_path = os.path.join(options.binaryen_test, dot_s_dir)

src/passes/Print.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
670670
printName(curr->name) << ' ';
671671
o << curr->initial;
672672
if (curr->max && curr->max != Memory::kMaxSize) o << ' ' << curr->max;
673+
if (curr->shared) o << " shared";
673674
o << ")";
674675
}
675676
void visitMemory(Memory* curr) {

src/wasm-binary.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,11 @@ enum MemoryAccess {
515515
NaturalAlignment = 0
516516
};
517517

518+
enum MemoryFlags {
519+
HasMaximum = 1 << 0,
520+
IsShared = 1 << 1
521+
};
522+
518523
} // namespace BinaryConsts
519524

520525

@@ -560,7 +565,7 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
560565
void write();
561566
void writeHeader();
562567
int32_t writeU32LEBPlaceholder();
563-
void writeResizableLimits(Address initial, Address maximum, bool hasMaximum);
568+
void writeResizableLimits(Address initial, Address maximum, bool hasMaximum, bool shared);
564569
int32_t startSection(BinaryConsts::Section code);
565570
void finishSection(int32_t start);
566571
int32_t startSubsection(BinaryConsts::UserSections::Subsection code);
@@ -712,7 +717,7 @@ class WasmBinaryBuilder {
712717

713718
// gets a name in the combined function import+defined function space
714719
Name getFunctionIndexName(Index i);
715-
void getResizableLimits(Address& initial, Address& max, Address defaultIfNoMax);
720+
void getResizableLimits(Address& initial, Address& max, bool& shared, Address defaultIfNoMax);
716721
void readImports();
717722

718723
std::vector<FunctionType*> functionTypes; // types of defined functions

src/wasm-s-parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ class SExpressionWasmBuilder {
196196
Expression* makeReturn(Element& s);
197197

198198
WasmType parseOptionalResultType(Element& s, Index& i);
199+
Index parseMemoryLimits(Element& s, Index i);
199200

200201
void stringToBinary(const char* input, size_t size, std::vector<char>& data);
201202
void parseMemory(Element& s, bool preParseImport = false);

src/wasm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,9 @@ class Memory {
632632
// See comment in Table.
633633
bool exists;
634634
bool imported;
635+
bool shared;
635636

636-
Memory() : initial(0), max(kMaxSize), exists(false), imported(false) {
637+
Memory() : initial(0), max(kMaxSize), exists(false), imported(false), shared(false) {
637638
name = Name::fromInt(0);
638639
}
639640
};

src/wasm/wasm-binary.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ int32_t WasmBinaryWriter::writeU32LEBPlaceholder() {
7171
return ret;
7272
}
7373

74-
void WasmBinaryWriter::writeResizableLimits(Address initial, Address maximum, bool hasMaximum) {
75-
uint32_t flags = hasMaximum ? 1 : 0;
74+
void WasmBinaryWriter::writeResizableLimits(Address initial, Address maximum,
75+
bool hasMaximum, bool shared) {
76+
uint32_t flags =
77+
(hasMaximum ? (uint32_t) BinaryConsts::HasMaximum : 0U) |
78+
(shared ? (uint32_t) BinaryConsts::IsShared : 0U);
7679
o << U32LEB(flags);
7780
o << U32LEB(initial);
7881
if (hasMaximum) {
@@ -113,7 +116,8 @@ void WasmBinaryWriter::writeMemory() {
113116
if (debug) std::cerr << "== writeMemory" << std::endl;
114117
auto start = startSection(BinaryConsts::Section::Memory);
115118
o << U32LEB(1); // Define 1 memory
116-
writeResizableLimits(wasm->memory.initial, wasm->memory.max, wasm->memory.max != Memory::kMaxSize);
119+
writeResizableLimits(wasm->memory.initial, wasm->memory.max,
120+
wasm->memory.max != Memory::kMaxSize, wasm->memory.shared);
117121
finishSection(start);
118122
}
119123

@@ -161,11 +165,12 @@ void WasmBinaryWriter::writeImports() {
161165
case ExternalKind::Function: o << U32LEB(getFunctionTypeIndex(import->functionType)); break;
162166
case ExternalKind::Table: {
163167
o << S32LEB(BinaryConsts::EncodedType::AnyFunc);
164-
writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize);
168+
writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize, /*shared=*/false);
165169
break;
166170
}
167171
case ExternalKind::Memory: {
168-
writeResizableLimits(wasm->memory.initial, wasm->memory.max, wasm->memory.max != Memory::kMaxSize);
172+
writeResizableLimits(wasm->memory.initial, wasm->memory.max,
173+
wasm->memory.max != Memory::kMaxSize, wasm->memory.shared);
169174
break;
170175
}
171176
case ExternalKind::Global:
@@ -368,7 +373,7 @@ void WasmBinaryWriter::writeFunctionTableDeclaration() {
368373
auto start = startSection(BinaryConsts::Section::Table);
369374
o << U32LEB(1); // Declare 1 table.
370375
o << S32LEB(BinaryConsts::EncodedType::AnyFunc);
371-
writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize);
376+
writeResizableLimits(wasm->table.initial, wasm->table.max, wasm->table.max != Table::kMaxSize, /*shared=*/false);
372377
finishSection(start);
373378
}
374379

@@ -1237,7 +1242,7 @@ void WasmBinaryBuilder::readMemory() {
12371242
throw ParseException("Memory cannot be both imported and defined");
12381243
}
12391244
wasm.memory.exists = true;
1240-
getResizableLimits(wasm.memory.initial, wasm.memory.max, Memory::kMaxSize);
1245+
getResizableLimits(wasm.memory.initial, wasm.memory.max, wasm.memory.shared, Memory::kMaxSize);
12411246
}
12421247

12431248
void WasmBinaryBuilder::readSignatures() {
@@ -1284,10 +1289,13 @@ Name WasmBinaryBuilder::getFunctionIndexName(Index i) {
12841289
}
12851290
}
12861291

1287-
void WasmBinaryBuilder::getResizableLimits(Address& initial, Address& max, Address defaultIfNoMax) {
1292+
void WasmBinaryBuilder::getResizableLimits(Address& initial, Address& max, bool &shared, Address defaultIfNoMax) {
12881293
auto flags = getU32LEB();
12891294
initial = getU32LEB();
1290-
bool hasMax = flags & 0x1;
1295+
bool hasMax = flags & BinaryConsts::HasMaximum;
1296+
bool isShared = flags & BinaryConsts::IsShared;
1297+
if (isShared && !hasMax) throw ParseException("shared memory must have max size");
1298+
shared = isShared;
12911299
if (hasMax) max = getU32LEB();
12921300
else max = defaultIfNoMax;
12931301
}
@@ -1320,13 +1328,15 @@ void WasmBinaryBuilder::readImports() {
13201328
if (elementType != BinaryConsts::EncodedType::AnyFunc) throw ParseException("Imported table type is not AnyFunc");
13211329
wasm.table.exists = true;
13221330
wasm.table.imported = true;
1323-
getResizableLimits(wasm.table.initial, wasm.table.max, Table::kMaxSize);
1331+
bool is_shared;
1332+
getResizableLimits(wasm.table.initial, wasm.table.max, is_shared, Table::kMaxSize);
1333+
if (is_shared) throw ParseException("Tables may not be shared");
13241334
break;
13251335
}
13261336
case ExternalKind::Memory: {
13271337
wasm.memory.exists = true;
13281338
wasm.memory.imported = true;
1329-
getResizableLimits(wasm.memory.initial, wasm.memory.max, Memory::kMaxSize);
1339+
getResizableLimits(wasm.memory.initial, wasm.memory.max, wasm.memory.shared, Memory::kMaxSize);
13301340
break;
13311341
}
13321342
case ExternalKind::Global: {
@@ -1759,7 +1769,9 @@ void WasmBinaryBuilder::readFunctionTableDeclaration() {
17591769
wasm.table.exists = true;
17601770
auto elemType = getS32LEB();
17611771
if (elemType != BinaryConsts::EncodedType::AnyFunc) throw ParseException("ElementType must be AnyFunc in MVP");
1762-
getResizableLimits(wasm.table.initial, wasm.table.max, Table::kMaxSize);
1772+
bool is_shared;
1773+
getResizableLimits(wasm.table.initial, wasm.table.max, is_shared, Table::kMaxSize);
1774+
if (is_shared) throw ParseException("Tables may not be shared");
17631775
}
17641776

17651777
void WasmBinaryBuilder::readTableElements() {

src/wasm/wasm-s-parser.cpp

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,10 +1440,28 @@ void SExpressionWasmBuilder::stringToBinary(const char* input, size_t size, std:
14401440
data.resize(actual);
14411441
}
14421442

1443+
Index SExpressionWasmBuilder::parseMemoryLimits(Element& s, Index i) {
1444+
wasm.memory.initial = getCheckedAddress(s[i++], "excessive memory init");
1445+
if (i == s.size()) return i;
1446+
while (i < s.size() && s[i]->isStr()) {
1447+
auto* curr = s[i]->c_str();
1448+
i++;
1449+
if (strstr(curr, "shared")) {
1450+
wasm.memory.shared = strncmp(curr, "notshared", 9) != 0;
1451+
break;
1452+
}
1453+
uint64_t max = atoll(curr);
1454+
if (max > Memory::kMaxSize) throw ParseException("total memory must be <= 4GB");
1455+
wasm.memory.max = max;
1456+
}
1457+
return i;
1458+
}
1459+
14431460
void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
14441461
if (wasm.memory.exists) throw ParseException("too many memories");
14451462
wasm.memory.exists = true;
14461463
wasm.memory.imported = preParseImport;
1464+
wasm.memory.shared = false;
14471465
Index i = 1;
14481466
if (s[i]->dollared()) {
14491467
wasm.memory.name = s[i++]->str();
@@ -1478,14 +1496,9 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
14781496
return;
14791497
}
14801498
}
1481-
wasm.memory.initial = getCheckedAddress(s[i++], "excessive memory init");
1482-
if (i == s.size()) return;
1483-
if (s[i]->isStr()) {
1484-
uint64_t max = atoll(s[i]->c_str());
1485-
if (max > Memory::kMaxSize) throw ParseException("total memory must be <= 4GB");
1486-
wasm.memory.max = max;
1487-
i++;
1488-
}
1499+
i = parseMemoryLimits(s, i);
1500+
1501+
// Parse memory initializers.
14891502
while (i < s.size()) {
14901503
Element& curr = *s[i];
14911504
size_t j = 1;
@@ -1683,12 +1696,7 @@ void SExpressionWasmBuilder::parseImport(Element& s) {
16831696
}
16841697
// ends with the table element type
16851698
} else if (im->kind == ExternalKind::Memory) {
1686-
if (j < inner.size()) {
1687-
wasm.memory.initial = getCheckedAddress(inner[j++], "excessive memory init size");
1688-
}
1689-
if (j < inner.size()) {
1690-
wasm.memory.max = getCheckedAddress(inner[j++], "excessive memory max size");
1691-
}
1699+
j = parseMemoryLimits(inner, j);
16921700
}
16931701
if (wasm.getImportOrNull(im->name)) throw ParseException("duplicate import", s.line, s.col);
16941702
wasm.addImport(im.release());

test/memory-shared.wast

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
(module
2+
(memory $0 23 256 shared)
3+
)
4+

test/memory-shared.wast.from-wast

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(module
2+
(memory $0 23 256 shared)
3+
)

0 commit comments

Comments
 (0)