diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6aee92 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.clss +exec_code \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..01d9224 --- /dev/null +++ b/README.md @@ -0,0 +1,114 @@ +# KolibriOS J2ME JVM Emulator (C) + +A small Java class-file interpreter aimed at `javax.microedition` (CLDC/MIDP style apps), with SDL2 rendering. + +## What this project does + +- Loads and parses Java `.class` files. +- Executes a subset of JVM bytecode. +- Boots MIDlet apps via `startApp()` when no Java `main` exists. +- Supports running a `.jar` by extracting it, reading `META-INF/MANIFEST.MF`, and resolving an entry class. +- Renders basic MIDP drawing operations through SDL2. +- Uses SDL_ttf for `Graphics.drawString(...)` text rendering. + +## Current status + +This is an emulator prototype and not a full JVM. + +Working pieces include: + +- Core classfile parsing and method execution. +- Basic object/field handling. +- Some branching and invocation opcodes. +- MIDP-oriented native stubs in `helpers.c`. +- Canvas paint callback path (`Display.setCurrent(...)` -> `Canvas.paint(Graphics)`). + +Known limitations: + +- Only a subset of JVM instructions and Java library behavior is implemented. +- Many platform classes are stubbed or partially handled. +- App compatibility is limited and depends on which opcodes/APIs are used. + +## Prerequisites (Ubuntu 24.04 / WSL) + +Install build/runtime dependencies: + +```bash +sudo apt update +sudo apt install -y build-essential make openjdk-17-jdk unzip libsdl2-dev libsdl2-ttf-dev +``` + +If you are using WSL, make sure GUI/WSLg works for SDL windows. + +## Build + +```bash +make +``` + +This builds: + +- `test_parser` +- `exec_code` + +## Run examples + +### 1) Run included Hello MIDlet (`.class`) + +```bash +make run_exec +``` + +Equivalent direct command: + +```bash +./exec_code Hello.class +``` + +### 2) Run a JAR + +```bash +./exec_code path/to/app.jar +``` + +Notes: + +- JAR mode extracts to a temp directory and reads manifest entries (`MIDlet-1` or `Main-Class`). +- If manifest lookup fails, it tries the first `.class` found. + +## Parser-only mode + +```bash +make run_parser +``` + +## Project layout + +- `classfile.c`, `classfile.h`: class file loader and structures. +- `exec_code.c`: bytecode execution engine and program entry point. +- `helpers.c`, `helpers.h`: heap/object helpers, SDL/MIDP native bridges, text drawing. +- `Hello.java`: sample MIDlet. +- `Makefile`: build and run targets. + +## Typical troubleshooting + +1. Build fails with SDL_ttf errors: + +- Install `libsdl2-ttf-dev`. + +2. JAR launch fails to extract: + +- Install `unzip`. + +3. No emulator window appears in WSL: + +- Verify WSLg/X display support. +- Try running from Ubuntu terminal directly. + +4. Emulator stops on unknown opcode: + +- The needed JVM instruction is not implemented yet. + +## License and third-party files + +See the `lib/` folder for included third-party license files. diff --git a/exec_code.c b/exec_code.c index a4c226e..5c983a6 100644 --- a/exec_code.c +++ b/exec_code.c @@ -485,6 +485,15 @@ int execute(ClassFile *cf, Method *m, intptr_t *args, int argc) { if (loaded_cf) classfile_free(loaded_cf); break; } + + /* Guard against accidental self-resolution causing infinite recursion. */ + if (target_cf == cf && target == m) { + fprintf(stderr, "recursive invokespecial guard: %s.%s%s\n", class_name, name, desc); + f.sp -= nargs; + if (loaded_cf) classfile_free(loaded_cf); + break; + } + intptr_t sargs[32]; for (int i = nargs - 1; i >= 0; i--) sargs[i] = f.stack[--f.sp]; execute(target_cf, target, sargs, nargs);