@@ -117,6 +117,8 @@ class StringConstantTracker {
117
117
return escape (str);
118
118
}
119
119
120
+ std::vector<Address> segmentOffsets; // segment index => address offset
121
+
120
122
private:
121
123
void calcSegmentOffsets () {
122
124
std::unordered_map<Index, Address> passiveOffsets;
@@ -185,7 +187,6 @@ class StringConstantTracker {
185
187
}
186
188
187
189
Module& wasm;
188
- std::vector<Address> segmentOffsets; // segment index => address offset
189
190
};
190
191
191
192
enum class Proxying {
@@ -380,6 +381,7 @@ struct EmJsWalker : public PostWalker<EmJsWalker> {
380
381
std::vector<Export> toRemove;
381
382
382
383
std::map<std::string, std::string> codeByName;
384
+ std::map<Address, size_t > codeAddresses; // map from address to string len
383
385
384
386
EmJsWalker (Module& _wasm) : wasm(_wasm), stringTracker(_wasm) {}
385
387
@@ -404,7 +406,32 @@ struct EmJsWalker : public PostWalker<EmJsWalker> {
404
406
int64_t address = addrConst->value .getInteger ();
405
407
auto code = stringTracker.codeForConstAddr (address);
406
408
codeByName[funcName] = code;
409
+ codeAddresses[address] = code.size () + 1 ;
410
+ }
411
+ };
412
+
413
+ struct SegmentRemover : WalkerPass<PostWalker<SegmentRemover>> {
414
+ SegmentRemover (Index segment) : segment(segment) {}
415
+
416
+ bool isFunctionParallel () override { return true ; }
417
+
418
+ Pass* create () override { return new SegmentRemover (segment); }
419
+
420
+ void visitMemoryInit (MemoryInit* curr) {
421
+ if (segment == curr->segment ) {
422
+ Builder builder (*getModule ());
423
+ replaceCurrent (builder.makeNop ());
424
+ }
407
425
}
426
+
427
+ void visitDataDrop (DataDrop* curr) {
428
+ if (segment == curr->segment ) {
429
+ Builder builder (*getModule ());
430
+ replaceCurrent (builder.makeNop ());
431
+ }
432
+ }
433
+
434
+ Index segment;
408
435
};
409
436
410
437
EmJsWalker fixEmJsFuncsAndReturnWalker (Module& wasm) {
@@ -415,6 +442,32 @@ EmJsWalker fixEmJsFuncsAndReturnWalker(Module& wasm) {
415
442
wasm.removeExport (exp .name );
416
443
wasm.removeFunction (exp .value );
417
444
}
445
+
446
+ // With newer versions of emscripten/llvm we pack all EM_JS strings into
447
+ // single segment.
448
+ // We can detect this by checking for segments that contain on JS strings.
449
+ // When we find such segements we remove them from the final binary.
450
+ for (Index i = 0 ; i < wasm.memory .segments .size (); i++) {
451
+ Address start = walker.stringTracker .segmentOffsets [0 ];
452
+ Address cur = start;
453
+
454
+ while (cur < start + wasm.memory .segments [i].data .size ()) {
455
+ if (walker.codeAddresses .count (cur) == 0 ) {
456
+ break ;
457
+ }
458
+ cur.addr += walker.codeAddresses [cur];
459
+ }
460
+
461
+ if (cur == start + wasm.memory .segments [i].data .size ()) {
462
+ // Enture segment is containes JS strings. Remove it.
463
+ PassRunner runner (&wasm);
464
+ SegmentRemover (i).run (&runner, &wasm);
465
+ // Resize the segment to zero. In theory we should completely remove it
466
+ // but that would mean re-numbering the segments that follow which would
467
+ // mean renumbering.
468
+ wasm.memory .segments [i].data .resize (0 );
469
+ }
470
+ }
418
471
return walker;
419
472
}
420
473
0 commit comments