Skip to content

Commit 3ee3af8

Browse files
committed
Merge branch 'main' into wasm-reduce-header
2 parents a195ebd + 63860fb commit 3ee3af8

14 files changed

+2654
-110
lines changed

CHANGELOG.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,31 @@ full changeset diff at the end of each section.
1515
Current Trunk
1616
-------------
1717

18+
v124
19+
----
20+
21+
- Add Custom Descriptors support. (Fuzzing: #7796)
22+
- Add Stack Switching support. (Fuzzing: #7834)
23+
- Add Compilation Hints + Branch Hinting support. (Fuzzing #7704)
24+
- Build mimalloc with `MI_NO_OPT_ARCH` to fix Raspberry Pi 4 on Arm64. (#7837)
1825
- `wasm-split`'s `--multi-split` mode now supports more options:
1926
`--no-placeholders`, `--import-namespace`, `--emit-module-names`,
2027
`--emit-text`, `--symbolmap`, and `--placeholdermap`. Because
2128
`--no-placeholders` is false by default and until now `--multi-split` didn't
2229
use placeholders at all, this is a breaking change. If you want to continue
2330
to do multi-split without placeholders, you need to explicitly specify
24-
`--no-placeholders`.
31+
`--no-placeholders`. (#7781, #7789, #7792)
32+
- InstrumentMemory: Allow filtering by instruction, and instrument memory.grow.
33+
(#7388)
34+
- Add support for more source map fields, "sourcesContent", "file", and
35+
"sourceRoot". (#7473)
36+
- [GC] Add a TypeRefiningGUFA pass. (#7433)
37+
- [C/JS APIs] Allow JS and C to read the start function of a module (#7424)
2538
- Add a `--string-lifting` pass that raises imported string operations and
2639
constants into stringref in Binaryen IR (which can then be fully optimized,
27-
and typically lowered back down with `--string-lowering`).
40+
and typically lowered back down with `--string-lowering`). (#7389)
41+
- Fuzzer: Improve handling of small inputs and their debugging using a new
42+
`BINARYEN_FUZZER_MAX_BYTES` env var. (#7832)
2843

2944
v123
3045
----

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.16.3)
77
# to reduce this for compatability with emsdk.
88
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum OS X deployment version")
99

10-
project(binaryen LANGUAGES C CXX VERSION 123)
10+
project(binaryen LANGUAGES C CXX VERSION 124)
1111
include(GNUInstallDirs)
1212

1313
# The C++ standard whose features are required to build Binaryen.

src/ir/struct-utils.h

Lines changed: 142 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,58 @@ using StructField = std::pair<HeapType, Index>;
2929

3030
namespace StructUtils {
3131

32+
// A value that has a single bool, and implements combine() so it can be used in
33+
// StructValues.
34+
struct CombinableBool {
35+
bool value = false;
36+
37+
CombinableBool() {}
38+
CombinableBool(bool value) : value(value) {}
39+
40+
operator bool() const { return value; }
41+
42+
bool combine(const CombinableBool& other) {
43+
if (!value && other.value) {
44+
value = true;
45+
return true;
46+
}
47+
return false;
48+
}
49+
};
50+
51+
static const Index DescriptorIndex = -1;
52+
3253
// A vector of a template type's values. One such vector will be used per struct
3354
// type, where each element in the vector represents a field. We always assume
3455
// that the vectors are pre-initialized to the right length before accessing any
3556
// data, which this class enforces using assertions, and which is implemented in
3657
// StructValuesMap.
3758
template<typename T> struct StructValues : public std::vector<T> {
3859
T& operator[](size_t index) {
60+
if (index == DescriptorIndex) {
61+
return desc;
62+
}
3963
assert(index < this->size());
4064
return std::vector<T>::operator[](index);
4165
}
4266

4367
const T& operator[](size_t index) const {
68+
if (index == DescriptorIndex) {
69+
return desc;
70+
}
4471
assert(index < this->size());
4572
return std::vector<T>::operator[](index);
4673
}
74+
75+
// Store the descriptor as another field. (This could be a std::optional to
76+
// indicate that the descriptor's existence depends on the type, but that
77+
// would add overhead & code clutter (type checks). If there is no descriptor,
78+
// this will just hang around with the default values, not harming anything
79+
// except perhaps for looking a little odd during debugging. And whenever we
80+
// combine() a non-existent descriptor, we are doing unneeded work, but the
81+
// data here is typically just a few bools, so it is simpler and likely
82+
// faster to just copy those rather than check if the type has a descriptor.)
83+
T desc;
4784
};
4885

4986
// Maps heap types to a StructValues for that heap type.
@@ -69,6 +106,7 @@ struct StructValuesMap : public std::unordered_map<HeapType, StructValues<T>> {
69106
for (Index i = 0; i < info.size(); i++) {
70107
combinedInfos[type][i].combine(info[i]);
71108
}
109+
combinedInfos[type].desc.combine(info.desc);
72110
}
73111
}
74112

@@ -80,6 +118,8 @@ struct StructValuesMap : public std::unordered_map<HeapType, StructValues<T>> {
80118
x.dump(o);
81119
o << " ";
82120
};
121+
o << " desc: ";
122+
vec.desc.dump(o);
83123
o << '\n';
84124
}
85125
}
@@ -129,14 +169,17 @@ struct FunctionStructValuesMap
129169
//
130170
// void noteCopy(HeapType type, Index index, T& info);
131171
//
132-
// * Note a read
172+
// * Note a read.
133173
//
134174
// void noteRead(HeapType type, Index index, T& info);
135175
//
136176
// We track information from struct.new and struct.set/struct.get separately,
137177
// because in struct.new we know more about the type - we know the actual exact
138178
// type being written to, and not just that it is of a subtype of the
139179
// instruction's type, which helps later.
180+
//
181+
// Descriptors are treated as fields in that we call the above functions on
182+
// them. We pass DescriptorIndex for their index as a fake value.
140183
template<typename T, typename SubType>
141184
struct StructScanner
142185
: public WalkerPass<PostWalker<StructScanner<T, SubType>>> {
@@ -168,6 +211,10 @@ struct StructScanner
168211
noteExpressionOrCopy(curr->operands[i], heapType, i, infos[i]);
169212
}
170213
}
214+
215+
if (curr->desc) {
216+
self().noteExpression(curr->desc, heapType, DescriptorIndex, infos.desc);
217+
}
171218
}
172219

173220
void visitStructSet(StructSet* curr) {
@@ -236,6 +283,42 @@ struct StructScanner
236283
noteExpressionOrCopy(curr->replacement, heapType, index, info);
237284
}
238285

286+
void visitRefCast(RefCast* curr) {
287+
if (curr->desc) {
288+
// We may try to read a descriptor from anything arriving in |curr->ref|,
289+
// but the only things that matter are the things we cast to: other types
290+
// can lack a descriptor, and are skipped anyhow. So the only effective
291+
// read is of the cast type.
292+
handleDescRead(curr->getCastType());
293+
}
294+
}
295+
296+
void visitBrOn(BrOn* curr) {
297+
if (curr->desc &&
298+
(curr->op == BrOnCastDesc || curr->op == BrOnCastDescFail)) {
299+
handleDescRead(curr->getCastType());
300+
}
301+
}
302+
303+
void visitRefGetDesc(RefGetDesc* curr) {
304+
// Unlike a cast, anything in |curr->ref| may be read from.
305+
handleDescRead(curr->ref->type);
306+
}
307+
308+
void handleDescRead(Type type) {
309+
if (type == Type::unreachable) {
310+
return;
311+
}
312+
auto heapType = type.getHeapType();
313+
if (heapType.isStruct()) {
314+
// Any subtype of the reference here may be read from.
315+
self().noteRead(heapType,
316+
DescriptorIndex,
317+
functionSetGetInfos[this->getFunction()][heapType].desc);
318+
return;
319+
}
320+
}
321+
239322
void
240323
noteExpressionOrCopy(Expression* expr, HeapType type, Index index, T& info) {
241324
// Look at the value falling through, if it has the exact same type
@@ -268,8 +351,8 @@ struct StructScanner
268351
FunctionStructValuesMap<T>& functionSetGetInfos;
269352
};
270353

271-
// Helper class to propagate information about fields to sub- and/or super-
272-
// classes in the type hierarchy. While propagating it calls a method
354+
// Helper class to propagate information to sub- and/or super- classes in the
355+
// type hierarchy. While propagating it calls a method
273356
//
274357
// to.combine(from)
275358
//
@@ -286,18 +369,32 @@ template<typename T> class TypeHierarchyPropagator {
286369

287370
SubTypes subTypes;
288371

372+
// Propagate given a StructValuesMap, which means we need to take into
373+
// account fields.
289374
void propagateToSuperTypes(StructValuesMap<T>& infos) {
290375
propagate(infos, false, true);
291376
}
292-
293377
void propagateToSubTypes(StructValuesMap<T>& infos) {
294378
propagate(infos, true, false);
295379
}
296-
297380
void propagateToSuperAndSubTypes(StructValuesMap<T>& infos) {
298381
propagate(infos, true, true);
299382
}
300383

384+
// Propagate on a simpler map of structs and infos (that is, not using
385+
// separate values for the fields, as StructValuesMap does). This is useful
386+
// when not tracking individual fields, but something more general about
387+
// types.
388+
using StructMap = std::unordered_map<HeapType, T>;
389+
390+
void propagateToSuperTypes(StructMap& infos) {
391+
propagate(infos, false, true);
392+
}
393+
void propagateToSubTypes(StructMap& infos) { propagate(infos, true, false); }
394+
void propagateToSuperAndSubTypes(StructMap& infos) {
395+
propagate(infos, true, true);
396+
}
397+
301398
private:
302399
void propagate(StructValuesMap<T>& combinedInfos,
303400
bool toSubTypes,
@@ -320,6 +417,11 @@ template<typename T> class TypeHierarchyPropagator {
320417
work.push(*superType);
321418
}
322419
}
420+
// Propagate the descriptor to the super, if the super has one.
421+
if (superType->getDescriptorType() &&
422+
superInfos.desc.combine(infos.desc)) {
423+
work.push(*superType);
424+
}
323425
}
324426
}
325427

@@ -333,6 +435,41 @@ template<typename T> class TypeHierarchyPropagator {
333435
work.push(subType);
334436
}
335437
}
438+
// Propagate the descriptor.
439+
if (subInfos.desc.combine(infos.desc)) {
440+
work.push(subType);
441+
}
442+
}
443+
}
444+
}
445+
}
446+
447+
void propagate(StructMap& combinedInfos, bool toSubTypes, bool toSuperTypes) {
448+
UniqueDeferredQueue<HeapType> work;
449+
for (auto& [type, _] : combinedInfos) {
450+
work.push(type);
451+
}
452+
while (!work.empty()) {
453+
auto type = work.pop();
454+
auto& info = combinedInfos[type];
455+
456+
if (toSuperTypes) {
457+
// Propagate to the supertype.
458+
if (auto superType = type.getDeclaredSuperType()) {
459+
auto& superInfo = combinedInfos[*superType];
460+
if (superInfo.combine(info)) {
461+
work.push(*superType);
462+
}
463+
}
464+
}
465+
466+
if (toSubTypes) {
467+
// Propagate shared fields to the subtypes.
468+
for (auto subType : subTypes.getImmediateSubTypes(type)) {
469+
auto& subInfo = combinedInfos[subType];
470+
if (subInfo.combine(info)) {
471+
work.push(subType);
472+
}
336473
}
337474
}
338475
}

0 commit comments

Comments
 (0)