Skip to content

Function JIT: "ENTRY 2 (block 15 start 68) - live var 66" for a namespaced method that passes a recursive self:: call to an unqualified function #25037

Open
dstogov/ir
#282

Description

@rhift

Description

With the function JIT at opcache.jit=1205 or 1204, compiling the method below writes this line to stderr once per process:

ENTRY 2 (block 15 start 68) - live var 66

The line is printed by ir_add_osr_entry_loads() in ext/opcache/jit/ir/ir_ra.c, which then sets ok = 0 and reaches IR_ASSERT(0). In a release build the assertion is compiled out, and the method is still compiled: it appears in the perf map written with opcache.jit_debug=0x10.

The following code:

<?php
// /tmp/entry.php
namespace Reproduce;

class Entry
{
    public static function chr(int $ord, string $encoding = 'UTF-8'): string
    {
        if ($encoding === 'UCS-4BE') {
            return pack('N', $ord);
        }

        return mb_convert_encoding(self::chr($ord, 'UCS-4BE'), $encoding, 'UCS-4BE');
    }
}
<?php
// /tmp/preload.php
opcache_compile_file('/tmp/entry.php');
php -d opcache.enable_cli=1 -d opcache.jit_buffer_size=32M -d opcache.jit=1205 \
    -d opcache.preload=/tmp/preload.php -d opcache.preload_user=root \
    -r 'echo \Reproduce\Entry::chr(0x1F35E), "\n";'

Resulted in this output:

ENTRY 2 (block 15 start 68) - live var 66
🍞

But I expected this output instead:

🍞

The same line, with the same numbers, appears on aarch64 in php:8.5.12-cli-alpine3.24 and php:8.5.12-cli-trixie, and on x86_64 in php:8.5.12-cli-trixie (linux/amd64, run under emulation on an aarch64 host).

What changes the outcome, each case measured with one process start (ENTRY lines counted on stderr):

Case ENTRY lines
As above, opcache.jit=1205 1
opcache.jit=1204 1
opcache.jit=1203, 1255, tracing or disable 0
\mb_convert_encoding(...) written fully qualified 0
use function mb_convert_encoding; added below the namespace 0
Only \pack(...) qualified 1
static::chr(...) instead of self::chr(...) 0
The class in the global namespace 0
opcache.file_cache set or unset no change
Not preloaded: require '/tmp/entry.php' in the script, opcache.jit=1205, aarch64 0
The same, x86_64 under emulation 1

So the trigger appears to be an unqualified function call in a namespace (resolved at run time, namespaced name first) whose argument is the result of a recursive self:: call, compiled by the function JIT with optimization level 4 or 5.

No wrong result was observed. In an application that preloads graphql-php, whose GraphQL\Utils\Utils::chr() has exactly this shape and writes the same line, chr() returned the same bytes with opcache.jit=1205 as with opcache.jit=disable for every code point from 0 to 0x10FFFF, and so did Utils::ord() applied to each result. Whether the entry named in the message is ever taken at run time was not determined.

Possibly related: GH-24578 reports the same message from the function JIT, there with a wrong result, and a comment on it notes that function JIT entries are the receive entries and the continuations after DO_UCALL.

Only 8.5.12 was tested. ext/opcache/jit/ir/ir_ra.c on the PHP-8.5 branch has not changed since 8.5.12; on master it changed after 8.5.12 was tagged. Neither branch was built.

PHP Version

PHP 8.5.12 (cli) (built: Oct 21 2026 15:54:49) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.5.12, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.12, Copyright (c), by Zend Technologies

The x86_64 run used the linux/amd64 php:8.5.12-cli-trixie image built on Oct 28 2026.

Operating System

Alpine Linux 3.24 and Debian trixie (official Docker images), aarch64; Debian trixie linux/amd64 under emulation

Activity

  1. self-assigned this
    on Oct 30, 2026
  2. added 2 commits that reference this issue on Oct 30, 2026
    643480e
    5609294
  3. jorgsowa commented on Nov 2, 2026

    @jorgsowa
    Contributor

    That's not yet fixed in php-src. I'm not sure why cross-repository commits close issues in github...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions