Stack validation can be done, but in the presence of dynamic jumps it cannot be done in linear time – every possible path out of every jump must be traced, taking quadratic time. The same problem afflicts anything that involves tracing the control flow of a program, including compilers of EVM bytecode to machine code.
The EVM has no subroutine instruction. Instead, they are implemented with dynamic jumps. We have been arguing about whether and how to remove dynamic jumps and add a subroutine instruction to the EVM for ten years now.