Skip to content

Commit 7b4f978

Browse files
authored
SafeHeap: Prepare for emscripten_get_sbrk_ptr (#2331)
Currently emscripten links the wasm, then links the JS, then computes the final static allocations and in particular the location of the sbrk ptr (i.e. the location in memory of the brk location). Emscripten then imports that into the asm.js or wasm as env.DYNAMICTOP_PTR. However, this didn't work in the wasm backend where we didn't have support for importing globals from JS, so we implement sbrk in JS. I am proposing that we change this model to allow us to write sbrk in C and compile it to wasm. To do so, that C code can import an extern C function, emscripten_get_sbrk_ptr(), which basically just returns that location. The PostEmscripten pass can even apply that value at compile time, so we avoid the function call, and end up in the optimal place, see #2325 and emscripten PRs will be opened once other stuff lands. However, the SafeHeap pass must be updated to handle this, or our CI will break in the middle. This PR fixes that, basically making it check if env.DYNAMICTOP_PTR exists, or if not then looking for env.emscripten_get_sbrk_ptr, so that it can handle both.
1 parent a0c77bf commit 7b4f978

5 files changed

Lines changed: 4560 additions & 724 deletions

src/passes/SafeHeap.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
namespace wasm {
3434

3535
const Name DYNAMICTOP_PTR_IMPORT("DYNAMICTOP_PTR");
36+
const Name GET_SBRK_PTR_IMPORT("emscripten_get_sbrk_ptr");
3637
const Name SEGFAULT_IMPORT("segfault");
3738
const Name ALIGNFAULT_IMPORT("alignfault");
3839

@@ -111,19 +112,27 @@ struct SafeHeap : public Pass {
111112
addGlobals(module, module->features);
112113
}
113114

114-
Name dynamicTopPtr, segfault, alignfault;
115+
Name dynamicTopPtr, getSbrkPtr, segfault, alignfault;
115116

116117
void addImports(Module* module) {
117118
ImportInfo info(*module);
119+
// Older emscripten imports env.DYNAMICTOP_PTR.
120+
// Newer emscripten imports emscripten_get_sbrk_ptr(), which is later
121+
// optimized to have the number in the binary.
118122
if (auto* existing = info.getImportedGlobal(ENV, DYNAMICTOP_PTR_IMPORT)) {
119123
dynamicTopPtr = existing->name;
124+
} else if (auto* existing =
125+
info.getImportedFunction(ENV, GET_SBRK_PTR_IMPORT)) {
126+
getSbrkPtr = existing->name;
120127
} else {
121-
auto* import = new Global;
122-
import->name = dynamicTopPtr = DYNAMICTOP_PTR_IMPORT;
128+
auto* import = new Function;
129+
import->name = getSbrkPtr = GET_SBRK_PTR_IMPORT;
123130
import->module = ENV;
124-
import->base = DYNAMICTOP_PTR_IMPORT;
125-
import->type = i32;
126-
module->addGlobal(import);
131+
import->base = GET_SBRK_PTR_IMPORT;
132+
auto* functionType = ensureFunctionType("i", module);
133+
import->type = functionType->name;
134+
FunctionTypeUtils::fillFunction(import, functionType);
135+
module->addFunction(import);
127136
}
128137
if (auto* existing = info.getImportedFunction(ENV, SEGFAULT_IMPORT)) {
129138
segfault = existing->name;
@@ -315,6 +324,12 @@ struct SafeHeap : public Pass {
315324
makeBoundsCheck(Type type, Builder& builder, Index local, Index bytes) {
316325
auto upperOp = options.lowMemoryUnused ? LtUInt32 : EqInt32;
317326
auto upperBound = options.lowMemoryUnused ? PassOptions::LowMemoryBound : 0;
327+
Expression* sbrkPtr;
328+
if (dynamicTopPtr.is()) {
329+
sbrkPtr = builder.makeGlobalGet(dynamicTopPtr, i32);
330+
} else {
331+
sbrkPtr = builder.makeCall(getSbrkPtr, {}, i32);
332+
}
318333
return builder.makeIf(
319334
builder.makeBinary(
320335
OrInt32,
@@ -326,8 +341,7 @@ struct SafeHeap : public Pass {
326341
builder.makeBinary(AddInt32,
327342
builder.makeLocalGet(local, i32),
328343
builder.makeConst(Literal(int32_t(bytes)))),
329-
builder.makeLoad(
330-
4, false, 0, 4, builder.makeGlobalGet(dynamicTopPtr, i32), i32))),
344+
builder.makeLoad(4, false, 0, 4, sbrkPtr, i32))),
331345
builder.makeCall(segfault, {}, none));
332346
}
333347
};

0 commit comments

Comments
 (0)