Skip to content

Part 4 — PL/I Runtime Reference

4.1 Runtime Overview

The Heirloom PL/I Runtime (pli_runtime2) is a Java library that provides the execution environment for transpiled PL/I programs. It consists of 221 Java classes (~55,000 lines) implementing PL/I semantics on the JVM.

4.1.1 Runtime Architecture

┌──────────────────────────────────────────────────────────┐
│                 PL/I Runtime Library                      │
│                                                          │
│  ┌────────────────┐  ┌────────────────┐  ┌────────────┐ │
│  │ Core Runtime   │  │ Type System    │  │ Builtin    │ │
│  │ - PLIRuntime   │  │ - PLIString    │  │ Functions  │ │
│  │ - ETPBase      │  │ - FixedBin     │  │ - 66+      │ │
│  │ - ETPBatch     │  │ - Picture      │  │   methods  │ │
│  │ - Condition    │  │ - BitN         │  │            │ │
│  │ - Entry        │  │ - Array<T>     │  │            │ │
│  │                │  │ - Group        │  │            │ │
│  │                │  │ - Pointer<T>   │  │            │ │
│  │                │  │ - PackedDecimal│  │            │ │
│  │                │  │ - Complex      │  │            │ │
│  └────────────────┘  └────────────────┘  └────────────┘ │
│                                                          │
│  ┌────────────────┐  ┌────────────────┐  ┌────────────┐ │
│  │ I/O Subsystem  │  │ CICS Layer     │  │ SQL Layer  │ │
│  │ - PLIStream    │  │ (see Part 5)   │  │ (see Pt 6) │ │
│  │ - PLIRecord    │  │                │  │            │ │
│  │ - PLIFile      │  │                │  │            │ │
│  └────────────────┘  └────────────────┘  └────────────┘ │
└──────────────────────────────────────────────────────────┘

4.1.2 Execution Modes

  • Batch Mode (ETPBatch) — Standalone batch program execution with main() entry point
  • Transaction Mode (ETPBase) — CICS/MQ transaction execution with instance lifecycle, constructor initialization, and thread-local environment isolation

4.1.3 Runtime Configuration

  • DD name mapping via environment variables (DD_<name>, DDNAME_<name>)
  • Property-based file configuration
  • JDBC connection factory configuration
  • MQ connection parameters
  • Log4j logging configuration

4.2 Runtime Type System

For PL/I syntax: See Language Reference: 3.2 Data Types and Declarations for PL/I declaration syntax and semantics

4.2.1 PLIString — Fixed/Variable-Length Character Strings

PL/I Syntax: See Language Reference: 3.2.3 String Data Types for CHARACTER declaration syntax

  • Fixed-length semantics with blank padding (PL/I CHAR(n))
  • Variable-length semantics with VARYING attribute
  • 1-based indexing (PL/I convention)
  • Automatic truncation and padding
  • EBCDIC/ASCII transparent support

4.2.2 FixedBin — Fixed Binary Integers

PL/I Syntax: See Language Reference: 3.2.2 Arithmetic Data Types for FIXED BINARY declaration syntax

  • Halfword (2-byte), fullword (4-byte), doubleword (8-byte)
  • Precision handling (1–63 digits)
  • Overflow detection

4.2.3 PackedDecimal — Packed Decimal Arithmetic

PL/I Syntax: See Language Reference: 3.2.2 Arithmetic Data Types for FIXED DECIMAL declaration syntax

  • Arbitrary precision decimal arithmetic
  • Precision and scale tracking
  • PICTURE integration

4.2.4 Picture — Formatted Numeric/Character Data

PL/I Syntax: See Language Reference: 3.2.4 PICTURE Data Type for PICTURE declaration syntax

  • Complete PICTURE clause implementation (177,000+ lines)
  • Character specifications: A, E, X, B
  • Numeric specifications: 9, Z, V, ., S, +, -, CR, DB
  • Currency symbols
  • Overpunch notation
  • Date/time PICTURE support

4.2.5 BitN — Bit String Operations

