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
1,518 changes: 792 additions & 726 deletions docs/bootstrap-inventory.md

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions lib/JIT/Builtin/Type/Value.php
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,23 @@ public function register(): void {



$fntype___cfcd208495d565ef66e7dff9f98764da = $this->context->context->functionType(
$this->context->getTypeFromString('void'),
false ,
$this->context->getTypeFromString('__value__*')
, $this->context->getTypeFromString('__value__*')

);
$fn___cfcd208495d565ef66e7dff9f98764da = $this->context->module->addFunction('__value__copy', $fntype___cfcd208495d565ef66e7dff9f98764da);



$this->context->registerFunction('__value__copy', $fn___cfcd208495d565ef66e7dff9f98764da);






}

Expand All @@ -252,6 +269,7 @@ public function implement(): void {
// __value__writeLong deferred — Context::lookupFunction ensureLinked (#36135).
// __value__writeNull deferred — Context::lookupFunction ensureLinked (#36124).
// __value__writeBool deferred — Context::lookupFunction ensureLinked (#36108).
// __value__copy deferred — Context::lookupFunction ensureLinked (#36193).
}

public function initialize(): void {
Expand Down
3 changes: 3 additions & 0 deletions lib/JIT/Builtin/Type/Value.pre
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class Value extends Type {
static inline function __value__writeString(__value__*, __string__*): void;

static inline function __value__writeNull(__value__*): void;

static inline function __value__copy(__value__*, __value__*): void;
}
}

Expand All @@ -52,6 +54,7 @@ class Value extends Type {
// __value__writeLong deferred — Context::lookupFunction ensureLinked (#36135).
// __value__writeNull deferred — Context::lookupFunction ensureLinked (#36124).
// __value__writeBool deferred — Context::lookupFunction ensureLinked (#36108).
// __value__copy deferred — Context::lookupFunction ensureLinked (#36193).
}

