summaryrefslogtreecommitdiff
path: root/src/abi
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2017-12-30 08:38:31 -0800
committerGitHub <noreply@github.com>2017-12-30 08:38:31 -0800
commitb5ee16f318019f89d8a897437fb906d470cfa8d9 (patch)
tree8be0a0cb6585ced8279e1d83f719ef0684a870e2 /src/abi
parent10bf008c73948d4592e567cdbce330dff724b1c2 (diff)
downloadbinaryen-b5ee16f318019f89d8a897437fb906d470cfa8d9.tar.gz
binaryen-b5ee16f318019f89d8a897437fb906d470cfa8d9.tar.bz2
binaryen-b5ee16f318019f89d8a897437fb906d470cfa8d9.zip
SpillPointers pass (#1339)
This is an experiment to help with Boehm-style GC. It will spill things that could be pointers to the C stack, so that they can be seen by conservative garbage collection. The spills add code size and runtime overhead, but actually less than I thought: 10% slower (smaller than the difference between VMs), 15% gzip size larger. We can do even better with more optimizations for this, like a dead store elimination pass. This PR does the following: * Add the new pass. * Create an abi/ dir, with info about the pointer size and stack manipulation utilities. * Separates out the liveness analysis from CoalesceLocals, so that other passes can use it (like SpillPointers). * Refactor out the SortedVector class from the liveness analysis to a separate file (just seems nicer that way).
Diffstat (limited to 'src/abi')
-rw-r--r--src/abi/abi.h33
-rw-r--r--src/abi/stack.h124
2 files changed, 157 insertions, 0 deletions
diff --git a/src/abi/abi.h b/src/abi/abi.h
new file mode 100644
index 000000000..ff1864efa
--- /dev/null
+++ b/src/abi/abi.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 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_abi_abi_h
+#define wasm_abi_abi_h
+
+#include "wasm.h"
+
+namespace wasm {
+
+namespace ABI {
+
+// The pointer type. Will need to update this for wasm64
+const static WasmType PointerType = WasmType::i32;
+
+} // namespace ABI
+
+} // namespace wasm
+
+#endif // wasm_abi_abi_h
diff --git a/src/abi/stack.h b/src/abi/stack.h
new file mode 100644
index 000000000..e43be07ec
--- /dev/null
+++ b/src/abi/stack.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017 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_abi_stack_h
+#define wasm_abi_stack_h
+
+#include "wasm.h"
+#include "wasm-builder.h"
+#include "shared-constants.h"
+#include "asmjs/shared-constants.h"
+#include "ir/find_all.h"
+#include "ir/global-utils.h"
+#include "abi.h"
+
+namespace wasm {
+
+namespace ABI {
+
+enum {
+ StackAlign = 16
+};
+
+inline Index stackAlign(Index size) {
+ return (size + StackAlign - 1) & -StackAlign;
+}
+
+// Allocate some space on the stack, and assign it to a local.
+// The local will have the same constant value in all the function, so you can just
+// get_local it anywhere there.
+inline void getStackSpace(Index local, Function* func, Index size, Module& wasm) {
+ auto* stackPointer = GlobalUtils::getGlobalInitializedToImport(wasm, ENV, "STACKTOP");
+ if (!stackPointer) {
+ Fatal() << "getStackSpace: failed to find the stack pointer";
+ }
+ // align the size
+ size = stackAlign(size);
+ // TODO: find existing stack usage, and add on top of that - carefully
+ Builder builder(wasm);
+ auto* block = builder.makeBlock();
+ block->list.push_back(
+ builder.makeSetLocal(
+ local,
+ builder.makeGetGlobal(stackPointer->name, PointerType)
+ )
+ );
+ // TODO: add stack max check
+ Expression* added;
+ if (PointerType == i32) {
+ added = builder.makeBinary(
+ AddInt32,
+ builder.makeGetLocal(local, PointerType),
+ builder.makeConst(Literal(int32_t(size)))
+ );
+ } else {
+ WASM_UNREACHABLE();
+ }
+ block->list.push_back(
+ builder.makeSetGlobal(
+ stackPointer->name,
+ added
+ )
+ );
+ auto makeStackRestore = [&]() {
+ return builder.makeSetGlobal(
+ stackPointer->name,
+ builder.makeGetLocal(local, PointerType)
+ );
+ };
+ // add stack restores to the returns
+ FindAllPointers<Return> finder(func->body);
+ for (auto** ptr : finder.list) {
+ auto* ret = (*ptr)->cast<Return>();
+ if (ret->value && ret->value->type != unreachable) {
+ // handle the returned value
+ auto* block = builder.makeBlock();
+ auto temp = builder.addVar(func, ret->value->type);
+ block->list.push_back(builder.makeSetLocal(temp, ret->value));
+ block->list.push_back(makeStackRestore());
+ block->list.push_back(builder.makeReturn(
+ builder.makeGetLocal(temp, ret->value->type)
+ ));
+ block->finalize();
+ *ptr = block;
+ } else {
+ // restore, then return
+ *ptr = builder.makeSequence(makeStackRestore(), ret);
+ }
+ }
+ // add stack restores to the body
+ if (func->body->type == none) {
+ block->list.push_back(func->body);
+ block->list.push_back(makeStackRestore());
+ } else if (func->body->type == unreachable) {
+ block->list.push_back(func->body);
+ // no need to restore the old stack value, we're gone anyhow
+ } else {
+ // save the return value
+ auto temp = builder.addVar(func, func->result);
+ block->list.push_back(builder.makeSetLocal(temp, func->body));
+ block->list.push_back(makeStackRestore());
+ block->list.push_back(builder.makeGetLocal(temp, func->result));
+ }
+ block->finalize();
+ func->body = block;
+}
+
+} // namespace ABI
+
+} // namespace wasm
+
+#endif // wasm_abi_stack_h