PL/I Syntax: See Language Reference: 3.2.3 String Data Types for BIT declaration syntax

  • Arbitrary-length bit strings
  • Bitwise operations (AND, OR, NOT, XOR)
  • Bit-to-character and character-to-bit conversion

4.2.6 Array — Multi-Dimensional Arrays

PL/I Syntax: See Language Reference: 3.2.6 Arrays for array declaration syntax

  • Custom lower bounds (default 1 for PL/I)
  • Sparse implementation with lazy initialization
  • Slice operations
  • Dimension introspection (DIM, HBOUND, LBOUND)

4.2.7 Group — Structured Data (Records)

PL/I Syntax: See Language Reference: 3.2.5 Structures for STRUCTURE declaration syntax

  • PL/I STRUCTURE equivalent
  • ByteBuilder integration for byte-level access
  • ASSIGN BY NAME semantics
  • Inner group (nested structure) support
  • Union handling
  • LOCATE mode support
  • Manifold property generation

4.2.8 Pointer — Pointers and Locator Variables

PL/I Syntax: See Language Reference: 3.2.7 Pointers and Locator Variables for POINTER declaration syntax

  • Typed pointers: Pointer<T> with type safety
  • Untyped pointers for generic references
  • Direct and indirect (handle-based) pointers
  • Pointer arithmetic (POINTERADD, POINTERDIFF)
  • Double-pointer support for pass-by-reference
  • Thread-safe pointer management

4.2.9 Complex — Complex Numbers

  • Real and imaginary components
  • Complex arithmetic operations

4.2.10 Entry — Procedure References

  • First-class procedure references
  • Parameter binding and invocation
  • Used for ENTRY VARIABLE declarations

4.3 Memory Management

PL/I Syntax: See Language Reference: 3.2.9 Data Attributes for BASED, CONTROLLED, and storage class syntax

4.3.1 Storage Classes

  • AUTOMATIC — Allocated on procedure entry, freed on exit
  • STATIC — Persists for program duration
  • CONTROLLED — Explicit ALLOCATE/FREE with push-down stack
  • BASED — Pointer-addressed storage

4.3.2 ALLOCATE and FREE

PL/I Syntax: See Language Reference: 3.4.4 Storage Management Statements for ALLOCATE and FREE statement syntax

  • Dynamic storage allocation for CONTROLLED variables
  • Based variable allocation with pointer binding
  • REFER attribute for self-defining data

4.3.3 Pointer Operations

  • ADDR() — Obtain pointer to a variable
  • Pointer dereferencing and assignment
  • Pointer arithmetic
  • Null pointer detection (NULL, SYSNULL)

4.3.4 Areas

  • Memory area management
  • Based variable areas

4.3.5 Memory Management Architecture

The PLI Runtime provides a sophisticated memory management system that ensures mainframe-compatible storage behavior on the JVM. This system enables PL/I programs to work with memory in the same way they did on the mainframe, including support for BASED variables, memory overlays, and byte-level data precision.

Key Capabilities

Mainframe Memory Compatibility - Maintains exact byte-level memory layout matching mainframe PL/I - Preserves field offsets and structure alignment - Supports EBCDIC/ASCII encoding conversions - Enables seamless data interchange with mainframe systems

Storage Hierarchy - Nested structures with parent-child relationships - Cumulative offset tracking across structure levels - Automatic memory layout calculation - Support for complex nested data structures

Memory Sharing and Overlays - Multiple variables can share the same memory location - Changes to one variable immediately visible to others sharing the memory - Enables efficient memory usage for large data structures - Supports PL/I UNION semantics (fields at same offset)


4.3.6 BASED Storage

BASED storage allows variables to overlay existing memory, enabling pointer-based memory access and efficient data structures.

Concept:

DCL BASE_STR CHAR(10);
DCL BASED_STR CHAR(7) BASED(ADDR(BASE_STR));

In this example, BASED_STR does not allocate its own storage. Instead, it accesses the first 7 bytes of BASE_STR's memory.

