Permalink
Browse files

support expressions in segment offsets

  • Loading branch information...
kripken committed Aug 12, 2016
1 parent 79029eb commit 7e3917884152eda021cff9107b5f789aee92fb1b
Showing with 236 additions and 278 deletions.
  1. +1 −1 check.py
  2. +4 −4 src/binaryen-c.cpp
  3. +1 −1 src/binaryen-c.h
  4. +6 −5 src/passes/Print.cpp
  5. +1 −0 src/shared-constants.h
  6. +3 −2 src/shell-interface.h
  7. +13 −7 src/wasm-binary.h
  8. +3 −3 src/wasm-interpreter.h
  9. +1 −1 src/wasm-js.cpp
  10. +1 −1 src/wasm-linker.cpp
  11. +2 −2 src/wasm-linker.h
  12. +27 −5 src/wasm-s-parser.h
  13. +0 −6 src/wasm-validator.h
  14. +1 −0 src/wasm.cpp
  15. +3 −3 src/wasm.h
  16. +2 −3 test/dot_s/alias.wast
  17. +2 −3 test/dot_s/asm_const.wast
  18. +4 −5 test/dot_s/basics.wast
  19. +8 −9 test/dot_s/bcp-1.wast
  20. +3 −4 test/dot_s/data-offset-folding.wast
  21. +4 −5 test/dot_s/function-data-sections.wast
  22. +2 −3 test/dot_s/indidx.wast
  23. +2 −3 test/dot_s/lcomm-in-text-segment.wast
  24. +2 −3 test/dot_s/macClangMetaData.wast
  25. +2 −3 test/dot_s/memops.wast
  26. +2 −3 test/dot_s/permute.wast
  27. +3 −4 test/dot_s/relocation.wast
  28. +2 −3 test/dot_s/symbolic-offset.wast
  29. +1 −1 test/example/c-api-kitchen-sink.c
  30. +8 −9 test/example/c-api-kitchen-sink.txt
  31. +2 −3 test/example/c-api-kitchen-sink.txt.txt
  32. +2 −3 test/kitchen_sink.wast
  33. +2 −3 test/kitchen_sink.wast.fromBinary
  34. +2 −3 test/llvm_autogenerated/byval.wast
  35. +2 −3 test/llvm_autogenerated/call.wast
  36. +2 −3 test/llvm_autogenerated/cfg-stackify.wast
  37. +2 −3 test/llvm_autogenerated/comparisons_f32.wast
  38. +2 −3 test/llvm_autogenerated/comparisons_f64.wast
  39. +2 −3 test/llvm_autogenerated/comparisons_i32.wast
  40. +2 −3 test/llvm_autogenerated/comparisons_i64.wast
  41. +2 −3 test/llvm_autogenerated/conv.wast
  42. +2 −3 test/llvm_autogenerated/copysign-casts.wast
  43. +2 −3 test/llvm_autogenerated/cpus.wast
  44. +2 −3 test/llvm_autogenerated/dead-vreg.wast
  45. +2 −3 test/llvm_autogenerated/divrem-constant.wast
  46. +2 −3 test/llvm_autogenerated/f32.wast
  47. +2 −3 test/llvm_autogenerated/f64.wast
  48. +2 −3 test/llvm_autogenerated/fast-isel.wast
  49. +2 −3 test/llvm_autogenerated/frem.wast
  50. +2 −3 test/llvm_autogenerated/func.wast
  51. +14 −15 test/llvm_autogenerated/global.wast
  52. +2 −3 test/llvm_autogenerated/globl.wast
  53. +2 −3 test/llvm_autogenerated/i128.wast
  54. +2 −3 test/llvm_autogenerated/i32-load-store-alignment.wast
  55. +2 −3 test/llvm_autogenerated/i32.wast
  56. +2 −3 test/llvm_autogenerated/i64-load-store-alignment.wast
  57. +2 −3 test/llvm_autogenerated/i64.wast
  58. +2 −3 test/llvm_autogenerated/ident.wast
  59. +2 −3 test/llvm_autogenerated/immediates.wast
  60. +2 −3 test/llvm_autogenerated/irreducible-cfg.wast
  61. +2 −3 test/llvm_autogenerated/legalize.wast
  62. +2 −3 test/llvm_autogenerated/load-ext.wast
  63. +2 −3 test/llvm_autogenerated/load-store-i1.wast
  64. +2 −3 test/llvm_autogenerated/load.wast
  65. +2 −3 test/llvm_autogenerated/mem-intrinsics.wast
  66. +2 −3 test/llvm_autogenerated/memory-addr32.wast
  67. +2 −3 test/llvm_autogenerated/non-executable-stack.wast
  68. +3 −4 test/llvm_autogenerated/offset.wast
  69. +2 −3 test/llvm_autogenerated/phi.wast
  70. +3 −4 test/llvm_autogenerated/reg-stackify.wast
  71. +2 −3 test/llvm_autogenerated/return-int32.wast
  72. +2 −3 test/llvm_autogenerated/return-void.wast
  73. +2 −3 test/llvm_autogenerated/select.wast
  74. +2 −3 test/llvm_autogenerated/signext-zeroext.wast
  75. +2 −3 test/llvm_autogenerated/store-results.wast
  76. +2 −3 test/llvm_autogenerated/store-trunc.wast
  77. +2 −3 test/llvm_autogenerated/store.wast
  78. +2 −3 test/llvm_autogenerated/switch.wast
  79. +2 −3 test/llvm_autogenerated/unreachable.wast
  80. +2 −3 test/llvm_autogenerated/unused-argument.wast
  81. +2 −3 test/llvm_autogenerated/userstack.wast
  82. +2 −3 test/llvm_autogenerated/varargs.wast
  83. +2 −3 test/unit.wast
  84. +2 −3 test/unit.wast.fromBinary
