Google's JSIR: An MLIR-Based Intermediate Representation for JavaScript Analysis

Google's JSIR: An MLIR-Based Intermediate Representation for JavaScript Analysis

lschvn5 min read

When a compiler intermediate representation (IR) makes the news, you know it matters. Google has published JSIR, a next-generation JavaScript analysis tool built on MLIR, and it's already used internally for tasks that reveal just how ambitious the project is: decompiling Hermes bytecode back to JavaScript, and powering AI-assisted deobfuscation pipelines that combine JSIR with Gemini.

Why This Matters for Tooling

An intermediate representation is the data structure that a compiler or analysis tool uses to represent code between parsing and code generation. If an AST tells you what the code looks like structurally, an IR tells you what it does. The quality of your IR determines what kind of analysis and transformation you can perform.

JavaScript tooling has long suffered from fragmented IR approaches. Babel plugins work on ASTs. ESLint rules work on ASTs. Bundlers often work on their own internal representations with limited interoperability. A common, well-designed IR could let these tools share analysis work — and that's exactly what Google is proposing with JSIR.

High-Level and Low-Level Simultaneously

The core technical challenge JSIR solves is a familiar one in compiler design: you typically have to choose between a high-level IR (preserves AST structure, can be lifted back to source) and a low-level IR (enables deep dataflow analysis like taint tracking and constant propagation). Most systems pick one.

JSIR uses MLIR regions to accurately model JavaScript's control flow structures — things like closures, try-catch-finally, async functions, and generator frames — in a way that supports both directions simultaneously. You can transform code and lift it back to source, or run taint analysis across the same representation.

This unlocks use cases that were previously impractical:

Decompilation: JSIR is used at Google to decompile Hermes bytecode all the way back to JavaScript. Hermes compiles React Native apps to a compact bytecode for faster startup; JSIR's source-liftability is what makes this decompilation possible when other tools would hit a dead end.

Deobfuscation: Google published research (CASCADE) on combining Gemini LLM with JSIR for JavaScript deobfuscation. The AI operates on JSIR's structured representation rather than raw obfuscated source, producing transformations that JSIR applies back to reconstruct clean code.

The MLIR Foundation

JSIR isn't a standalone project — it's built on MLIR, the LLVM project's flexible IR framework. This is significant for ecosystem compatibility: MLIR already has a broad set of existing dialects, transformations, and tooling. By expressing JavaScript analysis in MLIR terms, JSIR can plug into that ecosystem rather than reinventing infrastructure.

Getting Started

JSIR is available on GitHub at github.com/google/jsir. The project recommends using Docker for local experimentation:

docker build -t jsir:latest .
docker run --rm -v $(pwd):/workspace jsir:latest jsir_gen --input_file=/workspace/yourfile.js

Building from source requires clang, Bazel, and significant build time — the project notes that LLVM fetch and build takes a while. The Docker path is the practical entry point for most developers.

What This Means for the Ecosystem

Most developers won't interact with JSIR directly in the near term — it's a foundation for tooling developers to build on. But the long-term implications are significant. A shared, well-designed IR could enable:

  • Linters with deeper semantic understanding (not just pattern matching on AST nodes)
  • Bundlers with better dead code elimination using dataflow analysis
  • Refactoring tools that can safely transform code across complex control flow
  • Cross-framework analysis that works consistently regardless of which framework or build tool is used

Google has open sourced it, which means the community can build on this foundation. Whether it gains traction depends on whether tooling maintainers see enough benefit to integrate JSIR-based analysis into their pipelines — but the technical foundation is solid.

Frequently Asked Questions

Related articles

More coverage with overlapping topics and tags.

JetStream 3: The Benchmark That Actually Reflects How Modern Web Apps Run
JavaScript

JetStream 3: The Benchmark That Actually Reflects How Modern Web Apps Run

WebKit, Google, and Mozilla just released JetStream 3 — the first major overhaul of the benchmark suite since 2019. It drops microbenchmarks in favor of realistic workloads, rewrites WebAssembly scoring, and introduces Dart, Kotlin, and Rust compiled to Wasm.
Node.js 25.9: The stream/iter API Finally Lands as Experimental
JavaScript

Node.js 25.9: The stream/iter API Finally Lands as Experimental

Node.js 25.9 adds an experimental stream/iter module for async iteration over streams, a --max-heap-size CLI flag, AsyncLocalStorage with using scopes, TurboSHAKE crypto, and an upgraded npm 11.12.1. Here's what each change means for your code.
QuickBEAM: A JavaScript Runtime for the BEAM VM — JavaScript Meets Erlang's OTP
JavaScript

QuickBEAM: A JavaScript Runtime for the BEAM VM — JavaScript Meets Erlang's OTP

QuickBEAM is a JavaScript runtime that runs inside the BEAM VM — the same virtual machine powering Erlang and Elixir. It integrates JavaScript into OTP supervision trees, lets JS call Elixir functions and OTP libraries, and ships with a built-in TypeScript toolchain.

Comments

Log in Log in to join the conversation.

No comments yet. Be the first to share your thoughts.