Key Features: - Shared Storage - BASED variables reference memory owned by another variable - Memory Overlay - Multiple BASED variables can reference the same base storage - Offset Control - BASED variables can start at any byte offset within base storage - Synchronization - Changes through any reference are immediately visible to all

Use Cases: - Efficient memory reuse - Alternative views of the same data - Dynamic data structure management - Pointer-based algorithms


4.3.7 DEFINED Variables (Memory Aliases)

DEFINED variables create aliases to existing fields, allowing the same memory to be accessed under different names or types.

Concept:

DCL FULL_NAME CHAR(30);
DCL FIRST_NAME CHAR(15) DEFINED FULL_NAME;

Both variables reference the same memory location. Writing to FIRST_NAME modifies the beginning of FULL_NAME.

Benefits: - Type Reinterpretation - View the same memory as different types - Field Aliasing - Access portions of structures with convenient names - Memory Efficiency - No duplication of data - Mainframe Compatibility - Preserves PL/I memory semantics


4.3.8 Memory Layout Precision

The runtime maintains exact byte-level precision for all structure fields:

Example Structure:

DCL 1 CUSTOMER_REC,
      2 CUST_ID    CHAR(10),      /* Offset: 0, Size: 10 bytes */
      2 NAME       CHAR(30),      /* Offset: 10, Size: 30 bytes */
      2 BALANCE    DEC FIXED(15,2); /* Offset: 40, Size: 9 bytes */

Precision Requirements: - Field offsets match mainframe memory layout exactly - Structure size matches mainframe byte count - Nested structures maintain cumulative offsets - Arrays allocated contiguously

Why This Matters: - Data Interchange - Binary data files can be read/written compatibly - Integration - Can exchange data with mainframe systems - Migration - Gradual migration without data conversion - Validation - Side-by-side comparison with mainframe output


4.3.9 Thread Safety

The storage management system provides thread-safe operations for concurrent execution:

Thread Isolation: - Transaction-specific storage isolated per thread - Thread-local pointers automatically managed - No interference between concurrent transactions

Synchronization: - Safe concurrent access to shared structures - Automatic cleanup of thread resources - Proper handling of pointer lifecycles

CICS Compatibility: - Replicates mainframe quasi-reentrant behavior - Supports concurrent transaction execution - Maintains storage consistency across threads

4.4 Thread Safety and Concurrency

4.4.1 Mainframe Concurrency Model

The PLI Runtime replicates the IBM mainframe concurrency model to ensure transactions execute safely and predictably, matching mainframe behavior.

Quasi-Reentrant Execution

Concept: On the mainframe, PL/I programs execute in a quasi-reentrant mode, meaning: - Sequential Execution: Only one transaction executes PL/I logic at any given time - Shared Resource Safety: Static variables and common work areas are protected by sequential access - Yield Points: During I/O operations (SQL, CICS commands, MQ), other transactions can execute

Why This Matters: - Mainframe Compatibility: Java execution matches mainframe behavior exactly - Migration Safety: Programs behave the same way as on the mainframe - No Code Changes: PL/I programs don't need modifications for thread safety

Concurrent I/O Processing

While PL/I logic executes sequentially, I/O operations can overlap:

Without Concurrent I/O:

Transaction A: [Logic] → [====== SQL Wait ======] → [Logic]
Transaction B:           [Blocked - waiting]
Transaction C:           [Blocked - waiting]

With Concurrent I/O (Mainframe Model):

Transaction A: [Logic] → [SQL I/O] → [Logic]
Transaction B:    [Logic] → [SQL I/O] → [Logic]
Transaction C:       [Logic] → [SQL I/O] → [Logic]

Benefits: - Better Throughput: Multiple transactions can have SQL/MQ operations in progress simultaneously - Improved Latency: Transactions don't block during I/O waits - Resource Efficiency: Better utilization of database and network resources - Mainframe Parity: Matches mainframe TCB switching behavior

Supported I/O Operations

The runtime automatically manages concurrent I/O for:

