We're in this situation: performing dead code analysis on wasm isn't too hard, but it requires a representation of all wasm instructions: we'd need to be able to parse the "runtime" wasm bits, i.e., what's built using llvm from C code. When building upon that wasm module, we process the function bodies uninterpreted -- they are all just `[]byte` to us. This restriction lets us get by without implementing all the wasm instructions -- we only write what we use, and read a bare minimum to work as outlined above. To still be able to remove dead code, this change employs a trick: at build time, when the aforementioned runtime wasm module is compiled, we're calling wasm-opt on it to extract its call graph. We'll use that, together with the functions actually planned in our wasm compiler (using the subset of instructions that we understand), to remove all unused functions from the name section, and replace their function bodies with `unreachable`. We cannot really remove them, since that would require reindexing all functions; and we cannot do that without replacing the function indices at their call sites in the "runtime" wasm module. Another restriction to the impact of this approach is call_indirect: We need to keep every function that's referenced in the table -- we don't know which function might be calling them indirectly. In a follow-up, we could record that information and use it to further reduce the code size: we know that if none of the regex-related builtins are used, we could also stub out the re2-related functions. Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
OPA-WASM
This directory contains a library that implements various low-level operations for policies compiled into WebAssembly (WASM). Specifically, the library implements:
- JSON parsing
- JSON AST (e.g., comparison, iteration, lookup, etc.)
- String operations
- Memory allocation
This library does not make any backwards compatibility guarantees.
Development
You should have Docker installed to build and test changes to the library. We
commit the output of the build (opa.wasm) into the repository so it's
important for the build output to be reproducible.
You can build the library by running make build. This will produce WASM
executables under the _obj directory.
You can test the library by running make test. By default the test runner
does not print messages when tests pass. If you run make test VERBOSE=1 it
will log all of the tests that were run.
You can run make hack to start a shell inside the builder image. This is
useful if you need to interact with low-level WASM tooling like
wasm-objdump, wasm2wat, etc. or LLVM itself.
You must manually push the builder image if you make changes to it (run make builder to produce a new Docker image).
Debug Builds
Set the DEBUG environment variable to 1 to enable generating binaries with
debug symbols and a less aggressive optimization level. Eg: DEBUG=1 make build.
Vendoring
If you make changes to the library, run the make generate in the parent
directory and commit the results back to the repository. The generate
target will:
- Build the OPA-WASM library
- Copy the library into the internal/compiler/wasm/opa directory.
- Run the tool to generate the internal/compiler/wasm/opa/opa.go file.