View
@@ -362,7 +362,7 @@ def minify_check(wast, verify_final_result=True):
print '\n[ checking wasm-shell spec testcases... ]\n'
if len(requested) == 0:
BLACKLIST = []
BLACKLIST = ['memory.wast'] # FIXME we support old and new memory formats, for now, until 0xc, and so can't pass this old-style test
spec_tests = [os.path.join('spec', t) for t in sorted(os.listdir(os.path.join('test', 'spec'))) if t not in BLACKLIST]
else:
spec_tests = requested[:]
View
@@ -736,7 +736,7 @@ void BinaryenSetFunctionTable(BinaryenModuleRef module, BinaryenFunctionRef* fun
// Memory. One per module
void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char* exportName, const char **segments, BinaryenIndex* segmentOffsets, BinaryenIndex* segmentSizes, BinaryenIndex numSegments) {
void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char* exportName, const char **segments, BinaryenExpressionRef* segmentOffsets, BinaryenIndex* segmentSizes, BinaryenIndex numSegments) {
if (tracing) {
std::cout << " {\n";
for (BinaryenIndex i = 0; i < numSegments; i++) {
@@ -754,10 +754,10 @@ void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, Binaryen
}
if (numSegments == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
std::cout << " };\n";
std::cout << " BinaryenIndex segmentOffsets[] = { ";
std::cout << " BinaryenExpressionRef segmentOffsets[] = { ";
for (BinaryenIndex i = 0; i < numSegments; i++) {
if (i > 0) std::cout << ", ";
std::cout << segmentOffsets[i];
std::cout << "expressions[" << expressions[segmentOffsets[i]] << "]";
}
if (numSegments == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
std::cout << " };\n";
@@ -779,7 +779,7 @@ void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, Binaryen
wasm->memory.max = maximum;
if (exportName) wasm->memory.exportName = exportName;
for (BinaryenIndex i = 0; i < numSegments; i++) {
wasm->memory.segments.emplace_back(segmentOffsets[i], segments[i], segmentSizes[i]);
wasm->memory.segments.emplace_back((Expression*)segmentOffsets[i], segments[i], segmentSizes[i]);
}
}
View
@@ -346,7 +346,7 @@ void BinaryenSetFunctionTable(BinaryenModuleRef module, BinaryenFunctionRef* fun
// Each segment has data in segments, a start offset in segmentOffsets, and a size in segmentSizes.
// exportName can be NULL
void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char* exportName, const char **segments, BinaryenIndex* segmentOffsets, BinaryenIndex* segmentSizes, BinaryenIndex numSegments);
void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char* exportName, const char **segments, BinaryenExpressionRef* segmentOffsets, BinaryenIndex* segmentSizes, BinaryenIndex numSegments);
// Start function. One per module
View
@@ -589,9 +589,12 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
doIndent(o, indent);
printOpening(o, "memory") << ' ' << curr->memory.initial;
if (curr->memory.max && curr->memory.max != Memory::kMaxSize) o << ' ' << curr->memory.max;
o << ")\n";
for (auto segment : curr->memory.segments) {
o << maybeNewLine;
o << (minify ? "" : " ") << "(segment " << segment.offset << " \"";
doIndent(o, indent);
printOpening(o, "data ", true);
visit(segment.offset);
o << " \"";
for (size_t i = 0; i < segment.data.size(); i++) {
unsigned char c = segment.data[i];
switch (c) {
@@ -612,10 +615,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
}
}
o << "\")";
o << "\")\n";
}
o << ((curr->memory.segments.size() > 0 && !minify) ? "\n " : "") << ')';
o << maybeNewLine;
if (curr->memory.exportName.is()) {
doIndent(o, indent);
printOpening(o, "export ");
View
@@ -24,6 +24,7 @@ extern Name GROW_WASM_MEMORY,
PARAM,
RESULT,
MEMORY,
DATA,
SEGMENT,
EXPORT,
IMPORT,
View
@@ -92,9 +92,10 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
memory.resize(wasm.memory.initial * wasm::Memory::kPageSize);
// apply memory segments
for (auto& segment : wasm.memory.segments) {
assert(segment.offset + segment.data.size() <= wasm.memory.initial * wasm::Memory::kPageSize);
Address offset = ConstantExpressionRunner().visit(segment.offset).value.geti32();
assert(offset + segment.data.size() <= wasm.memory.initial * wasm::Memory::kPageSize);
for (size_t i = 0; i != segment.data.size(); ++i) {
memory.set(segment.offset + i, segment.data[i]);
memory.set(offset + i, segment.data[i]);
}
}
}
View
@@ -706,7 +706,8 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
o << U32LEB(num);
for (auto& segment : wasm->memory.segments) {
if (segment.data.size() == 0) continue;
o << U32LEB(segment.offset);
writeExpression(segment.offset);
o << int8_t(BinaryConsts::End);
writeInlineBuffer(&segment.data[0], segment.data.size());
}
finishSection(start);
@@ -1572,6 +1573,15 @@ class WasmBinaryBuilder {
}
}
Expression* readExpression() {
assert(depth == 0);
processExpressions();
assert(expressionStack.size() == 1);
auto* ret = popExpression();
assert(depth == 0);
return ret;
}
void readGlobals() {
if (debug) std::cerr << "== readGlobals" << std::endl;
size_t num = getU32LEB();
@@ -1580,11 +1590,7 @@ class WasmBinaryBuilder {
if (debug) std::cerr << "read one" << std::endl;
auto curr = new Global;
curr->type = getWasmType();
assert(depth == 0);
processExpressions();
assert(expressionStack.size() == 1);
curr->init = popExpression();
assert(depth == 0);
curr->init = readExpression();
wasm.addGlobal(curr);
}
}
@@ -1649,7 +1655,7 @@ class WasmBinaryBuilder {
auto num = getU32LEB();
for (size_t i = 0; i < num; i++) {
Memory::Segment curr;
auto offset = getU32LEB();
auto offset = readExpression();
auto size = getU32LEB();
std::vector<char> buffer;
buffer.resize(size);
View
@@ -497,8 +497,8 @@ class ExpressionRunner : public Visitor<SubType, Flow> {
}
};
// Execute an expression in global init
class GlobalInitRunner : public ExpressionRunner<GlobalInitRunner> {
// Execute an constant expression in a global init or memory offset
class ConstantExpressionRunner : public ExpressionRunner<ConstantExpressionRunner> {
public:
Flow visitLoop(Loop* curr) { WASM_UNREACHABLE(); }
Flow visitCall(Call* curr) { WASM_UNREACHABLE(); }
@@ -547,7 +547,7 @@ class ModuleInstance {
ModuleInstance(Module& wasm, ExternalInterface* externalInterface) : wasm(wasm), externalInterface(externalInterface) {
memorySize = wasm.memory.initial;
for (Index i = 0; i < wasm.globals.size(); i++) {
globals.push_back(GlobalInitRunner().visit(wasm.globals[i]->init).value);
globals.push_back(ConstantExpressionRunner().visit(wasm.globals[i]->init).value);
}
externalInterface->init(wasm);
if (wasm.start.is()) {
View
@@ -193,7 +193,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() {
var source = Module['HEAP8'].subarray($1, $1 + $2);
var target = new Int8Array(Module['outside']['newBuffer']);
target.set(source, $0);
}, (uint32_t)segment.offset, &segment.data[0], segment.data.size());
}, ConstantExpressionRunner().visit(segment.offset).value.geti32(), &segment.data[0], segment.data.size());
}
}
View
@@ -83,7 +83,7 @@ void Linker::layout() {
// Update the segments with their addresses now that they have been allocated.
for (const auto& seg : out.segments) {
Address address = staticAddresses[seg.first];
out.wasm.memory.segments[seg.second].offset = address;
out.wasm.memory.segments[seg.second].offset = out.wasm.allocator.alloc<Const>()->set(Literal(uint32_t(address)));
segmentsByAddress[address] = seg.second;
}
View
@@ -114,12 +114,12 @@ class LinkerObject {
// Add an initializer segment for the named static variable.
void addSegment(Name name, const char* data, Address size) {
segments[name] = wasm.memory.segments.size();
wasm.memory.segments.emplace_back(0, data, size);
wasm.memory.segments.emplace_back(wasm.allocator.alloc<Const>()->set(Literal(uint32_t(0))), data, size);
}
void addSegment(Name name, std::vector<char>& data) {
segments[name] = wasm.memory.segments.size();
wasm.memory.segments.emplace_back(0, data);
wasm.memory.segments.emplace_back(wasm.allocator.alloc<Const>()->set(Literal(uint32_t(0))), data);
}
void addInitializerFunction(Name name) {
View
@@ -367,13 +367,14 @@ class SExpressionWasmBuilder {
if (id == START) return parseStart(curr);
if (id == FUNC) return parseFunction(curr);
if (id == MEMORY) return parseMemory(curr);
if (id == DATA) return parseData(curr);
if (id == EXPORT) return parseExport(curr);
if (id == IMPORT) return; // already done
if (id == GLOBAL) return parseGlobal(curr);
if (id == TABLE) return parseTable(curr);
if (id == TYPE) return; // already done
std::cerr << "bad module element " << id.str << '\n';
throw ParseException("unknown module element");
throw ParseException("unknown module element", curr.line, curr.col);
}
// function parsing state
@@ -1321,19 +1322,40 @@ class SExpressionWasmBuilder {
}
while (i < s.size()) {
Element& curr = *s[i];
assert(curr[0]->str() == SEGMENT);
const char *input = curr[2]->c_str();
size_t j = 1;
Address offsetValue;
if (curr[0]->str() == DATA) {
offsetValue = 0;
} else {
offsetValue = atoi(curr[j++]->c_str());
}
const char *input = curr[j]->c_str();
auto* offset = allocator.alloc<Const>();
offset->type = i32;
offset->value = Literal(int32_t(offsetValue));
if (auto size = strlen(input)) {
std::vector<char> data;
stringToBinary(input, size, data);
wasm.memory.segments.emplace_back(atoi(curr[1]->c_str()), data.data(), data.size());
wasm.memory.segments.emplace_back(offset, data.data(), data.size());
} else {
wasm.memory.segments.emplace_back(atoi(curr[1]->c_str()), "", 0);
wasm.memory.segments.emplace_back(offset, "", 0);
}
i++;
}
}
void parseData(Element& s) {
auto* offset = parseExpression(s[1]);
const char *input = s[2]->c_str();
if (auto size = strlen(input)) {
std::vector<char> data;
stringToBinary(input, size, data);
wasm.memory.segments.emplace_back(offset, data.data(), data.size());
} else {
wasm.memory.segments.emplace_back(offset, "", 0);
}
}
void parseExport(Element& s) {
if (!s[2]->dollared() && !std::isdigit(s[2]->str()[0])) {
assert(s[2]->str() == MEMORY);
View
@@ -281,12 +281,6 @@ struct WasmValidator : public PostWalker<WasmValidator, Visitor<WasmValidator>>
void visitMemory(Memory *curr) {
shouldBeFalse(curr->initial > curr->max, "memory", "memory max >= initial");
shouldBeTrue(curr->max <= Memory::kMaxSize, "memory", "max memory must be <= 4GB");
size_t top = 0;
for (auto& segment : curr->segments) {
shouldBeFalse(segment.offset < top, "memory", "segment offset is small enough");
top = segment.offset + segment.data.size();
}
shouldBeFalse(top > curr->initial * Memory::kPageSize, "memory", "total segments must be small enough");
}
void visitModule(Module *curr) {
// exports
View
@@ -49,6 +49,7 @@ Name GROW_WASM_MEMORY("__growWasmMemory"),
PARAM("param"),
RESULT("result"),
MEMORY("memory"),
DATA("data"),
SEGMENT("segment"),
EXPORT("export"),
IMPORT("import"),
View
@@ -1441,14 +1441,14 @@ class Memory {
static const Address::address_t kMaxSize = ~Address::address_t(0) / kPageSize;
static const Address::address_t kPageMask = ~(kPageSize - 1);
struct Segment {
Address offset;
Expression* offset;
std::vector<char> data; // TODO: optimize
Segment() {}
Segment(Address offset, const char *init, Address size) : offset(offset) {
Segment(Expression* offset, const char *init, Address size) : offset(offset) {
data.resize(size);
std::copy_n(init, size, data.begin());
}
Segment(Address offset, std::vector<char>& init) : offset(offset) {
Segment(Expression* offset, std::vector<char>& init) : offset(offset) {
data.swap(init);
}
};
View
@@ -1,7 +1,6 @@
(module
(memory 1
(segment 16 "\d2\04\00\00\00\00\00\00)\t\00\00")
)
(memory 1)
(data (i32.const 16) "\d2\04\00\00\00\00\00\00)\t\00\00")
(export "memory" memory)
(type $FUNCSIG$v (func))
(export "__exit" $__exit)
@@ -1,7 +1,6 @@
(module
(memory 1
(segment 16 "{ Module.print(\"hello, world!\"); }\00")
)
(memory 1)
(data (i32.const 16) "{ Module.print(\"hello, world!\"); }\00")
(export "memory" memory)
(type $FUNCSIG$vi (func (param i32)))
(import $emscripten_asm_const_vi "env" "emscripten_asm_const_vi" (param i32))
View
@@ -1,9 +1,8 @@
(module
(memory 1
(segment 16 "hello, world!\n\00")
(segment 32 "vcq")
(segment 48 "\16\00\00\00")
)
(memory 1)
(data (i32.const 16) "hello, world!\n\00")
(data (i32.const 32) "vcq")
(data (i32.const 48) "\16\00\00\00")
(export "memory" memory)
(type $FUNCSIG$vi (func (param i32)))
(type $FUNCSIG$v (func))
View
@@ -1,13 +1,12 @@
(module
(memory 1
(segment 16 "\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00\06\00\00\00")
(segment 40 "\07\00\00\00\08\00\00\00\t\00\00\00")
(segment 52 "\n\00\00\00\0b\00\00\00")
(segment 60 "\0c\00\00\00\0d\00\00\00\0e\00\00\00")
(segment 72 "\0f\00\00\00\10\00\00\00\11\00\00\00")
(segment 96 "hi\00")
(segment 100 "\00\00\00\00")
)
(memory 1)
(data (i32.const 16) "\01\00\00\00\02\00\00\00\03\00\00\00\04\00\00\00\05\00\00\00\06\00\00\00")
(data (i32.const 40) "\07\00\00\00\08\00\00\00\t\00\00\00")
(data (i32.const 52) "\n\00\00\00\0b\00\00\00")
(data (i32.const 60) "\0c\00\00\00\0d\00\00\00\0e\00\00\00")
(data (i32.const 72) "\0f\00\00\00\10\00\00\00\11\00\00\00")
(data (i32.const 96) "hi\00")
(data (i32.const 100) "\00\00\00\00")
(export "memory" memory)
(type $FUNCSIG$i (func (result i32)))
(type $FUNCSIG$ii (func (param i32) (result i32)))
@@ -1,8 +1,7 @@
(module
(memory 1
(segment 12 "\00\00\00\00")
(segment 416 "`\00\00\00")
)
(memory 1)
(data (i32.const 12) "\00\00\00\00")
(data (i32.const 416) "`\00\00\00")
(export "memory" memory)
)
;; METADATA: { "asmConsts": {},"staticBump": 420, "initializers": [] }
@@ -1,9 +1,8 @@
(module
(memory 1
(segment 12 "\00\00\00\00")
(segment 16 "\01\00\00\00")
(segment 20 "33\13@")
)
(memory 1)
(data (i32.const 12) "\00\00\00\00")
(data (i32.const 16) "\01\00\00\00")
(data (i32.const 20) "33\13@")
(export "memory" memory)
(export "foo" $foo)
(export "bar" $bar)
View
@@ -1,7 +1,6 @@
(module
(memory 1
(segment 16 "\04\00\00\00\02\00\00\00\01\00\00\00\03\00\00\00")
)
(memory 1)
(data (i32.const 16) "\04\00\00\00\02\00\00\00\01\00\00\00\03\00\00\00")
(export "memory" memory)
(type $FUNCSIG$i (func (result i32)))
(type $FUNCSIG$v (func))
@@ -1,7 +1,6 @@
(module
(memory 1
(segment 20 "\10\00\00\00")
)
(memory 1)
(data (i32.const 20) "\10\00\00\00")
(export "memory" memory)
)
;; METADATA: { "asmConsts": {},"staticBump": 24, "initializers": [] }
Oops, something went wrong.

0 comments on commit 7e39178

Please sign in to comment.