SQL Operations: - All database queries (SELECT, INSERT, UPDATE, DELETE) - Transaction control (COMMIT, ROLLBACK) - Cursor operations (OPEN, FETCH, CLOSE)

CICS Commands: - File operations (READ, WRITE, REWRITE, DELETE) - Terminal I/O (SEND, RECEIVE) - Queue operations (temporary storage, transient data) - Program control commands

MQ Operations: - Message queue operations (PUT, GET) - Queue management (OPEN, CLOSE) - Connection management


4.4.2 Performance Benefits

The QR TCB lock management provides significant performance improvements for I/O-heavy workloads:

Before Implementation (serialized I/O):

Thread 1: [PL/I][====SQL I/O====][PL/I]
Thread 2:                         [PL/I][====SQL I/O====][PL/I]
Thread 3:                                                 [PL/I][====SQL I/O====][PL/I]
Thread 4:                                                                         [PL/I]

Total Time: ~12 time units (fully serialized)

After Implementation (parallelized I/O):

Thread 1: [PL/I][====SQL I/O====][PL/I]
Thread 2:       [PL/I][====SQL I/O====][PL/I]
Thread 3:             [PL/I][====SQL I/O====][PL/I]
Thread 4:                   [PL/I][====SQL I/O====][PL/I]

Total Time: ~6 time units (up to 2x improvement)

Expected Improvements: - Throughput: 2-4x improvement for I/O-heavy workloads with multiple concurrent transactions - Latency: Reduced wait times for threads blocked on QR TCB acquisition - Scalability: Better utilization of multi-core systems - Mainframe Parity: Behavior now matches mainframe TCB switching (QR→L8→QR)

Performance Considerations: - Lock Contention: Single global lock serializes all PL/I logic execution (matches mainframe) - TCB Switching Overhead: Each SQL/MQ operation incurs two lock operations (matches mainframe) - Scalability Limits: Only one thread executes PL/I logic at any given time (matches mainframe)


Storage Solution and Thread Safety

Shared Resource Protection: - PL/I programs must adhere to quasi-reentrancy principles - Shared resources (STATIC variables, CWA, GWA) are accessed safely because concurrent execution under QR TCB is not allowed - Tasks using QR TCB are inherently serialized

Storage Classes: - AUTOMATIC: Thread-safe (local to each invocation) - STATIC: Protected by QR TCB lock (serialized access) - CONTROLLED: Stack-based, protected by QR TCB lock - BASED: Dynamic allocation, user-managed pointers

Transaction Environment Isolation: - Thread-local storage for transaction environments - Isolated variable state per transaction instance - Prevents cross-contamination between concurrent transactions


Configuration

The QR TCB lock mechanism is always active in the runtime to ensure proper mainframe parity.

Historical Note: Prior to version 26.2.19 (February 2026), a tcb.lock.disable configuration option existed but has been removed to ensure consistency and safety.

Rationale for Mandatory Locking: - Consistency: All environments behave identically - Simplification: Removes conditional checks in hot code paths - Mainframe Parity: The mainframe doesn't allow disabling QR TCB serialization - Safety: Prevents accidental data corruption from concurrent access to shared resources


Summary: Mainframe Parity Checklist

Behavior Mainframe pli_runtime2 Status
Serialize PL/I execution QR TCB single-threaded Single ReentrantLock ✓ Complete
Release during CICS I/O Task suspension checkpoint() ✓ Complete
Release during SQL QR→L8 switch checkpoint() ✓ Complete
Release during MQ QR→L8 switch checkpoint() ✓ Complete
Reacquire after I/O L8→QR switch acquireLock() ✓ Complete
Protect shared resources Implicit via QR TCB Implicit via lock ✓ Complete
SQL Cursor operations L8 TCB execution checkpoint pattern ✓ Complete

Key Principle: The QR TCB lock management implementation in pli_runtime2 provides complete mainframe parity for quasi-reentrant PL/I program execution, ensuring that PL/I logic executes serially while allowing concurrent I/O operations.

4.4.2 Transaction Environment Isolation

  • Thread-local storage for transaction environments
  • Isolated variable state per transaction instance