Skip to content

Commit 7abbee0

Browse files
committed
fix
2 parents 1155b7f + 11d3aef commit 7abbee0

16 files changed

Lines changed: 1127 additions & 37 deletions

src/binaryen-c.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5754,6 +5754,14 @@ void BinaryenSetFlexibleInlineMaxSize(BinaryenIndex size) {
57545754
globalPassOptions.inlining.flexibleInlineMaxSize = size;
57555755
}
57565756

5757+
BinaryenIndex BinaryenGetMaxCombinedBinarySize(void) {
5758+
return globalPassOptions.inlining.maxCombinedBinarySize;
5759+
}
5760+
5761+
void BinaryenSetMaxCombinedBinarySize(BinaryenIndex size) {
5762+
globalPassOptions.inlining.maxCombinedBinarySize = size;
5763+
}
5764+
57575765
BinaryenIndex BinaryenGetOneCallerInlineMaxSize(void) {
57585766
return globalPassOptions.inlining.oneCallerInlineMaxSize;
57595767
}

src/binaryen-c.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3148,6 +3148,14 @@ BINARYEN_API BinaryenIndex BinaryenGetFlexibleInlineMaxSize(void);
31483148
// Applies to all modules, globally.
31493149
BINARYEN_API void BinaryenSetFlexibleInlineMaxSize(BinaryenIndex size);
31503150

3151+
// Gets the limit for the combined size of the code after inlining.
3152+
// Applies to all modules, globally.
3153+
BINARYEN_API BinaryenIndex BinaryenGetMaxCombinedBinarySize(void);
3154+
3155+
// Sets the limit for the combined size of the code after inlining.
3156+
// Applies to all modules, globally.
3157+
BINARYEN_API void BinaryenSetMaxCombinedBinarySize(BinaryenIndex size);
3158+
31513159
// Gets the function size which we inline when there is only one caller.
31523160
// Applies to all modules, globally.
31533161
BINARYEN_API BinaryenIndex BinaryenGetOneCallerInlineMaxSize(void);

src/pass.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ struct InliningOptions {
8989
// This is checked after alwaysInlineMaxSize and oneCallerInlineMaxSize, but
9090
// the order normally won't matter.
9191
Index flexibleInlineMaxSize = 20;
92+
// The limit for the combined size of the code after inlining.
93+
// We have an absolute limit in order to avoid extremely-large sizes after
94+
// inlining, as they may hit limits in VMs and/or slow down startup
95+
// (measurements there indicate something like ~1 second to optimize a 100K
96+
// function). See e.g.
97+
// https://github.com/WebAssembly/binaryen/pull/3730#issuecomment-867939138
98+
// https://github.com/emscripten-core/emscripten/issues/13899#issuecomment-825073344
99+
// The limit is arbitrary, but based on the links above. It is a very high
100+
// value that should appear very rarely in practice (for example, it does
101+
// not occur on the Emscripten benchmark suite of real-world codebases).
102+
Index maxCombinedBinarySize = 400 * 1024;
92103
// Loops usually mean the function does heavy work, so the call overhead
93104
// is not significant and we do not inline such functions by default.
94105
bool allowFunctionsWithLoops = false;

src/passes/Inlining.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,21 +1501,13 @@ struct Inlining : public Pass {
15011501
}
15021502

15031503
// Checks if the combined size of the code after inlining is under the
1504-
// absolute size limit. We have an absolute limit in order to avoid
1505-
// extremely-large sizes after inlining, as they may hit limits in VMs and/or
1506-
// slow down startup (measurements there indicate something like ~1 second to
1507-
// optimize a 100K function). See e.g.
1508-
// https://github.com/WebAssembly/binaryen/pull/3730#issuecomment-867939138
1509-
// https://github.com/emscripten-core/emscripten/issues/13899#issuecomment-825073344
1504+
// absolute size limit.
15101505
bool isUnderSizeLimit(Name target, Name source) {
15111506
// Estimate the combined binary size from the number of instructions.
15121507
auto combinedSize = infos[target].size + infos[source].size;
15131508
auto estimatedBinarySize = Measurer::BytesPerExpr * combinedSize;
1514-
// The limit is arbitrary, but based on the links above. It is a very high
1515-
// value that should appear very rarely in practice (for example, it does
1516-
// not occur on the Emscripten benchmark suite of real-world codebases).
1517-
const Index MaxCombinedBinarySize = 400 * 1024;
1518-
return estimatedBinarySize < MaxCombinedBinarySize;
1509+
auto& options = getPassRunner()->options;
1510+
return estimatedBinarySize < options.inlining.maxCombinedBinarySize;
15191511
}
15201512
};
15211513

src/passes/RemoveUnusedModuleElements.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ struct Noter : public PostWalker<Noter, UnifiedExpressionVisitor<Noter>> {
190190
auto type = curr->ref->type.getHeapType();
191191
noteStructField(StructField{type, curr->index});
192192
}
193+
194+
void visitContNew(ContNew* curr) {
195+
// The function reference that is passed in here will be called, just as if
196+
// we were a call_ref, except at a potentially later time.
197+
if (!curr->func->type.isRef()) {
198+
return;
199+
}
200+
201+
noteCallRef(curr->func->type.getHeapType());
202+
}
193203
};
194204

195205
// Analyze a module to find what things are referenced and what things are used.

