|
29 | 29 | // across modules, we still want to legalize dynCalls so JS can call into the |
30 | 30 | // tables even to a signature that is not legal. |
31 | 31 | // |
| 32 | +// Another variation also "prunes" imports and exports that we cannot yet |
| 33 | +// legalize, like exports and imports with SIMD or multivalue. Until we write |
| 34 | +// the logic to legalize them, removing those imports/exports still allows us to |
| 35 | +// fuzz all the legal imports/exports. (Note that multivalue is supported in |
| 36 | +// exports in newer VMs - node 16+ - so that part is only needed for older VMs.) |
| 37 | +// |
32 | 38 |
|
33 | 39 | #include "asmjs/shared-constants.h" |
34 | 40 | #include "ir/element-utils.h" |
|
43 | 49 |
|
44 | 50 | namespace wasm { |
45 | 51 |
|
| 52 | +namespace { |
| 53 | + |
46 | 54 | // These are aliases for getTempRet0/setTempRet0 which emscripten defines in |
47 | 55 | // compiler-rt and exports under these names. |
48 | 56 | static Name GET_TEMP_RET_EXPORT("__get_temp_ret"); |
@@ -358,10 +366,88 @@ struct LegalizeJSInterface : public Pass { |
358 | 366 | } |
359 | 367 | }; |
360 | 368 |
|
| 369 | +struct LegalizeAndPruneJSInterface : public LegalizeJSInterface { |
| 370 | + // Legalize fully (true) and add pruning on top. |
| 371 | + LegalizeAndPruneJSInterface() : LegalizeJSInterface(true) {} |
| 372 | + |
| 373 | + void run(Module* module) override { |
| 374 | + LegalizeJSInterface::run(module); |
| 375 | + |
| 376 | + prune(module); |
| 377 | + } |
| 378 | + |
| 379 | + void prune(Module* module) { |
| 380 | + // For each function name, the exported id it is exported with. For |
| 381 | + // example, |
| 382 | + // |
| 383 | + // (func $foo (export "bar") |
| 384 | + // |
| 385 | + // Would have exportedFunctions["foo"] = "bar"; |
| 386 | + std::unordered_map<Name, Name> exportedFunctions; |
| 387 | + for (auto& exp : module->exports) { |
| 388 | + if (exp->kind == ExternalKind::Function) { |
| 389 | + exportedFunctions[exp->value] = exp->name; |
| 390 | + } |
| 391 | + } |
| 392 | + |
| 393 | + for (auto& func : module->functions) { |
| 394 | + // If the function is neither exported nor imported, no problem. |
| 395 | + auto imported = func->imported(); |
| 396 | + auto exported = exportedFunctions.count(func->name); |
| 397 | + if (!imported && !exported) { |
| 398 | + continue; |
| 399 | + } |
| 400 | + |
| 401 | + // The params are allowed to be multivalue, but not the results. Otherwise |
| 402 | + // look for SIMD. |
| 403 | + auto sig = func->type.getSignature(); |
| 404 | + auto illegal = isIllegal(sig.results); |
| 405 | + illegal = |
| 406 | + illegal || std::any_of(sig.params.begin(), |
| 407 | + sig.params.end(), |
| 408 | + [&](const Type& t) { return isIllegal(t); }); |
| 409 | + if (!illegal) { |
| 410 | + continue; |
| 411 | + } |
| 412 | + |
| 413 | + // Prune an import by implementing it in a trivial manner. |
| 414 | + if (imported) { |
| 415 | + func->module = func->base = Name(); |
| 416 | + |
| 417 | + Builder builder(*module); |
| 418 | + if (sig.results == Type::none) { |
| 419 | + func->body = builder.makeNop(); |
| 420 | + } else { |
| 421 | + func->body = |
| 422 | + builder.makeConstantExpression(Literal::makeZeros(sig.results)); |
| 423 | + } |
| 424 | + } |
| 425 | + |
| 426 | + // Prune an export by just removing it. |
| 427 | + if (exported) { |
| 428 | + module->removeExport(exportedFunctions[func->name]); |
| 429 | + } |
| 430 | + } |
| 431 | + |
| 432 | + // TODO: globals etc. |
| 433 | + } |
| 434 | + |
| 435 | + bool isIllegal(Type type) { |
| 436 | + auto features = type.getFeatures(); |
| 437 | + return features.hasSIMD() || features.hasMultivalue(); |
| 438 | + } |
| 439 | +}; |
| 440 | + |
| 441 | +} // anonymous namespace |
| 442 | + |
361 | 443 | Pass* createLegalizeJSInterfacePass() { return new LegalizeJSInterface(true); } |
362 | 444 |
|
363 | 445 | Pass* createLegalizeJSInterfaceMinimallyPass() { |
364 | 446 | return new LegalizeJSInterface(false); |
365 | 447 | } |
366 | 448 |
|
| 449 | +Pass* createLegalizeAndPruneJSInterfacePass() { |
| 450 | + return new LegalizeAndPruneJSInterface(); |
| 451 | +} |
| 452 | + |
367 | 453 | } // namespace wasm |
0 commit comments