Skip to content

Language: (array)/(object)/(float)/(unset) cast — JIT/AOT TYPE_CAST_* opcodes (zend_operators.c) #4887

Closed

Description

@PurHur

Category

language

Problem

Several cast opcodes are implemented on the VM but missing from the JIT execute switch. Audit (lib/VM.php cases minus lib/JIT.php):

Opcode VM JIT
TYPE_CAST_ARRAY yes no
TYPE_CAST_OBJECT yes no
TYPE_CAST_FLOAT yes no
TYPE_CAST_UNSET yes no

Scripts using (array) $obj, (object) $arr, (float) $x, or (unset) $ref compile for VM but JIT/AOT paths lack lowering.

php-src reference

Repro — VM baseline

test/compliance/cases/language/cast_array_object.phpt:

<?php
class C { public int $x = 1; public string $y = 'hi'; }
$a = (array) new C();
echo count($a), $a['x'], $a['y'];
$b = [1 => 'one', 'k' => 'two'];
$c = (array) $b;
$c[1] = 'changed';
echo $b[1], "\n";

Expected: 21hi2onetwoone (Zend object→array uses mangled keys; match existing PHPT).

./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && php bin/vm.php test/compliance/cases/language/cast_array_object.phpt'

Repro — JIT gap

./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
export PHP_COMPILER_LLVM_PATH=/opt/llvm9
export LD_LIBRARY_PATH=/opt/llvm9
php bin/jit.php -r "echo count((array)(object)[\"x\"=>1]);"
'

VM prints 1; JIT must match once casts are lowered (delegate to lib/VM/CastSupport.php semantics).

Scope

Area Files
JIT lib/JIT.php — add TYPE_CAST_ARRAY, TYPE_CAST_OBJECT, TYPE_CAST_FLOAT, TYPE_CAST_UNSET
Shared lib/VM/CastSupport.php — single source of cast semantics
Tests existing cast_*.phpt; add cast_array_object_jit.phpt if needed
Matrix script/capability-syntax.php cast rows

Done when

  • All four opcodes lowered in JIT (AOT inherits)
  • cast_array_object.phpt + cast_unset.phpt pass under JIT filter
  • No new VM-only fallback solely due to missing cast opcodes

Links

Activity

  1. added
    enhancementNew feature or request
    area:vmVirtual machine
    implementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claim
    on Jun 3, 2026
  2. PurHur commented on Jun 7, 2026

    @PurHur
    OwnerAuthor

    claim: worker-lane-a — starting this run

  3. PurHur commented on Jun 7, 2026

    @PurHur
    OwnerAuthor

    Unclaiming: simple cast scripts VM-fallback or compile via object cast path; full JIT lowering deferred. Lane A switching to #5049 (unit enum <=> JIT divergence confirmed).

  4. PurHur commented on Jun 8, 2026

    @PurHur
    OwnerAuthor

    claim: worker-lane-a — starting this run

  5. PurHur commented on Jun 8, 2026

    @PurHur
    OwnerAuthor

    claim released — WIP blocked on stdClass dynamic property store from hashtable iteration.

    Verified gap: TYPE_CAST_ARRAY / TYPE_CAST_OBJECT / TYPE_CAST_UNSET missing from lib/JIT.php switch; Analyzer.php rejects Cast\\Array_ operands during Variable::fromOp().

    Repro compile failure:

    ./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && php -r "
    use PHPCompiler\\Runtime; use PHPCompiler\\Block;
    \$r = new Runtime();
    \$s = \"<?php echo count((array)(object)[\"x\"=>1]);\";
    \$b = \$r->parseAndCompile(\$s, \"t.php\");
    \$r->jit(\$b, \$s, \"t.php\");
    "'

    → LogicException: Not implemented escape operand PHPCfg\\Op\\Expr\\Cast\\Array_

    Next steps: (1) Analyzer cast-op allowlist, (2) ext/standard/JitCast.php delegating array cast to JitGetObjectVars + ArrayBuiltinHelper::cloneHashTableForCast, (3) object cast needs stdClass property store from hashtable keys (no propertyStoreDynamic helper yet — mirror Object_::propertyFetchDynamic write path).

  6. PurHur commented on Jun 8, 2026

    @PurHur
    OwnerAuthor

    claim: worker-lane-a — starting this run

  7. PurHur commented on Jun 8, 2026

    @PurHur
    OwnerAuthor

    Merged via #7618

    Verification

    • vendor/bin/phpunit test/unit/CastJitCompileTest.php — OK (3 tests)
    • Issue repro JIT execute: count((array)(object)["x"=>1]) → 1

    Implementation

    • lib/JIT/CastHelper.php — TYPE_CAST_ARRAY / TYPE_CAST_OBJECT / TYPE_CAST_UNSET lowering
    • Object_::allocate() — restore LLVM insert block after first GcCollectCyclesRuntime::ensureLinked() so phpc_gc_register emits into the active CFG block
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:compilerCompiler / CFG / JITarea:vmVirtual machineenhancementNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-2:languagePhase 2 – language features

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions