summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerek Schuff <dschuff@chromium.org>2016-04-27 09:18:37 -0700
committerDerek Schuff <dschuff@chromium.org>2016-04-27 09:18:37 -0700
commitd63486d0ef085f905dafdb14a76cfb2ca1fb452e (patch)
tree33fd133e9c3313c458ae756f0e7b397dfb198d28
parent206338a6c4e3f9739abd7a2ad082d1770b3a628f (diff)
downloadbinaryen-d63486d0ef085f905dafdb14a76cfb2ca1fb452e.tar.gz
binaryen-d63486d0ef085f905dafdb14a76cfb2ca1fb452e.tar.bz2
binaryen-d63486d0ef085f905dafdb14a76cfb2ca1fb452e.zip
Split construction, scanning, and building phases of S2WasmBuilder (#400)
Instead of doing all of the S2Wasm work in the constructor, split construction, scanning (to determine implemented functions) and building of the wasm module. This allows the linker to get the symbol information (e.g. implemented functions) without having to build an entire module (which will be useful for archives) and to allow the linker to link a new object into the existing one by building the wasm module in place on the existing module.
-rw-r--r--src/asm2wasm.h2
-rw-r--r--src/asmjs/CMakeLists.txt1
-rw-r--r--src/asmjs/shared-constants.cpp (renamed from src/shared-constants.h)9
-rw-r--r--src/asmjs/shared-constants.h104
-rw-r--r--src/parsing.h4
-rw-r--r--src/s2wasm-main.cpp8
-rw-r--r--src/s2wasm.h109
-rw-r--r--src/shell-interface.h3
-rw-r--r--src/wasm-binary.h2
-rw-r--r--src/wasm-linker.cpp36
-rw-r--r--src/wasm-linker.h48
-rw-r--r--src/wasm-s-parser.h2
-rw-r--r--src/wasm2asm.h2
13 files changed, 250 insertions, 80 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index 1da59d2f2..ae24358d7 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -25,7 +25,7 @@
#include "wasm.h"
#include "emscripten-optimizer/optimizer.h"
#include "mixed_arena.h"
-#include "shared-constants.h"
+#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
#include "pass.h"
#include "ast_utils.h"
diff --git a/src/asmjs/CMakeLists.txt b/src/asmjs/CMakeLists.txt
index 8be8ea2c4..2387d3ca0 100644
--- a/src/asmjs/CMakeLists.txt
+++ b/src/asmjs/CMakeLists.txt
@@ -1,4 +1,5 @@
SET(asmjs_SOURCES
asm_v_wasm.cpp
+ shared-constants.cpp
)
ADD_LIBRARY(asmjs STATIC ${asmjs_SOURCES}) \ No newline at end of file
diff --git a/src/shared-constants.h b/src/asmjs/shared-constants.cpp
index 626c5423e..bc1c0fa3d 100644
--- a/src/shared-constants.h
+++ b/src/asmjs/shared-constants.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 WebAssembly Community Group participants
+ * Copyright 2016 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,7 @@
* limitations under the License.
*/
-#ifndef wasm_shared_constants_h
-#define wasm_shared_constants_h
-
-#include "emscripten-optimizer/optimizer.h"
+#include "asmjs/shared-constants.h"
namespace wasm {
@@ -100,5 +97,3 @@ cashew::IString GLOBAL("global"),
EXIT("exit");
}
-
-#endif // wasm_shared_constants_h
diff --git a/src/asmjs/shared-constants.h b/src/asmjs/shared-constants.h
new file mode 100644
index 000000000..2f6c608ba
--- /dev/null
+++ b/src/asmjs/shared-constants.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2015 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef wasm_asmjs_shared_constants_h
+#define wasm_asmjs_shared_constants_h
+
+#include "emscripten-optimizer/istring.h"
+
+namespace wasm {
+
+extern cashew::IString GLOBAL,
+ NAN_,
+ INFINITY_,
+ NAN__,
+ INFINITY__,
+ TOPMOST,
+ INT8ARRAY,
+ INT16ARRAY,
+ INT32ARRAY,
+ UINT8ARRAY,
+ UINT16ARRAY,
+ UINT32ARRAY,
+ FLOAT32ARRAY,
+ FLOAT64ARRAY,
+ IMPOSSIBLE_CONTINUE,
+ MATH,
+ IMUL,
+ CLZ32,
+ FROUND,
+ ASM2WASM,
+ F64_REM,
+ F64_TO_INT,
+ GLOBAL_MATH,
+ ABS,
+ FLOOR,
+ CEIL,
+ SQRT,
+ I32_TEMP,
+ DEBUGGER,
+ GROW_WASM_MEMORY,
+ NEW_SIZE,
+ MODULE,
+ START,
+ FUNC,
+ PARAM,
+ RESULT,
+ MEMORY,
+ SEGMENT,
+ EXPORT,
+ IMPORT,
+ TABLE,
+ LOCAL,
+ TYPE,
+ CALL,
+ CALL_IMPORT,
+ CALL_INDIRECT,
+ BLOCK,
+ BR_IF,
+ THEN,
+ ELSE,
+ NEG_INFINITY,
+ NEG_NAN,
+ CASE,
+ BR,
+ USE_ASM,
+ BUFFER,
+ ENV,
+ FAKE_RETURN,
+ MATH_IMUL,
+ MATH_CLZ32,
+ MATH_CTZ32,
+ MATH_POPCNT32,
+ MATH_ABS,
+ MATH_CEIL,
+ MATH_FLOOR,
+ MATH_TRUNC,
+ MATH_NEAREST,
+ MATH_SQRT,
+ MATH_MIN,
+ MATH_MAX,
+ ASSERT_RETURN,
+ ASSERT_TRAP,
+ ASSERT_INVALID,
+ SPECTEST,
+ PRINT,
+ INVOKE,
+ EXIT;
+
+}
+
+#endif // wasm_asmjs_shared_constants_h
diff --git a/src/parsing.h b/src/parsing.h
index 935750537..2104337a6 100644
--- a/src/parsing.h
+++ b/src/parsing.h
@@ -19,14 +19,14 @@
#include <sstream>
+#include "asmjs/shared-constants.h"
#include "mixed_arena.h"
-#include "shared-constants.h"
#include "support/utilities.h"
#include "wasm.h"
namespace wasm {
-Expression* parseConst(cashew::IString s, WasmType type, MixedArena& allocator) {
+inline Expression* parseConst(cashew::IString s, WasmType type, MixedArena& allocator) {
const char *str = s.str;
auto ret = allocator.alloc<Const>();
ret->type = type;
diff --git a/src/s2wasm-main.cpp b/src/s2wasm-main.cpp
index 435eb560f..7b0e4c179 100644
--- a/src/s2wasm-main.cpp
+++ b/src/s2wasm-main.cpp
@@ -104,7 +104,13 @@ int main(int argc, const char *argv[]) {
Linker linker(globalBase, stackAllocation, initialMem, maxMem,
ignoreUnknownSymbols, startFunction, options.debug);
- S2WasmBuilder s2wasm(linker.getOutput(), input.c_str(), options.debug);
+ S2WasmBuilder mainbuilder(input.c_str(), options.debug);
+ linker.linkObject(mainbuilder);
+
+ // In the future, there will be code to open additional files/buffers and
+ // link additional objects, as well as archive members (which only get linked if needed), e.g.:
+ // S2WasmBuilder lazyObject(some_other_buffer, options.debug)
+ // linker.linkLazyObject(lazyObject); // calls builder.scan to get symbol info, then build
linker.layout();
diff --git a/src/s2wasm.h b/src/s2wasm.h
index 00e6b12a2..b66859ce9 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -37,26 +37,40 @@ namespace wasm {
//
class S2WasmBuilder {
- Module& wasm;
- MixedArena& allocator;
+ const char* inputStart;
const char* s;
bool debug;
- LinkerObject& linkerObj;
+ Module* wasm;
+ MixedArena* allocator;
+ LinkerObject* linkerObj;
public:
- S2WasmBuilder(LinkerObject& linkerObj, const char* input, bool debug)
- : wasm(linkerObj.wasm),
- allocator(wasm.allocator),
+ S2WasmBuilder(const char* input, bool debug)
+ : inputStart(input),
+ s(input),
debug(debug),
- linkerObj(linkerObj) {
- if (!linkerObj.isEmpty()) Fatal() << "Cannot construct an S2WasmBuilder in an non-empty LinkerObject";
- s = input;
- scan();
- s = input;
+ wasm(nullptr),
+ allocator(nullptr),
+ linkerObj(nullptr)
+ {}
+ void build(LinkerObject *obj, LinkerObject::SymbolInfo* info) {
+ if (!obj->isEmpty()) Fatal() << "Cannot construct an S2WasmBuilder in an non-empty LinkerObject";
+ if (!info) info = getSymbolInfo();
+ linkerObj = obj;
+ wasm = &obj->wasm;
+ allocator = &wasm->allocator;
+
+ s = inputStart;
process();
}
+ LinkerObject::SymbolInfo* getSymbolInfo() {
+ auto* info = new LinkerObject::SymbolInfo();
+ scan(info);
+ return info;
+ }
+
private:
// utilities
@@ -209,7 +223,7 @@ class S2WasmBuilder {
s++;
offset = -getInt();
}
- linkerObj.addRelocation(kind, target, cleanFunction(name), offset);
+ linkerObj->addRelocation(kind, target, cleanFunction(name), offset);
return true;
}
}
@@ -334,7 +348,8 @@ class S2WasmBuilder {
// processors
- void scan() {
+ void scan(LinkerObject::SymbolInfo* info) {
+ s = inputStart;
while (*s) {
skipWhitespace();
s = strstr(s, ".type");
@@ -346,11 +361,11 @@ class S2WasmBuilder {
if (match(".hidden")) mustMatch(name.str);
mustMatch(name.str);
if (match(":")) {
- linkerObj.addImplementedFunction(name);
+ info->implementedFunctions.insert(name);
} else if (match("=")) {
Name alias = getAtSeparated();
mustMatch("@FUNCTION");
- linkerObj.addAliasedFunction(name, alias);
+ info->aliasedFunctions.insert({name, alias});
} else {
abort_on("unknown directive");
}
@@ -402,7 +417,7 @@ class S2WasmBuilder {
}
mustMatch(".int32");
do {
- linkerObj.addInitializerFunction(cleanFunction(getStr()));
+ linkerObj->addInitializerFunction(cleanFunction(getStr()));
skipWhitespace();
} while (match(".int32"));
}
@@ -437,7 +452,7 @@ class S2WasmBuilder {
}
void parseGlobl() {
- linkerObj.addGlobal(getStr());
+ linkerObj->addGlobal(getStr());
skipWhitespace();
}
@@ -465,7 +480,7 @@ class S2WasmBuilder {
auto getNextId = [&nextId]() {
return cashew::IString(('$' + std::to_string(nextId++)).c_str(), false);
};
- wasm::Builder builder(wasm);
+ wasm::Builder builder(*wasm);
std::vector<NameType> params;
WasmType resultType = none;
std::vector<NameType> vars;
@@ -498,7 +513,7 @@ class S2WasmBuilder {
Function* func = builder.makeFunction(name, std::move(params), resultType, std::move(vars));
// parse body
- func->body = allocator.alloc<Block>();
+ func->body = allocator->alloc<Block>();
std::vector<Expression*> bstack;
auto addToBlock = [&bstack](Expression* curr) {
Expression* last = bstack.back();
@@ -543,7 +558,7 @@ class S2WasmBuilder {
skipToSep();
inputs[i] = nullptr;
} else {
- auto curr = allocator.alloc<GetLocal>();
+ auto curr = allocator->alloc<GetLocal>();
curr->index = func->getLocalIndex(getStrToSep());
curr->type = func->getLocalType(curr->index);
inputs[i] = curr;
@@ -569,7 +584,7 @@ class S2WasmBuilder {
} else if (assign.str[1] == 'p') { // push
push(curr);
} else { // set to a local
- auto set = allocator.alloc<SetLocal>();
+ auto set = allocator->alloc<SetLocal>();
set->index = func->getLocalIndex(assign);
set->value = curr;
set->type = curr->type;
@@ -597,7 +612,7 @@ class S2WasmBuilder {
auto makeBinary = [&](BinaryOp op, WasmType type) {
Name assign = getAssign();
skipComma();
- auto curr = allocator.alloc<Binary>();
+ auto curr = allocator->alloc<Binary>();
curr->op = op;
auto inputs = getInputs(2);
curr->left = inputs[0];
@@ -609,7 +624,7 @@ class S2WasmBuilder {
auto makeUnary = [&](UnaryOp op, WasmType type) {
Name assign = getAssign();
skipComma();
- auto curr = allocator.alloc<Unary>();
+ auto curr = allocator->alloc<Unary>();
curr->op = op;
curr->value = getInput();
curr->type = type;
@@ -617,20 +632,20 @@ class S2WasmBuilder {
};
auto makeHost = [&](HostOp op) {
Name assign = getAssign();
- auto curr = allocator.alloc<Host>();
+ auto curr = allocator->alloc<Host>();
curr->op = op;
setOutput(curr, assign);
};
auto makeHost1 = [&](HostOp op) {
Name assign = getAssign();
- auto curr = allocator.alloc<Host>();
+ auto curr = allocator->alloc<Host>();
curr->op = op;
curr->operands.push_back(getInput());
setOutput(curr, assign);
};
auto makeLoad = [&](WasmType type) {
skipComma();
- auto curr = allocator.alloc<Load>();
+ auto curr = allocator->alloc<Load>();
curr->type = type;
int32_t bytes = getInt() / CHAR_BIT;
curr->bytes = bytes > 0 ? bytes : getWasmTypeSize(type);
@@ -650,7 +665,7 @@ class S2WasmBuilder {
};
auto makeStore = [&](WasmType type) {
skipComma();
- auto curr = allocator.alloc<Store>();
+ auto curr = allocator->alloc<Store>();
curr->type = type;
int32_t bytes = getInt() / CHAR_BIT;
curr->bytes = bytes > 0 ? bytes : getWasmTypeSize(type);
@@ -671,7 +686,7 @@ class S2WasmBuilder {
auto makeSelect = [&](WasmType type) {
Name assign = getAssign();
skipComma();
- auto curr = allocator.alloc<Select>();
+ auto curr = allocator->alloc<Select>();
auto inputs = getInputs(3);
curr->ifTrue = inputs[0];
curr->ifFalse = inputs[1];
@@ -689,7 +704,7 @@ class S2WasmBuilder {
auto input = inputs.begin();
auto* target = *input;
std::vector<Expression*> operands(++input, inputs.end());
- auto* funcType = ensureFunctionType(getSig(type, operands), &wasm);
+ auto* funcType = ensureFunctionType(getSig(type, operands), wasm);
assert(type == funcType->result);
auto* indirect = builder.makeCallIndirect(funcType, target, std::move(operands));
setOutput(indirect, assign);
@@ -697,13 +712,13 @@ class S2WasmBuilder {
} else {
// non-indirect call
Name assign = getAssign();
- Name target = linkerObj.resolveAlias(cleanFunction(getCommaSeparated()));
+ Name target = linkerObj->resolveAlias(cleanFunction(getCommaSeparated()));
- Call* curr = allocator.alloc<Call>();
+ Call* curr = allocator->alloc<Call>();
curr->target = target;
curr->type = type;
- if (!linkerObj.isFunctionImplemented(target)) {
- linkerObj.addUndefinedFunctionCall(curr);
+ if (!linkerObj->isFunctionImplemented(target)) {
+ linkerObj->addUndefinedFunctionCall(curr);
}
skipWhitespace();
if (*s == ',') {
@@ -731,13 +746,13 @@ class S2WasmBuilder {
Name assign = getAssign();
if (type == i32) {
// may be a relocation
- auto curr = allocator.alloc<Const>();
+ auto curr = allocator->alloc<Const>();
curr->type = curr->value.type = i32;
getConst((uint32_t*)curr->value.geti32Ptr());
setOutput(curr, assign);
} else {
cashew::IString str = getStr();
- setOutput(parseConst(str, type, allocator), assign);
+ setOutput(parseConst(str, type, *allocator), assign);
}
}
else if (match("call")) makeCall(type);
@@ -891,7 +906,7 @@ class S2WasmBuilder {
} else if (match("f64.")) {
handleTyped(f64);
} else if (match("block")) {
- auto curr = allocator.alloc<Block>();
+ auto curr = allocator->alloc<Block>();
curr->name = getNextLabel();
addToBlock(curr);
bstack.push_back(curr);
@@ -900,11 +915,11 @@ class S2WasmBuilder {
} else if (match(".LBB")) {
s = strchr(s, '\n');
} else if (match("loop")) {
- auto curr = allocator.alloc<Loop>();
+ auto curr = allocator->alloc<Loop>();
addToBlock(curr);
curr->in = getNextLabel();
curr->out = getNextLabel();
- auto block = allocator.alloc<Block>();
+ auto block = allocator->alloc<Block>();
block->name = curr->out; // temporary, fake - this way, on bstack we have the right label at the right offset for a br
curr->body = block;
loopBlocks.push_back(block);
@@ -914,7 +929,7 @@ class S2WasmBuilder {
bstack.pop_back();
bstack.pop_back();
} else if (match("br_table")) {
- auto curr = allocator.alloc<Switch>();
+ auto curr = allocator->alloc<Switch>();
curr->condition = getInput();
while (skipComma()) {
curr->targets.push_back(getBranchLabel(getInt()));
@@ -924,7 +939,7 @@ class S2WasmBuilder {
curr->targets.pop_back();
addToBlock(curr);
} else if (match("br")) {
- auto curr = allocator.alloc<Break>();
+ auto curr = allocator->alloc<Break>();
bool hasCondition = false;
if (*s == '_') {
mustMatch("_if");
@@ -945,7 +960,7 @@ class S2WasmBuilder {
} else if (match("tee_local")) {
Name assign = getAssign();
skipComma();
- auto curr = allocator.alloc<SetLocal>();
+ auto curr = allocator->alloc<SetLocal>();
curr->index = func->getLocalIndex(getAssign());
skipComma();
curr->value = getInput();
@@ -954,7 +969,7 @@ class S2WasmBuilder {
} else if (match("return")) {
addToBlock(builder.makeReturn(*s == '$' ? getInput() : nullptr));
} else if (match("unreachable")) {
- addToBlock(allocator.alloc<Unreachable>());
+ addToBlock(allocator->alloc<Unreachable>());
} else if (match("memory_size")) {
makeHost(CurrentMemory);
} else if (match("grow_memory")) {
@@ -978,7 +993,7 @@ class S2WasmBuilder {
block->name = Name();
}
func->body->dynCast<Block>()->finalize();
- wasm.addFunction(func);
+ wasm->addFunction(func);
}
void parseType() {
@@ -1064,7 +1079,7 @@ class S2WasmBuilder {
size_t size = raw->size();
raw->resize(size + 4);
if (getConst((uint32_t*)&(*raw)[size])) { // just the size, as we may reallocate; we must fix this later, if it's a relocation
- currRelocations.emplace_back(linkerObj.getCurrentRelocation(), size);
+ currRelocations.emplace_back(linkerObj->getCurrentRelocation(), size);
}
zero = false;
} else if (match(".int64")) {
@@ -1095,9 +1110,9 @@ class S2WasmBuilder {
r->data = (uint32_t*)&(*raw)[i];
}
// assign the address, add to memory
- linkerObj.addStatic(size, align, name);
+ linkerObj->addStatic(size, align, name);
if (!zero) {
- linkerObj.addSegment(name, (const char*)&(*raw)[0], size);
+ linkerObj->addSegment(name, (const char*)&(*raw)[0], size);
}
}
@@ -1109,7 +1124,7 @@ class S2WasmBuilder {
skipComma();
getInt();
}
- linkerObj.addStatic(size, align, name);
+ linkerObj->addStatic(size, align, name);
}
void skipImports() {
diff --git a/src/shell-interface.h b/src/shell-interface.h
index daaf23501..b23b7b645 100644
--- a/src/shell-interface.h
+++ b/src/shell-interface.h
@@ -18,7 +18,7 @@
// Implementation of the shell interpreter execution environment
//
-#include "shared-constants.h"
+#include "asmjs/shared-constants.h"
#include "wasm.h"
#include "wasm-interpreter.h"
@@ -177,4 +177,3 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
};
}
-
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index d13e1a526..0cf85a50f 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -26,7 +26,7 @@
#include "wasm.h"
#include "wasm-traversal.h"
-#include "shared-constants.h"
+#include "asmjs/shared-constants.h"
#include "asm_v_wasm.h"
#include "wasm-builder.h"
#include "ast_utils.h"
diff --git a/src/wasm-linker.cpp b/src/wasm-linker.cpp
index 8fc4f18c8..6dca9e01b 100644
--- a/src/wasm-linker.cpp
+++ b/src/wasm-linker.cpp
@@ -17,6 +17,7 @@
#include "wasm-linker.h"
#include "asm_v_wasm.h"
#include "ast_utils.h"
+#include "s2wasm.h"
#include "support/utilities.h"
#include "wasm-builder.h"
#include "wasm-printing.h"
@@ -51,7 +52,7 @@ void Linker::placeStackPointer(size_t stackAllocation) {
void Linker::layout() {
// Convert calls to undefined functions to call_imports
- for (const auto& f : out.undefinedFunctions) {
+ for (const auto& f : out.undefinedFunctionCalls) {
Name target = f.first;
// Create an import for the target if necessary.
if (!out.wasm.checkImport(target)) {
@@ -145,12 +146,12 @@ void Linker::layout() {
}
}
if (!!startFunction) {
- if (out.implementedFunctions.count(startFunction) == 0) {
+ if (out.symbolInfo.implementedFunctions.count(startFunction) == 0) {
Fatal() << "Unknown start function: `" << startFunction << "`\n";
}
const auto *target = out.wasm.getFunction(startFunction);
Name start("_start");
- if (out.implementedFunctions.count(start) != 0) {
+ if (out.symbolInfo.implementedFunctions.count(start) != 0) {
Fatal() << "Start function already present: `" << start << "`\n";
}
auto* func = out.wasm.allocator.alloc<Function>();
@@ -186,6 +187,35 @@ void Linker::layout() {
}
}
+bool Linker::linkObject(S2WasmBuilder& builder) {
+ LinkerObject::SymbolInfo *newSymbols = builder.getSymbolInfo();
+ // check for multiple definitions
+ for (const Name& symbol : newSymbols->implementedFunctions) {
+ if (out.symbolInfo.implementedFunctions.count(symbol)) {
+ // TODO: Figure out error handling for library-style pieces
+ // TODO: give LinkerObjects (or builders) names for better errors.
+ std::cerr << "Error: multiple definition of symbol " << symbol << "\n";
+ return false;
+ }
+ }
+ // Allow duplicate aliases only if they refer to the same name. For now we
+ // do not expect aliases in compiler-rt files.
+ // TODO: figure out what the semantics of merging aliases should be.
+ for (const auto& alias : newSymbols->aliasedFunctions) {
+ if (out.symbolInfo.aliasedFunctions.count(alias.first) &&
+ out.symbolInfo.aliasedFunctions[alias.first] != alias.second) {
+ std::cerr << "Error: conflicting definitions for alias "
+ << alias.first.c_str() << "\n";
+ return false;
+ }
+ }
+ out.symbolInfo.merge(std::move(*newSymbols));
+ builder.build(&out, &out.symbolInfo);
+ delete newSymbols;
+ return true;
+}
+
+
void Linker::emscriptenGlue(std::ostream& o) {
if (debug) {
WasmPrinter::printModule(&out.wasm, std::cerr);
diff --git a/src/wasm-linker.h b/src/wasm-linker.h
index e72f862f1..ab336e581 100644
--- a/src/wasm-linker.h
+++ b/src/wasm-linker.h
@@ -29,6 +29,8 @@
namespace wasm {
+class S2WasmBuilder;
+
// An "object file" for linking. Contains a wasm module, plus the associated
// information needed for linking/layout.
class LinkerObject {
@@ -44,6 +46,26 @@ class LinkerObject {
Relocation(Kind kind, uint32_t* data, Name symbol, int addend) :
kind(kind), data(data), symbol(symbol), addend(addend) {}
};
+ // Information about symbols
+ struct SymbolInfo {
+ std::unordered_set<cashew::IString> implementedFunctions;
+ std::unordered_set<cashew::IString> undefinedFunctions;
+ // TODO: it's not clear that this really belongs here.
+ std::unordered_map<cashew::IString, Name> aliasedFunctions;
+
+ // For now, do not support weak symbols or anything special. Just directly
+ // merge the functions together, and remove any newly-defined functions
+ // from undefinedFunction
+ void merge(SymbolInfo&& other) {
+ for (const auto& func : other.implementedFunctions) {
+ undefinedFunctions.erase(func);
+ }
+ implementedFunctions.insert(other.implementedFunctions.begin(),
+ other.implementedFunctions.end());
+ aliasedFunctions.insert(other.aliasedFunctions.begin(),
+ other.aliasedFunctions.end());
+ }
+ };
LinkerObject() {}
@@ -63,20 +85,15 @@ class LinkerObject {
return relocations.back().get();
}
- void addImplementedFunction(Name name) {
- implementedFunctions.insert(name);
- }
+
bool isFunctionImplemented(Name name) {
- return implementedFunctions.count(name) != 0;
+ return symbolInfo.implementedFunctions.count(name) != 0;
}
- void addAliasedFunction(Name name, Name alias) {
- aliasedFunctions.insert({name, alias});
- }
// If name is an alias, return what it points to. Otherwise return name
Name resolveAlias(Name name) {
- auto aliased = aliasedFunctions.find(name);
- if (aliased != aliasedFunctions.end()) return aliased->second;
+ auto aliased = symbolInfo.aliasedFunctions.find(name);
+ if (aliased != symbolInfo.aliasedFunctions.end()) return aliased->second;
return name;
}
@@ -88,11 +105,12 @@ class LinkerObject {
void addInitializerFunction(Name name) {
initializerFunctions.emplace_back(name);
- assert(implementedFunctions.count(name));
+ assert(symbolInfo.implementedFunctions.count(name));
}
void addUndefinedFunctionCall(Call* call) {
- undefinedFunctions[call->target].push_back(call);
+ symbolInfo.undefinedFunctions.insert(call->target);
+ undefinedFunctionCalls[call->target].push_back(call);
}
bool isEmpty() {
@@ -117,11 +135,10 @@ class LinkerObject {
std::vector<StaticObject> staticObjects;
std::vector<std::unique_ptr<Relocation>> relocations;
- std::set<Name> implementedFunctions;
- std::unordered_map<cashew::IString, Name> aliasedFunctions;
+ SymbolInfo symbolInfo;
using CallList = std::vector<Call*>;
- std::map<Name, CallList> undefinedFunctions;
+ std::map<Name, CallList> undefinedFunctionCalls;
std::map<Name, size_t> segments; // name => segment index (in wasm module)
@@ -187,6 +204,9 @@ class Linker {
// metadata for asmConsts, staticBump and initializer functions.
void emscriptenGlue(std::ostream& o);
+ // Add an object to the link by constructing it in-place with a builder.
+ bool linkObject(S2WasmBuilder& builder);
+
private:
// Allocate a static variable and return its address in linear memory
size_t allocateStatic(size_t allocSize, size_t alignment, Name name) {
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index e1a073b0b..b6a532790 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -27,8 +27,8 @@
#include <limits>
#include "wasm.h"
+#include "asmjs/shared-constants.h"
#include "mixed_arena.h"
-#include "shared-constants.h"
#include "parsing.h"
#include "asm_v_wasm.h"
#include "ast_utils.h"
diff --git a/src/wasm2asm.h b/src/wasm2asm.h
index 1c1dba6e1..82eb0b1a9 100644
--- a/src/wasm2asm.h
+++ b/src/wasm2asm.h
@@ -24,11 +24,11 @@
#include <cmath>
+#include "asmjs/shared-constants.h"
#include "wasm.h"
#include "emscripten-optimizer/optimizer.h"
#include "mixed_arena.h"
#include "asm_v_wasm.h"
-#include "shared-constants.h"
namespace wasm {