summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJF Bastien <jfb@chromium.org>2016-02-04 05:18:07 -0800
committerJF Bastien <jfb@chromium.org>2016-02-05 00:51:24 -0800
commit3fbae879fc1b678e748ab3f8c24148e1c3818f45 (patch)
treea0592797c47de742624a4d1e2011a459b2273a17
parentc1f9026c2788e4ef6f6af0c6d9aa04d22fc00320 (diff)
downloadbinaryen-3fbae879fc1b678e748ab3f8c24148e1c3818f45.tar.gz
binaryen-3fbae879fc1b678e748ab3f8c24148e1c3818f45.tar.bz2
binaryen-3fbae879fc1b678e748ab3f8c24148e1c3818f45.zip
Support start
As spec'd in: https://github.com/WebAssembly/design/pull/495 And discussed in: https://github.com/WebAssembly/spec/issues/231 This will make it simpler and more uniform to add a start entry point. s2wasm is the right place to add start because it'll eventually need to do other basic setup, e.g. put code in start to setup the stack, as dschuff is doing in: https://github.com/WebAssembly/binaryen/pull/179 Or rather, the linker is the right place and s2wasm happens to act as our linker right now.
-rwxr-xr-xcheck.py4
-rw-r--r--src/emscripten-optimizer/istring.h4
-rw-r--r--src/s2wasm-main.cpp8
-rw-r--r--src/s2wasm.h53
-rw-r--r--src/shared-constants.h1
-rw-r--r--src/wasm-s-parser.h3
-rw-r--r--src/wasm.h8
-rw-r--r--test/dot_s/start_main0.s8
-rw-r--r--test/dot_s/start_main0.wast12
-rw-r--r--test/dot_s/start_main2.s11
-rw-r--r--test/dot_s/start_main2.wast20
11 files changed, 122 insertions, 10 deletions
diff --git a/check.py b/check.py
index 22acc0228..10093a3cc 100755
--- a/check.py
+++ b/check.py
@@ -408,7 +408,9 @@ for dot_s_dir in ['dot_s', 'llvm_autogenerated']:
print '..', s
wasm = s.replace('.s', '.wast')
full = os.path.join('test', dot_s_dir, s)
- actual, err = subprocess.Popen([os.path.join('bin', 's2wasm'), full], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ start = ['--start'] if s.startswith('start_') else []
+ cmd = [os.path.join('bin', 's2wasm'), full] + start
+ actual, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
assert err == '', 'bad err:' + err
# verify output
diff --git a/src/emscripten-optimizer/istring.h b/src/emscripten-optimizer/istring.h
index d114540e2..abc1e327b 100644
--- a/src/emscripten-optimizer/istring.h
+++ b/src/emscripten-optimizer/istring.h
@@ -114,8 +114,8 @@ struct IString {
const char *c_str() const { return str; }
bool equals(const char *other) const { return !strcmp(str, other); }
- bool is() { return str != nullptr; }
- bool isNull() { return str == nullptr; }
+ bool is() const { return str != nullptr; }
+ bool isNull() const { return str == nullptr; }
};
} // namespace cashew
diff --git a/src/s2wasm-main.cpp b/src/s2wasm-main.cpp
index e75147b75..03321a608 100644
--- a/src/s2wasm-main.cpp
+++ b/src/s2wasm-main.cpp
@@ -28,6 +28,7 @@ using namespace wasm;
int main(int argc, const char *argv[]) {
bool ignoreUnknownSymbols = false;
+ std::string startFunction;
Options options("s2wasm", "Link .s file into .wast");
options
.add("--output", "-o", "Output file (stdout if not specified)",
@@ -41,6 +42,11 @@ int main(int argc, const char *argv[]) {
[&ignoreUnknownSymbols](Options *, const std::string &) {
ignoreUnknownSymbols = true;
})
+ .add("--start", "", "Generate the start method (default: main)",
+ Options::Arguments::Optional,
+ [&startFunction](Options *, const std::string &argument) {
+ startFunction = argument.size() ? argument : "main";
+ })
.add("--global-base", "-g", "Where to start to place globals",
Options::Arguments::One,
[](Options *o, const std::string &argument) {
@@ -70,7 +76,7 @@ int main(int argc, const char *argv[]) {
: 0;
if (options.debug) std::cerr << "Global base " << globalBase << '\n';
S2WasmBuilder s2wasm(wasm, input.c_str(), options.debug, globalBase,
- stackAllocation, ignoreUnknownSymbols);
+ stackAllocation, ignoreUnknownSymbols, startFunction);
if (options.debug) std::cerr << "Emscripten gluing..." << std::endl;
std::stringstream meta;
diff --git a/src/s2wasm.h b/src/s2wasm.h
index 1e0a28b43..5f8ba850f 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -39,15 +39,17 @@ class S2WasmBuilder {
const char* s;
bool debug;
bool ignoreUnknownSymbols;
+ const std::string &startFunction;
public:
S2WasmBuilder(AllocatingModule& wasm, const char* input, bool debug,
size_t globalBase, size_t stackAllocation,
- bool ignoreUnknownSymbols)
+ bool ignoreUnknownSymbols, const std::string& startFunction)
: wasm(wasm),
allocator(wasm.allocator),
debug(debug),
ignoreUnknownSymbols(ignoreUnknownSymbols),
+ startFunction(startFunction),
globalBase(globalBase),
nextStatic(globalBase) {
s = input;
@@ -78,7 +80,7 @@ class S2WasmBuilder {
};
std::vector<Relocation> relocations;
- std::set<Name> implementedFunctions;
+ std::map<Name, Function*> implementedFunctions;
std::map<Name, Name> aliasedFunctions;
std::map<size_t, size_t> addressSegments; // address => segment index
@@ -365,7 +367,7 @@ class S2WasmBuilder {
if (match(".hidden")) mustMatch(name.str);
mustMatch(name.str);
if (match(":")) {
- implementedFunctions.insert(name);
+ implementedFunctions.insert({name, nullptr});
} else if (match("=")) {
Name alias = getAtSeparated();
mustMatch("@FUNCTION");
@@ -485,6 +487,7 @@ class S2WasmBuilder {
};
auto func = allocator.alloc<Function>();
+ implementedFunctions[name] = func;
func->name = name;
std::map<Name, WasmType> localTypes;
// params and result
@@ -722,7 +725,7 @@ class S2WasmBuilder {
Name target = cleanFunction(getCommaSeparated());
auto aliased = aliasedFunctions.find(target);
if (aliased != aliasedFunctions.end()) target = aliased->second;
- if (implementedFunctions.count(target) > 0) {
+ if (implementedFunctions.count(target) != 0) {
auto specific = allocator.alloc<Call>();
specific->target = target;
curr = specific;
@@ -1171,13 +1174,15 @@ class S2WasmBuilder {
if (functionIndexes.count(name) == 0) {
functionIndexes[name] = wasm.table.names.size();
wasm.table.names.push_back(name);
- if (debug) std::cerr << "function index: " << name << ": " << functionIndexes[name] << '\n';
+ if (debug)
+ std::cerr << "function index: " << name << ": "
+ << functionIndexes[name] << '\n';
}
};
for (auto& relocation : relocations) {
Name name = relocation.value;
if (debug) std::cerr << "fix relocation " << name << '\n';
- const auto &symbolAddress = staticAddresses.find(name);
+ const auto& symbolAddress = staticAddresses.find(name);
if (symbolAddress != staticAddresses.end()) {
*(relocation.data) = symbolAddress->second + relocation.offset;
if (debug) std::cerr << " ==> " << *(relocation.data) << '\n';
@@ -1193,6 +1198,42 @@ class S2WasmBuilder {
}
}
}
+ if (startFunction.size()) {
+ if (implementedFunctions.count(startFunction) == 0) {
+ std::cerr << "Unknown start function: `" << startFunction << "`\n";
+ abort();
+ }
+ const auto *target = implementedFunctions[startFunction];
+ Name start("_start");
+ if (implementedFunctions.count(start) != 0) {
+ std::cerr << "Start function already present: `" << start << "`\n";
+ abort();
+ }
+ auto* func = allocator.alloc<Function>();
+ func->name = start;
+ wasm.addFunction(func);
+ auto* exp = allocator.alloc<Export>();
+ exp->name = exp->value = start;
+ wasm.addExport(exp);
+ wasm.addStart(start);
+ auto* block = allocator.alloc<Block>();
+ func->body = block;
+ { // Create the call, matching its parameters.
+ // TODO allow calling with non-default values.
+ auto* call = allocator.alloc<Call>();
+ call->target = startFunction;
+ size_t paramNum = 0;
+ for (const NameType& nt : target->params) {
+ Name name = Name::fromInt(paramNum++);
+ func->locals.emplace_back(name, nt.type);
+ auto* param = allocator.alloc<GetLocal>();
+ param->name = name;
+ param->type = nt.type;
+ call->operands.push_back(param);
+ }
+ block->list.push_back(call);
+ }
+ }
}
template<class C>
diff --git a/src/shared-constants.h b/src/shared-constants.h
index a928756da..6662c50b2 100644
--- a/src/shared-constants.h
+++ b/src/shared-constants.h
@@ -52,6 +52,7 @@ cashew::IString GLOBAL("global"),
GROW_WASM_MEMORY("__growWasmMemory"),
NEW_SIZE("newSize"),
MODULE("module"),
+ START("start"),
FUNC("func"),
PARAM("param"),
RESULT("result"),
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 1c704ac74..e2a880e51 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -283,6 +283,7 @@ private:
void parseModuleElement(Element& curr) {
IString id = curr[0]->str();
+ if (id == START) return parseStart(curr);
if (id == FUNC) return parseFunction(curr);
if (id == MEMORY) return parseMemory(curr);
if (id == EXPORT) return parseExport(curr);
@@ -304,6 +305,8 @@ private:
return IString((prefix + std::to_string(otherIndex++)).c_str(), false);
}
+ void parseStart(Element& s) { wasm.addStart(s[1]->str()); }
+
void parseFunction(Element& s) {
auto func = currFunction = allocator.alloc<Function>();
size_t i = 1;
diff --git a/src/wasm.h b/src/wasm.h
index c030d9d60..b9d0d6822 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1125,6 +1125,7 @@ public:
std::map<Name, Function*> functionsMap;
Table table;
Memory memory;
+ Name start;
Module() : functionTypeIndex(0), importIndex(0), exportIndex(0), functionIndex(0) {}
@@ -1168,6 +1169,9 @@ public:
functionsMap[numericName] = curr;
functionIndex++;
}
+ void addStart(const Name &s) {
+ start = s;
+ }
void removeImport(Name name) {
for (size_t i = 0; i < imports.size(); i++) {
@@ -1211,6 +1215,10 @@ public:
o << "\")";
}
o << (module.memory.segments.size() > 0 ? "\n " : "") << ")\n";
+ if (module.start.is()) {
+ doIndent(o, indent);
+ printOpening(o, "start") << " " << module.start << ")\n";
+ }
for (auto& curr : module.functionTypes) {
doIndent(o, indent);
curr->print(o, indent, true);
diff --git a/test/dot_s/start_main0.s b/test/dot_s/start_main0.s
new file mode 100644
index 000000000..85323ee62
--- /dev/null
+++ b/test/dot_s/start_main0.s
@@ -0,0 +1,8 @@
+ .text
+ .file "main0"
+ .globl main
+ .type main,@function
+main: # @main
+# BB#0:
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
diff --git a/test/dot_s/start_main0.wast b/test/dot_s/start_main0.wast
new file mode 100644
index 000000000..d40390aee
--- /dev/null
+++ b/test/dot_s/start_main0.wast
@@ -0,0 +1,12 @@
+(module
+ (memory 0 4294967295)
+ (start $_start)
+ (export "main" $main)
+ (export "_start" $_start)
+ (func $main
+ )
+ (func $_start
+ (call $main)
+ )
+)
+;; METADATA: { "asmConsts": {},"staticBump": 4 }
diff --git a/test/dot_s/start_main2.s b/test/dot_s/start_main2.s
new file mode 100644
index 000000000..7f77ec463
--- /dev/null
+++ b/test/dot_s/start_main2.s
@@ -0,0 +1,11 @@
+ .text
+ .file "main2"
+ .globl main
+ .type main,@function
+main: # @main
+ .param i32, i32
+ .result i32
+# BB#0:
+ return $0
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
diff --git a/test/dot_s/start_main2.wast b/test/dot_s/start_main2.wast
new file mode 100644
index 000000000..42e8b4897
--- /dev/null
+++ b/test/dot_s/start_main2.wast
@@ -0,0 +1,20 @@
+(module
+ (memory 0 4294967295)
+ (start $_start)
+ (export "main" $main)
+ (export "_start" $_start)
+ (func $main (param $$0 i32) (param $$1 i32) (result i32)
+ (return
+ (get_local $$0)
+ )
+ )
+ (func $_start
+ (local $0 i32)
+ (local $1 i32)
+ (call $main
+ (get_local $0)
+ (get_local $1)
+ )
+ )
+)
+;; METADATA: { "asmConsts": {},"staticBump": 4 }