forked from WebAssembly/binaryen
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstack.h
More file actions
139 lines (129 loc) · 4.74 KB
/
Copy pathstack.h
File metadata and controls
139 lines (129 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
* 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 "abi.h"
#include "asmjs/shared-constants.h"
#include "ir/find_all.h"
#include "ir/global-utils.h"
#include "shared-constants.h"
#include "wasm-builder.h"
#include "wasm.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 local.get it anywhere there.
inline void
getStackSpace(Index local, Function* func, Index size, Module& wasm) {
// In fastcomp. STACKTOP is the name of the stack pointer.
auto* stackPointer =
GlobalUtils::getGlobalInitializedToImport(wasm, ENV, "STACKTOP");
if (!stackPointer) {
// If we didn't recognize it by name, look for the emscripten stackSave
// function, which reads the stack pointer
if (auto* exp = wasm.getExportOrNull("stackSave")) {
if (exp->kind == ExternalKind::Function) {
auto* func = wasm.getFunction(exp->value);
auto* body = func->body;
if (auto* block = body->dynCast<Block>()) {
if (block->list.size() == 1) {
body = block->list[0];
}
}
if (auto* ret = body->dynCast<Return>()) {
if (ret->value) {
body = ret->value;
}
}
if (auto* get = body->dynCast<GlobalGet>()) {
stackPointer = wasm.getGlobal(get->name);
}
}
}
}
// In general we may not be able to find it, for example if the stackSave
// method was metadce'd out. In that case, building without metadce (-O2
// instead of -O3 in emscripten) may help.
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.makeLocalSet(
local, builder.makeGlobalGet(stackPointer->name, PointerType)));
// TODO: add stack max check
Expression* added;
if (PointerType == i32) {
// XXX the wasm backend's stack goes down, not up! Should we use
// stackAlloc/stackSave/stackRestore?
added = builder.makeBinary(AddInt32,
builder.makeLocalGet(local, PointerType),
builder.makeConst(Literal(int32_t(size))));
} else {
WASM_UNREACHABLE();
}
block->list.push_back(builder.makeGlobalSet(stackPointer->name, added));
auto makeStackRestore = [&]() {
return builder.makeGlobalSet(stackPointer->name,
builder.makeLocalGet(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.makeLocalSet(temp, ret->value));
block->list.push_back(makeStackRestore());
block->list.push_back(
builder.makeReturn(builder.makeLocalGet(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.makeLocalSet(temp, func->body));
block->list.push_back(makeStackRestore());
block->list.push_back(builder.makeLocalGet(temp, func->result));
}
block->finalize();
func->body = block;
}
} // namespace ABI
} // namespace wasm
#endif // wasm_abi_stack_h