Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ Example format at the end of a design doc:

| Feature | Status |
|---------|--------|
| `weaken` / `isweak` | Implemented on the `feature/destroy-weaken` branch. Uses cooperative reference counting on top of JVM GC. See `dev/architecture/weaken-destroy.md` for details. |
| `DESTROY` | Implemented on the `feature/destroy-weaken` branch. Fires deterministically for tracked objects (blessed into a class with DESTROY). See `dev/architecture/weaken-destroy.md`. |
| `weaken` / `isweak` | Implemented. Uses cooperative reference counting on top of JVM GC. See `dev/architecture/weaken-destroy.md` for details. |
| `DESTROY` | Implemented. Fires deterministically for tracked objects (blessed into a class with DESTROY). See `dev/architecture/weaken-destroy.md`. |
| `Scalar::Util::readonly` | Works for compile-time constants (`RuntimeScalarReadOnly` instances). Does not yet detect variables made readonly at runtime via `Internals::SvREADONLY` (those copy type/value into a plain `RuntimeScalar` without replacing the object). |

### Unimplemented Features
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -196,5 +196,5 @@ sbom-clean:
check-links:
@command -v lychee >/dev/null 2>&1 || { echo "Error: lychee not found. Install with: brew install lychee"; exit 1; }
@echo "Checking documentation links..."
lychee --offline *.md docs/ dev/design/
lychee --offline *.md docs/ dev/design/ dev/architecture/

15 changes: 12 additions & 3 deletions dev/architecture/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,26 @@ PerlOnJava is a Perl 5 implementation that compiles Perl source code to JVM byte
- Bytecode interpreter: Interprets a subset of operations for eval STRING

3. **Runtime** (`org.perlonjava.runtime`)
- Runtime types: RuntimeScalar, RuntimeArray, RuntimeHash, RuntimeCode
- Runtime types: RuntimeScalar, RuntimeArray, RuntimeHash, RuntimeList, RuntimeCode, RuntimeGlob, RuntimeIO
- Operators: Arithmetic, string, comparison, I/O
- Perl modules: Built-in implementations of core modules

4. **Application** (`org.perlonjava.app`)
- CLI entry point (Main, ArgumentParser, CompilerOptions)
- JSR-223 ScriptEngine integration

## Key Architecture Documents

| Document | Description |
|----------|-------------|
| [dynamic-scope.md](dynamic-scope.md) | Dynamic scoping via `local` and DynamicVariableManager |
| [weaken-destroy.md](weaken-destroy.md) | Cooperative reference counting, DESTROY, and weak references |
| [lexical-pragmas.md](lexical-pragmas.md) | Lexical warnings, strict, and features |
| [control-flow.md](control-flow.md) | Control flow implementation (die/eval, last/next/redo, block dispatchers) |
| [block-dispatcher-optimization.md](block-dispatcher-optimization.md) | Block-level shared dispatchers for control flow |
| [large-code-refactoring.md](large-code-refactoring.md) | Large code handling: proactive block refactoring and interpreter fallback |
| [../design/inline-cache.md](../design/inline-cache.md) | Inline caching design (runtime global cache implemented; per-site variant planned) |
| [../design/method-call-optimization.md](../design/method-call-optimization.md) | Method call optimization plan (Phase 1 done; Phases 2-3 not yet implemented) |
| [../design/interpreter.md](../design/interpreter.md) | Bytecode interpreter design |
| [../design/variables_and_values.md](../design/variables_and_values.md) | Runtime value representation |

Expand All @@ -37,7 +46,7 @@ Perl Source
┌─────────┐
│ Lexer │ Tokenizes source into LexerTokens
│ Lexer │ Tokenizes source into LexerToken instances
└────┬────┘
Expand Down Expand Up @@ -70,7 +79,7 @@ Perl Source
┌────────────────────────────────────────────────┐
│ Runtime Types │
│ RuntimeScalar, RuntimeArray, RuntimeHash │
│ RuntimeCode, RuntimeGlob, RuntimeIO
RuntimeList, RuntimeCode, RuntimeGlob, RuntimeIO │
└────────────────────────────────────────────────┘
Expand Down
24 changes: 22 additions & 2 deletions dev/architecture/block-dispatcher-optimization.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,20 @@ notControlFlow:
ALOAD controlFlowTempSlot // Not marked, continue
```

> **Note:** In addition to the above, each call site also emits an inline tail-call
> trampoline (~30 instructions) that handles `goto &NAME` without jumping to the
> block dispatcher. The actual per-call-site bytecode is ~100-150 bytes, not ~20.

**Block dispatcher (emitted once, ~150 bytes):**
```java
blockDispatcher:
Get control flow type ordinal
Check if LAST/NEXT/REDO (0/1/2)
IF_ICMPGT propagateToCaller // ordinals > 2 handled below
// Higher ordinals (GOTO=3, TAILCALL=4, RETURN=5):
// - GOTO and TAILCALL: propagate to caller
// - RETURN (ordinal 5): unwrap return value for non-map/grep blocks,
// then jump to returnLabel; otherwise propagate
Loop through visible loop labels:
Match label name
Dispatch by type to appropriate label
Expand All @@ -79,6 +88,11 @@ skipDispatcher:
- New: 20N + 150 + 3 bytes
- **Savings: 130N - 153 bytes**

> **Note:** These calculations use a simplified ~20 bytes per call site. The actual
> per-call-site overhead is ~100-150 bytes due to the inline tailcall trampoline.
> The block dispatcher sharing still provides significant savings, but the
> absolute numbers differ from this simplified model.

**Examples:**
| Calls | Old (bytes) | New (bytes) | Savings | Percentage |
|-------|-------------|-------------|---------|------------|
Expand Down Expand Up @@ -106,14 +120,20 @@ skipDispatcher:
1. **JavaClassInfo.java**
- Added `blockDispatcherLabels` map to track dispatcher reuse
- Added `getLoopStateSignature()` method to compute unique signatures
- Imports: Added `HashMap` and `Map`
- Imports: Uses wildcard `import java.util.*`

2. **EmitSubroutine.java**
- Modified call-site emission to use block-level dispatchers
- Added `emitBlockDispatcher()` helper method
- Simplified call-site code to ~20 bytes (check + GOTO)

3. **CONTROL_FLOW_IMPLEMENTATION.md**
3. **Dereference.java** (`backend/jvm/Dereference.java`)
- Contains a full copy of the block-dispatcher pattern (lines 982-1109)
- Includes `getLoopStateSignature()`, `blockDispatcherLabels` lookup,
the tailcall trampoline, and calls `EmitSubroutine.emitBlockDispatcher()`
- Significant second emission point alongside EmitSubroutine.java

4. **control-flow.md**
- Documented block-level dispatcher approach
- Updated performance metrics
- Explained why method-level centralization doesn't work
Expand Down
Loading
Loading