summaryrefslogtreecommitdiff
path: root/src/wasm/wasm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm.cpp')
-rw-r--r--src/wasm/wasm.cpp198
1 files changed, 198 insertions, 0 deletions
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
new file mode 100644
index 000000000..cf58949de
--- /dev/null
+++ b/src/wasm/wasm.cpp
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ * 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.
+ */
+
+#include "wasm.h"
+#include "wasm-traversal.h"
+#include "ast_utils.h"
+
+namespace wasm {
+
+// shared constants
+
+Name WASM("wasm"),
+ RETURN_FLOW("*return:)*");
+
+namespace BinaryConsts {
+namespace UserSections {
+const char* Name = "name";
+}
+}
+
+Name GROW_WASM_MEMORY("__growWasmMemory"),
+ NEW_SIZE("newSize"),
+ MODULE("module"),
+ START("start"),
+ FUNC("func"),
+ PARAM("param"),
+ RESULT("result"),
+ MEMORY("memory"),
+ DATA("data"),
+ SEGMENT("segment"),
+ EXPORT("export"),
+ IMPORT("import"),
+ TABLE("table"),
+ ELEM("elem"),
+ LOCAL("local"),
+ TYPE("type"),
+ CALL("call"),
+ CALL_IMPORT("call_import"),
+ CALL_INDIRECT("call_indirect"),
+ BLOCK("block"),
+ BR_IF("br_if"),
+ THEN("then"),
+ ELSE("else"),
+ _NAN("NaN"),
+ _INFINITY("Infinity"),
+ NEG_INFINITY("-infinity"),
+ NEG_NAN("-nan"),
+ CASE("case"),
+ BR("br"),
+ ANYFUNC("anyfunc"),
+ FAKE_RETURN("fake_return_waka123"),
+ MUT("mut"),
+ SPECTEST("spectest"),
+ PRINT("print"),
+ EXIT("exit");
+
+// core AST type checking
+
+struct TypeSeeker : public PostWalker<TypeSeeker, Visitor<TypeSeeker>> {
+ Expression* target; // look for this one
+ Name targetName;
+ std::vector<WasmType> types;
+
+ TypeSeeker(Expression* target, Name targetName) : target(target), targetName(targetName) {
+ Expression* temp = target;
+ walk(temp);
+ }
+
+ void visitBreak(Break* curr) {
+ if (curr->name == targetName) {
+ types.push_back(curr->value ? curr->value->type : none);
+ }
+ }
+
+ void visitSwitch(Switch* curr) {
+ for (auto name : curr->targets) {
+ if (name == targetName) types.push_back(curr->value ? curr->value->type : none);
+ }
+ if (curr->default_ == targetName) types.push_back(curr->value ? curr->value->type : none);
+ }
+
+ void visitBlock(Block* curr) {
+ if (curr == target) {
+ if (curr->list.size() > 0) {
+ types.push_back(curr->list.back()->type);
+ } else {
+ types.push_back(none);
+ }
+ } else if (curr->name == targetName) {
+ types.clear(); // ignore all breaks til now, they were captured by someone with the same name
+ }
+ }
+
+ void visitLoop(Loop* curr) {
+ if (curr == target) {
+ types.push_back(curr->body->type);
+ } else if (curr->name == targetName) {
+ types.clear(); // ignore all breaks til now, they were captured by someone with the same name
+ }
+ }
+};
+
+static WasmType mergeTypes(std::vector<WasmType>& types) {
+ WasmType type = unreachable;
+ for (auto other : types) {
+ // once none, stop. it then indicates a poison value, that must not be consumed
+ // and ignore unreachable
+ if (type != none) {
+ if (other == none) {
+ type = none;
+ } else if (other != unreachable) {
+ if (type == unreachable) {
+ type = other;
+ } else if (type != other) {
+ type = none; // poison value, we saw multiple types; this should not be consumed
+ }
+ }
+ }
+ }
+ return type;
+}
+
+void Block::finalize(WasmType type_) {
+ type = type_;
+ if (type == none && list.size() > 0) {
+ if (list.back()->type == unreachable) {
+ if (!BreakSeeker::has(this, name)) {
+ type = unreachable; // the last element is unreachable, and this block truly cannot be exited, so it is unreachable itself
+ }
+ }
+ }
+}
+
+void Block::finalize() {
+ if (!name.is()) {
+ // nothing branches here, so this is easy
+ if (list.size() > 0) {
+ type = list.back()->type;
+ } else {
+ type = unreachable;
+ }
+ return;
+ }
+
+ TypeSeeker seeker(this, this->name);
+ type = mergeTypes(seeker.types);
+}
+
+void If::finalize(WasmType type_) {
+ type = type_;
+ if (type == none && (condition->type == unreachable || (ifTrue->type == unreachable && (!ifFalse || ifFalse->type == unreachable)))) {
+ type = unreachable;
+ }
+}
+
+void If::finalize() {
+ if (condition->type == unreachable) {
+ type = unreachable;
+ } else if (ifFalse) {
+ if (ifTrue->type == ifFalse->type) {
+ type = ifTrue->type;
+ } else if (isConcreteWasmType(ifTrue->type) && ifFalse->type == unreachable) {
+ type = ifTrue->type;
+ } else if (isConcreteWasmType(ifFalse->type) && ifTrue->type == unreachable) {
+ type = ifFalse->type;
+ } else {
+ type = none;
+ }
+ } else {
+ type = none; // if without else
+ }
+}
+
+void Loop::finalize(WasmType type_) {
+ type = type_;
+ if (type == none && body->type == unreachable) {
+ type = unreachable;
+ }
+}
+
+void Loop::finalize() {
+ type = body->type;
+}
+
+} // namespace wasm