public function initialize(): void {
Expand Down
41 changes: 41 additions & 0 deletions lib/JIT/Builtin/ValueBoxCopyJit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace PHPCompiler\JIT\Builtin;

use PHPCompiler\JIT\BasicBlockHelper;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\NestedJitCompileScope;
use PHPCompiler\VM\VmValueCopy;

/**
* JIT trampoline for __value__copy.
*
* SSOT: {@see \PHPCompiler\VM\VmValueCopy}
*
* Lazy from JitValueBox::copyBetweenPointers via Context::lookupFunction (#36193).
*/
final class ValueBoxCopyJit
{
public static function ensureLinked(Context $context): void
{
$probe = $context->module->getNamedFunction('__value__copy');
if (null !== $probe && $probe->countBasicBlocks() > 0) {
return;
}
$restore = BasicBlockHelper::tryGetInsertBlock($context);
try {
NestedJitCompileScope::run($context, static function () use ($context): void {
self::implement($context);
});
} finally {
BasicBlockHelper::restoreInsertBlock($context, $restore);
}
}

public static function implement(Context $context): void
{
VmValueCopy::implement($context);
}
}
4 changes: 4 additions & 0 deletions lib/JIT/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -3662,6 +3662,10 @@ public function lookupFunction(string $name): PHPLLVM\Value\Function_ {
if ('__value__writeBool' === $name) {
Builtin\ValueBoxWriteBoolJit::ensureLinked($this);
}
// Lazy __value__copy — one outlined type-switch per module (#36193).
if ('__value__copy' === $name) {
Builtin\ValueBoxCopyJit::ensureLinked($this);
}
if (isset($this->functionScope[$name])) {
return $this->functionScope[$name];
}
Expand Down
158 changes: 5 additions & 153 deletions lib/JIT/JitValueBox.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@

final class JitValueBox
{
private static int $copySeq = 0;

public static function alloc(Context $context): Value
{
BasicBlockHelper::ensureOpenInsertBlock($context, 'value_box_alloc_cont');
Expand Down Expand Up @@ -608,166 +606,20 @@ public static function copyFromPointer(Context $context, Value $destSlot, Value
self::copyBetweenPointers($context, self::pointer($context, $destSlot), $srcPtr);
}

/**
* Copy between two {@see __value__*} pointers — delegates to outlined __value__copy (#36193).
*/
private static function copyBetweenPointers(Context $context, Value $destPtr, Value $srcPtr): void
{
if (!BasicBlockHelper::unsealAndContinue($context)) {
BasicBlockHelper::ensureOpenInsertBlockReplacingVoidReturn($context, 'value_copy_cont');
}
$map = $context->structFieldMap['__value__'];
$typeByte = $context->builder->load(
$context->builder->structGep($srcPtr, $map['type'])
);
$i8 = $context->getTypeFromString('int8');
// Mask IS_REFCOUNTED — HT slots may store VM TYPE_STRING (4) or JIT (4|0x80).
// Unmasked compare missed VM tags → empty copy → NestedJIT toString strlen=0 (#21921).
$kind = $context->builder->and($typeByte, $i8->constInt(0x7f, false));

$tag = 'v'.(string) self::$copySeq++;
$stringBlock = BasicBlockHelper::append($context, 'value_copy_string_'.$tag);
$hashtableBlock = BasicBlockHelper::append($context, 'value_copy_hashtable_'.$tag);
$objectBlock = BasicBlockHelper::append($context, 'value_copy_object_'.$tag);
$longBlock = BasicBlockHelper::append($context, 'value_copy_long_'.$tag);
$doubleBlock = BasicBlockHelper::append($context, 'value_copy_double_'.$tag);
$boolBlock = BasicBlockHelper::append($context, 'value_copy_bool_'.$tag);
$nullBlock = BasicBlockHelper::append($context, 'value_copy_null_'.$tag);
$done = BasicBlockHelper::append($context, 'value_copy_done_'.$tag);

$isString = $context->builder->icmp(
Builder::INT_EQ,
$kind,
$i8->constInt(Variable::TYPE_STRING & 0x7f, false)
);
$isHashtable = $context->builder->icmp(
Builder::INT_EQ,
$kind,
$i8->constInt(Variable::TYPE_HASHTABLE & 0x7f, false)
);
$isObject = $context->builder->icmp(
Builder::INT_EQ,
$kind,
$i8->constInt(Variable::TYPE_OBJECT & 0x7f, false)
);
$isLong = $context->builder->icmp(
Builder::INT_EQ,
$kind,
$i8->constInt(Variable::TYPE_NATIVE_LONG, false)
);
$isBool = $context->builder->icmp(
Builder::INT_EQ,
$kind,
$i8->constInt(Variable::TYPE_NATIVE_BOOL, false)
);
$isDouble = $context->builder->icmp(
Builder::INT_EQ,
$kind,
$i8->constInt(Variable::TYPE_NATIVE_DOUBLE, false)
);
$isNull = $context->builder->icmp(
Builder::INT_EQ,
$kind,
$i8->constInt(Variable::TYPE_NULL, false)
);

$afterString = BasicBlockHelper::append($context, 'value_copy_after_string_'.$tag);
$context->builder->branchIf($isString, $stringBlock, $afterString);

$context->builder->positionAtEnd($stringBlock);
$str = $context->builder->call(
$context->lookupFunction('__value__readString'),
$srcPtr
);
self::writeStringToValuePtrByAddref($context, $destPtr, $str);
$context->builder->branch($done);

$context->builder->positionAtEnd($afterString);
$afterHashtable = BasicBlockHelper::append($context, 'value_copy_after_hashtable_'.$tag);
$context->builder->branchIf($isHashtable, $hashtableBlock, $afterHashtable);

$context->builder->positionAtEnd($hashtableBlock);
$ht = $context->builder->call(
$context->lookupFunction('__value__readHashtable'),
$srcPtr
);
$context->refcount->addref($ht);
Builtin\ValueBoxCopyJit::ensureLinked($context);
$context->builder->call(
$context->lookupFunction('__value__writeHashtable'),
$context->lookupFunction('__value__copy'),
$destPtr,
$ht
);
$context->builder->branch($done);

$context->builder->positionAtEnd($afterHashtable);
$afterObject = BasicBlockHelper::append($context, 'value_copy_after_object_'.$tag);
$context->builder->branchIf($isObject, $objectBlock, $afterObject);

$context->builder->positionAtEnd($objectBlock);
$obj = $context->builder->call(
$context->lookupFunction('__value__readObject'),
$srcPtr
);
// writeObject addrefs internally (#4096); do not addref here.
$context->builder->call(
$context->lookupFunction('__value__writeObject'),
$destPtr,
$obj
);
$context->builder->branch($done);

$context->builder->positionAtEnd($afterObject);
$afterLong = BasicBlockHelper::append($context, 'value_copy_after_long_'.$tag);
$context->builder->branchIf($isLong, $longBlock, $afterLong);

$context->builder->positionAtEnd($longBlock);
$context->builder->call(
$context->lookupFunction('__value__writeLong'),
$destPtr,
$context->builder->call($context->lookupFunction('__value__readLong'), $srcPtr)
);
$context->builder->branch($done);

$context->builder->positionAtEnd($afterLong);
$afterBool = BasicBlockHelper::append($context, 'value_copy_after_bool_'.$tag);
$context->builder->branchIf($isBool, $boolBlock, $afterBool);

$context->builder->positionAtEnd($boolBlock);
// __value__readLong has no TYPE_NATIVE_BOOL arm (returns 0) — #21892 / JitZendScalarCast.
$boolByte = self::readBoolByte($context, $srcPtr);
$i32 = $context->getTypeFromString('int32');
$context->builder->call(
$context->lookupFunction('__value__writeBool'),
$destPtr,
$context->builder->zExt(
$context->builder->icmp(
Builder::INT_NE,
$boolByte,
$context->getTypeFromString('int8')->constInt(0, false)
),
$i32
)
);
$context->builder->branch($done);

$context->builder->positionAtEnd($afterBool);
$afterDouble = BasicBlockHelper::append($context, 'value_copy_after_double_'.$tag);
$context->builder->branchIf($isDouble, $doubleBlock, $afterDouble);

$context->builder->positionAtEnd($doubleBlock);
$context->builder->call(
$context->lookupFunction('__value__writeDouble'),
$destPtr,
$context->builder->call($context->lookupFunction('__value__readDouble'), $srcPtr)
);
$context->builder->branch($done);

$context->builder->positionAtEnd($afterDouble);
$context->builder->branchIf($isNull, $nullBlock, $done);

$context->builder->positionAtEnd($nullBlock);
$context->builder->call($context->lookupFunction('__value__writeNull'), $destPtr);
$context->builder->branch($done);

$context->builder->positionAtEnd($done);
BasicBlockHelper::branchToFreshContinue($context, 'after_value_copy_'.$tag);
}

/**
Expand Down
Loading
Loading