src/passes/TypeMerging.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,30 @@ struct ShapeHash {
248248
size_t operator()(const HeapType& type) const { return shapeHash(type); }
249249
};
250250

251+
// The supertypes of each type in a descriptor chain. Hash and equality-compare
252+
// them using real identity to identify siblings chains that share the same
253+
// supertypes.
254+
using ChainSupers = std::vector<std::optional<HeapType>>;
255+
256+
struct ChainSupersEq {
257+
bool operator()(const ChainSupers& a, const ChainSupers& b) const {
258+
return a == b;
259+
}
260+
};
261+
262+
struct ChainSupersHash {
263+
size_t operator()(const ChainSupers& supers) const {
264+
auto digest = wasm::hash(supers.size());
265+
for (auto& super : supers) {
266+
wasm::rehash(digest, !!super);
267+
if (super) {
268+
wasm::rehash(digest, *super);
269+
}
270+
}
271+
return digest;
272+
}
273+
};
274+
251275
void TypeMerging::run(Module* module_) {
252276
module = module_;
253277

@@ -339,8 +363,10 @@ bool TypeMerging::merge(MergeKind kind) {
339363
// that siblings that refine the supertype in the same way can be assigned to
340364
// the same partition and potentially merged.
341365
std::unordered_map<
342-
std::optional<HeapType>,
343-
std::unordered_map<HeapType, Partitions::iterator, ShapeHash, ShapeEq>>
366+
std::vector<std::optional<HeapType>>,
367+
std::unordered_map<HeapType, Partitions::iterator, ShapeHash, ShapeEq>,
368+
ChainSupersHash,
369+
ChainSupersEq>
344370
shapePartitions;
345371

346372
// Ensure the type has a partition and return a reference to it. Since we
@@ -358,12 +384,16 @@ bool TypeMerging::merge(MergeKind kind) {
358384
// Similar to the above, but look up or create a partition associated with the
359385
// type's supertype and top-level shape rather than its identity.
360386
auto ensureShapePartition = [&](HeapType type) -> Partitions::iterator {
361-
auto super = type.getDeclaredSuperType();
362-
if (super) {
363-
super = getMerged(*super);
387+
ChainSupers supers;
388+
for (auto t : type.getDescriptorChain()) {
389+
auto super = t.getDeclaredSuperType();
390+
if (super) {
391+
super = getMerged(*super);
392+
}
393+
supers.push_back(super);
364394
}
365395
auto [it, inserted] =
366-
shapePartitions[super].insert({type, partitions.end()});
396+
shapePartitions[supers].insert({type, partitions.end()});
367397
if (inserted) {
368398
it->second = partitions.insert(partitions.end(), Partition{});
369399
}

src/tools/optimization-options.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,17 @@ struct OptimizationOptions : public ToolOptions {
246246
passOptions.inlining.oneCallerInlineMaxSize =
247247
static_cast<Index>(atoi(argument.c_str()));
248248
})
249+
.add("--inline-max-combined-binary-size",
250+
"-imcbs",
251+
"Max size of combined functions after inlining. "
252+
"Default: " +
253+
std::to_string(InliningOptions().maxCombinedBinarySize),
254+
OptimizationOptionsCategory,
255+
Options::Arguments::One,
256+
[this](Options* o, const std::string& argument) {
257+
passOptions.inlining.maxCombinedBinarySize =
258+
static_cast<Index>(atoi(argument.c_str()));
259+
})
249260
.add("--inline-functions-with-loops",
250261
"-ifwl",
251262
"Allow inlining functions with loops",

src/wasm-interpreter.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4824,7 +4824,11 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
48244824
return funcFlow;
48254825
}
48264826
// Create a new continuation for the target function.
4827-
Name funcName = funcFlow.getSingleValue().getFunc();
4827+
auto funcValue = funcFlow.getSingleValue();
4828+
if (funcValue.isNull()) {
4829+
trap("null ref");
4830+
}
4831+
auto funcName = funcValue.getFunc();
48284832
auto* func = self()->getModule()->getFunction(funcName);
48294833
return Literal(std::make_shared<ContData>(
48304834
self()->makeFuncData(func->name, func->type), curr->type.getHeapType()));

test/lit/help/wasm-metadce.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,9 @@
634634
;; CHECK-NEXT: caller (default -1, which means
635635
;; CHECK-NEXT: all such functions are inlined)
636636
;; CHECK-NEXT:
637+
;; CHECK-NEXT: --inline-max-combined-binary-size,-imcbs Max size of combined functions
638+
;; CHECK-NEXT: after inlining. Default: 409600
639+
;; CHECK-NEXT:
637640
;; CHECK-NEXT: --inline-functions-with-loops,-ifwl Allow inlining functions with
638641
;; CHECK-NEXT: loops
639642
;; CHECK-NEXT:

test/lit/help/wasm-opt.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,9 @@
658658
;; CHECK-NEXT: caller (default -1, which means
659659
;; CHECK-NEXT: all such functions are inlined)
660660
;; CHECK-NEXT:
661+
;; CHECK-NEXT: --inline-max-combined-binary-size,-imcbs Max size of combined functions
662+
;; CHECK-NEXT: after inlining. Default: 409600
663+
;; CHECK-NEXT:
661664
;; CHECK-NEXT: --inline-functions-with-loops,-ifwl Allow inlining functions with
662665
;; CHECK-NEXT: loops
663666
;; CHECK-NEXT:

0 commit comments

Comments
 (0)