Julia is designed along these lines - its JIT compiler is really just does AOT compilation at runtime. JavaScript JITs tend to work along the lines of:
1. Interpret (and gather profiling data including type information)
2. JIT compile hot code, making assumptions based on profiling data
3. Deoptimize (fall back to the interpreter) if an assumption is broken
Julia does none of this - it can only work with types that are explicitly stated or that can be inferred statically. For extremely dynamic source code, Julia's compiler must emit slow, highly generic machine code.This is why Julia code tends to contain many more explicit types than code in other dynamic languages. Compared to other JIT-compiled dynamic languages, Julia trades-off some dynamism for compiler simplicity.