by Enrico Zimuel
Principal Software Engineer @ Elastic
PUG Torino, Mar. 31, 2020
|
* accepted
A Just-In-Time (JIT) compiler is a feature of the run-time interpreter, that instead of interpreting bytecode every time a method is invoked, will compile the bytecode into machine code, and then invoke this object code instead
for ($i=0; $i<100; $i++) {
echo $i;
}
Opcode:
L0 (2): ASSIGN CV0($i) int(0)
L1 (2): JMP L4
L2 (3): ECHO CV0($i)
L3 (2): PRE_INC CV0($i)
L4 (2): T1 = IS_SMALLER CV0($i) int(100)
L5 (2): JMPNZ T1 L2
L6 (5): RETURN int(1)
php -d opcache.opt_debug_level=0x20000 -d opcache.enable_cli=1 test.php
sub $0x10, %rsp
lea 0x50(%r14), %rdi
cmp $0xa, 0x8(%rdi)
jnz .L1
mov (%rdi), %rdi
cmp $0x0, 0x18(%rdi)
jnz .L6
add $0x8, %rdi
.L1:
test $0x1, 0x9(%rdi)
jnz .L7
mov $0x0, (%rdi)
mov $0x4, 0x8(%rdi)
.L2:
mov $EG(exception), %rax
cmp $0x0, (%rax)
jnz JIT$$exception_handler
jmp .L4
.L3:
mov $0x7fcc67e2e630, %r15
mov $0x561f82773690, %rax
call *%rax
mov $EG(exception), %rax
cmp $0x0, (%rax)
jnz JIT$$exception_handler
cmp $0x4, 0x58(%r14)
jnz .L9
add $0x1, 0x50(%r14)
.L4:
mov $EG(vm_interrupt), %rax
cmp $0x0, (%rax)
jnz .L11
cmp $0x4, 0x58(%r14)
jnz .L12
cmp $0x64, 0x50(%r14)
jl .L3
.L5:
mov $0x7fcc67e2e6b0, %r15
add $0x10, %rsp
mov $ZEND_RETURN_SPEC_CONST_LABEL, %rax
jmp *%rax
sub $0x10, %rsp
jmp .L4
.L6:
mov $0x7fcc67e2e5c0, %rsi
mov %r15, (%r14)
mov $zend_jit_assign_const_to_typed_ref, %rax
call *%rax
jmp .L2
.L7:
mov (%rdi), %rax
mov %rax, (%rsp)
mov $0x0, (%rdi)
mov $0x4, 0x8(%rdi)
mov (%rsp), %rdi
sub $0x1, (%rdi)
jnz .L8
mov %r15, (%r14)
mov $rc_dtor_func, %rax
call *%rax
jmp .L2
.L8:
mov 0x4(%rdi), %eax
and $0xfffffc10, %eax
cmp $0x10, %eax
jnz .L2
mov $gc_possible_root, %rax
call *%rax
jmp .L2
.L9:
mov %r15, (%r14)
lea 0x50(%r14), %rdi
cmp $0xa, 0x8(%rdi)
jnz .L10
mov (%rdi), %rsi
cmp $0x0, 0x18(%rsi)
lea 0x8(%rsi), %rdi
jz .L10
mov $0x0, %rdx
mov $zend_jit_pre_inc_typed_ref, %rax
call *%rax
mov $EG(exception), %rax
cmp $0x0, (%rax)
jnz JIT$$exception_handler
jmp .L4
.L10:
mov $increment_function, %rax
call *%rax
jmp .L4
.L11:
mov $0x7fcc67e2e670, %r15
jmp JIT$$interrupt_handler
.L12:
cmp $0x5, 0x58(%r14)
jnz .L13
mov $0x64, %rax
vcvtsi2sd %rax, %xmm0, %xmm0
vucomisd 0x50(%r14), %xmm0
ja .L3
jmp .L5
.L13:
mov $0x7fcc67e2e670, %rax
mov %rax, (%r14)
lea 0x50(%r14), %rsi
mov $0x7fcc67e2e5d0, %rdx
lea 0x60(%r14), %rdi
mov $compare_function, %rax
call *%rax
mov $EG(exception), %rax
cmp $0x0, (%rax)
jnz JIT$$exception_handler_undef
cmp $0x0, 0x60(%r14)
jl .L3
jmp .L5
php -d opcache.enable_cli=1 -d opcache.jit=1235
-d opcache.jit_buffer_size=64M -d opcache.jit_debug=1 test.php
Execution time (sec) of Zend/bench.php, using PHP 7.4.4 (Zend Engine 3.4.0)
and PHP 8.0.0-dev (Zend Engine 4.0.0-dev)
class Number {
private int|float $number;
public function setNumber(int|float $number): void {
$this->number = $number;
}
public function getNumber(): int|float {
return $this->number;
}
}
class Foo {
public function __construct($params = [])
{
$this->params = $params;
}
public function createFromWhatever($whatever): static {
return new static($whatever);
}
}
$foo = new Foo();
var_dump($foo); // object(Foo)#1 { ["params"]=> [] }
$bar = $foo->createFromWhatever(['x' => 'y']);
var_dump($bar); // object(Foo)#2 { ["params"]=> ["x" => "y"]}
class Test {
public function doWhatever(): static {
// Do whatever.
return $this;
}
}
To provide "weakly referenced" map objects
$map = new WeakMap;
$obj = new stdClass;
$map[$obj] = 42;
var_dump($map);
// object(WeakMap)#1 (1) {
// [0]=> [
// "key" => object(stdClass)#2,
// "value" => int(42)
// ]
// }
// The object is destroyed here, key automatically removed
unset($obj);
var_dump($map);
// object(WeakMap)#1 (0) { }
final class WeakMap implements ArrayAccess, Countable, Traversable {
public function offsetGet($object);
public function offsetSet($object, $value): void;
public function offsetExists($object): bool;
public function offsetUnset($object): void;
public function count(): int;
}
class Foo {
private WeakMap $cache;
public function getSomethingWithCaching(object $obj) {
return $this->cache[$obj] ??= $this->somethingExpensive($obj);
}
// ...
}
??= Null Coalescing Assignment (PHP 7.4+)
$object = new stdClass;
var_dump($object::class); // "stdClass"
$object = null;
var_dump($object::class); // TypeError
interface Stringable
{
public function __toString(): string;
}
Stringable interface is automatically added to classes that implement the __toString() method
PHP 8 should be released on December 2020
(maybe Q1 2021)
Follow me: @ezimuel
Subscribe to PUG Torino on Meetup!
This work is licensed under a
Creative Commons Attribution-ShareAlike 3.0 Unported License.
I used reveal.js to make this presentation.