PHP 7 – What changed internally?

122
PHP 7 What changed internally? Nikita Popov

Transcript of PHP 7 – What changed internally?

PHP 7What changed internally?

Nikita Popov

•Return type declarations

•Scalar type declarations

function startsWith(string $s1, string $s2) : bool {…}

211

254 256 273

627666

0

100

200

300

400

500

600

700

PHP 5.3 PHP 5.4 PHP 5.5 PHP 5.6 PHP 7 HHVM 3.7

Req

/ S

ec

Wordpress 4.1.1 (home, 20 c)

Stolen from Rasmus

•Smaller data structures

•Fewer allocations

•Less indirection

zval

zval

5

NULLBOOLLONGDOUBLESTRINGARRAYOBJECTRESOURCE

5

NULLBOOLLONGDOUBLESTRINGARRAYOBJECTRESOURCE

lval (long)

dval (double)

5

NULLBOOLLONGDOUBLESTRINGARRAYOBJECTRESOURCE

lval (long)

dval (double)

5

64 bits / 8 bytes

NULLBOOLLONGDOUBLESTRINGARRAYOBJECTRESOURCE

lval (long)

dval (double)

lval (long)

1 bit

5

NULLBOOLLONGDOUBLESTRINGARRAYOBJECTRESOURCE

val (char *)

len (int)

A B C \0

5

value

ty

5

value

refcount ty

5

value = LONG(42)

refcount = 1$i

$i = 42;

5

value = LONG(42)

refcount = 2$i

$j

$i = 42;$j = $i;

5

value = LONG(42)

refcount = 3$i

$j

$k

$i = 42;$j = $i;$k = $i;

5

value = LONG(42)

refcount = 1

$i = 42;$j = $i;$k = $i;unset($i, $k);

5

$j

value = LONG(42)

refcount = 0

$i = 42;$j = $i;$k = $i;unset($i, $k);unset($j);

5

value = LONG(42)

refcount = 0

$i = 42;$j = $i;$k = $i;unset($i, $k);unset($j);

free( )

5

value = ARRAY

refcount = 1$a

$a = [];

5

[0]: (empty)

[1]: (empty)

[2]: (empty)

value = ARRAY

refcount = 2$a

$a = [];$a[0] = $a;

5

[0]:

[1]: (empty)

[2]: (empty)

value = ARRAY

refcount = 1

$a = [];$a[0] = $a;unset($a);

5

[0]:

[1]: (empty)

[2]: (empty)

value = ARRAY

refcount = 1

$a = [];$a[0] = $a;unset($a);

5

[0]:

[1]: (empty)

[2]: (empty)

[0]: (empty)

[1]: (empty)

[2]: (empty)

GC root buffer

value = ARRAY

refcount = 1

$a = [];$a[0] = $a;unset($a);

5

[0]:

[1]: (empty)

[2]: (empty)

[0]:

[1]: (empty)

[2]: (empty)

GC root buffer

value = ARRAY

refcount = 1

gc_root

$a = [];$a[0] = $a;unset($a);

5

[0]:

[1]: (empty)

[2]: (empty)

[0]:

[1]: (empty)

[2]: (empty)

GC root buffer

value

refcount ty

gc_root

5

size

prev_size

value

refcount ty

gc_root

5

size

prev_size

value

refcount ty

gc_root

5

32 bytes

16 bytes

value

type_info (u2)

7

NULLBOOLLONGDOUBLESTRINGARRAYOBJECTRESOURCE

5

NULLBOOLLONGDOUBLESTRINGARRAYOBJECTRESOURCE

7

FALSETRUE

NULLBOOLLONGDOUBLESTRINGARRAYOBJECTRESOURCEREFERENCE 7

FALSETRUE

NULLFALSETRUELONGDOUBLESTRINGARRAYOBJECTRESOURCEREFERENCE

val (char *)

len (int)

A B C \0

5

NULLFALSETRUELONGDOUBLESTRINGARRAYOBJECTRESOURCEREFERENCE 7

zend_string *

refcount type_info

hash

len (size_t)

A B C \0

NULLFALSETRUELONGDOUBLESTRINGARRAYOBJECTRESOURCEREFERENCE 7

zend_string *

refcount type_info

hash

len (size_t)

A B C \0

refcounted header

$i = 42;

7

$i value = 42

LONG

$i = 42;$j = $i;

7

$i value = 42

LONG

$j value = 42

LONG

$i = 42;$j = $i;$k = $i;

7

$i value = 42

LONG

$j value = 42

LONG

$k value = 42

LONG

$s = “foobar”;

7

$s value

STRING

refcount = 1 type_info

hash = 0x80000652FDE460BE

len = 6

f o o b a r \0

$s = “foobar”;$t = $s;

7

$s value

STRING

$t value

STRING refcount = 2 type_info

hash = 0x80000652FDE460BE

len = 6

f o o b a r \0

$s = “foobar”;$t = $s;$u = $s;

7

$s value

STRING

$t value

STRING

$u value

STRING

refcount = 3 type_info

hash = 0x80000652FDE460BE

len = 6

f o o b a r \0

7

refcount type_info

hash

len (size_t)

A B C \0

refcounted header

7

refcount type_info

hash

len (size_t)

A B C \0

refcounted header

type flags gc_info

7

refcount type_info

hash

len (size_t)

A B C \0

refcounted header

type flags gc_info

INTERNEDetc.

value

type_info (u2)

7

value

type_info (u2)

7

type type_flags const_flags

7

type type_flags const_flags

refcounted collectable copyable

simple types

string

interned string

array

object

resource

reference

7

type type_flags const_flags

refcounted collectable copyable

simple types

string

interned string

array

object

resource

reference

7

type type_flags const_flags

refcounted collectable copyable

simple types

string

interned string

array

object

resource

reference

7

type type_flags const_flags

refcounted collectable copyable

simple types

string

interned string

array

object

resource

reference

5

array == HashTable

5

key = “foo”

idx = hash(“foo”)

5

key = “foo”

idx = hash(“foo”) % tableSize

5

[0]: (empty)

[1]: (empty)

[2]: (empty)

[3]: (empty)

“foo”

5

[0]: (empty)

[1]:

[2]: (empty)

[3]: (empty)

“foo”data

key “foo”

zval

5

[0]: (empty)

[1]:

[2]: (empty)

[3]: (empty)

“foo”data

key “foo”“bar”

5

[0]: (empty)

[1]:

[2]: (empty)

[3]: (empty)

“foo”data

key “foo”

next“bar”

data

key “bar”

next = NULL

5

[0]: (empty)

[1]:

[2]: (empty)

[3]: (empty)

“foo”data

key “foo”

next

prev = NULL

“bar”

data

key “bar”

next = NULL

prev

5

data

prev

next

key “foo”

zval

5

data

listNext

listPrev

prev

next

key “foo”

zval

$a1 = [“foo” => 1,“bar” => 2];

$a2 = [“bar” => 2,“foo” => 1];

5

dataPtr

data

listNext

listPrev

prev

next

key “foo”

zval

5

hash

keyLen

dataPtr

data

listNext

listPrev

prev

next

key “foo”

zval

7

hash

key

value

type_info nextzval

7

hash

key

value

type_info nextrefcount type_info

hash

len

f o o \0

zend_string

7

hash

key

value

type_info next

hash

key

value

type_info next

hash

key

value

type_info next

7

hash

key

value

type_info next

hash

key

value

type_info next

hash

key

value

type_info next

[0]

[1]

[2]

[3]

7

hash

key

value

type_info next

hash

key

value

type_info next

hash

key

value

type_info next

[0] = -1

[1] = -1

[2] = -1

[3] = -1

$a = [];numUsed = 0

7

hash

key

value = 42

LONG next = -1

hash

key

value

type_info next

hash

key

value

type_info next

[0] = -1

[1] = 0

[2] = -1

[3] = -1

“foo”

$a = [];$a[“foo”] = 42;

“foo”

numUsed = 1

7

hash

key

value = 42

LONG next = -1

hash

key

value = 24

LONG next = -1

hash

key

value

type_info next

[0] = -1

[1] = 0

[2] = -1

[3] = 1

“foo”

$a = [];$a[“foo”] = 42;$a[“bar”] = 24; “foo”

“bar”

“bar”

numUsed = 2

7

hash

key

value = 42

LONG next = 2

hash

key

value = 24

LONG next = -1

hash

key

value = 3.141

DOUBLE next = -1

[0] = -1

[1] = 0

[2] = -1

[3] = 1

“foo”

$a = [];$a[“foo”] = 42;$a[“bar”] = 24;$a[“xyz”] = 3.141;

“foo”

“bar”

“bar”

“xyz”

“xyz”

7

hash

key

value

UNDEF next = -1

hash

key

value = 24

LONG next = -1

hash

key

value = 3.141

DOUBLE next = -1

[0] = -1

[1] = 2

[2] = -1

[3] = 1

$a = [];$a[“foo”] = 42;$a[“bar”] = 24;$a[“xyz”] = 3.141;unset($a[“foo”]);

“bar”

“bar”

“xyz”

“xyz”

7

hash

key

value

type_info next

hash

key

value

type_info next

[0]

[1]

[2]

[3]

[4]

[5]

[6]

[7]

7

hash

key

value

type_info next

hash

key

value

type_info next

[0] [1]

[2] [3]

[4] [5]

[6] [7]

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

refcount type_info

data / hash pointer

numUsed

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

refcount type_info

tableMask

data / hash pointer

numUsed

tableSize

tableMask = -tableSize

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

refcount type_info

tableMask

data / hash pointer

numUsed

tableSize

1010111010110110

tableMask = -tableSize

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

refcount type_info

tableMask

data / hash pointer

numUsed

tableSize

1010111010110110| 1111111111100000

tableMask = -tableSize

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

refcount type_info

tableMask

data / hash pointer

numUsed

tableSize

1010111010110110| 1111111111100000= 1111111111110110 = -10

tableMask = -tableSize

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

refcount type_info

tableMask

data / hash pointer

numUsed numElems

tableSize

nextFreeElement

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

refcount type_info

tableMask

data / hash pointer

numUsed numElems

tableSize internalPtr

nextFreeElement

destructor

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

refcount type_info

flags tableMask

data / hash pointer

numUsed numElems

tableSize internalPtr

nextFreeElement

destructor

flags applyCnt iterCnt

7

hash

key

value

type_info next

hash

key

value

type_info next

[-8] [-7]

[-6] [-5]

[-4] [-3]

[-2] [-1]

hash

data

refcount type_info

flags tableMask

data / hash pointer

numUsed numElems

tableSize internalPtr

nextFreeElement

destructor

flags applyCnt iterCnt

PACKEDetc.

7

hash

key

value

type_info next

hash

key

value

type_info next

data

refcount type_info

flags tableMask

data pointer

numUsed numElems

tableSize internalPtr

nextFreeElement

destructor

flags applyCnt iterCnt

PACKEDetc.

5

objects

5

handle (ID)

handlers

zval value

5

handle (ID)

handlers

zval value

handler table

object store bucket

5

handle (ID)

handlers

zval value

read_prop()

write_prop()

object store bucket

5

handle (ID)

handlers

zval value

read_prop()

write_prop()

object

object store bucket

actual object

5

handle (ID)

handlers

zval value

read_prop()

write_prop()

object

refcount

object store bucket

actual object

5

handle (ID)

handlers

zval value

read_prop()

write_prop()

object

dtor()

free_storage()

clone()

refcount

object store bucket

actual object

5

handle (ID)

handlers

zval value

read_prop()

write_prop()

object

dtor()

free_storage()

clone()

handlers

refcount

gc_root

object store bucket

actual object

5

handle (ID)

handlers

zval value

read_prop()

write_prop()

D V ac

object

dtor()

free_storage()

clone()

handlers

refcount

gc_root

object store bucket

actual object

5

object store bucketstandard object

5

object store bucketce

standard object

zend_class_entry

5

object store bucketce

properties

standard object

zend_class_entry

HashTable fordynamic properties

5

object store bucketce

properties

properties_table

standard object

zend_class_entry

HashTable fordynamic properties

[0] (stores $prop1)

[1] (stores $prop2)

[2] (stores $prop3)

zval

zval

zval

5

object store bucketce

properties

properties_table

guards

standard object

zend_class_entry

HashTable fordynamic properties

[0] (stores $prop1)

[1] (stores $prop2)

[2] (stores $prop3)

zval

zval

zval

HashTable for__get etc. guards

5

object store bucketce

properties

properties_table

guards

custom extension

for internal object

standard object

zend_class_entry

HashTable fordynamic properties

[0] (stores $prop1)

[1] (stores $prop2)

[2] (stores $prop3)

zval

zval

zval

HashTable for__get etc. guards

7

zend_object *refcount type_info

ce

properties

zend_class_entry

HashTable fordynamic properties

7

zend_object *refcount type_info

handle

ce

handlers

properties

zend_class_entry

HashTable fordynamic properties

handler table

7

zend_object *refcount type_info

handle

ce

handlers

properties

zend_class_entry

HashTable fordynamic properties

handler table

object store

7

zend_object *refcount type_info

handle

ce

handlers

properties

value

type_info

value

type_info

value

type_info

zend_class_entry

HashTable fordynamic properties$prop1 zval

$prop2 zval

$prop3 zval

handler table

object store

7

zend_object *refcount type_info

handle

ce

handlers

properties

value

type_info

value

type_info

value

type_info

zend_class_entry

HashTable fordynamic properties

HashTable for__get etc. guards

guards zval

$prop1 zval

$prop2 zval

handler table

object store

7

zend_object *refcount type_info

handle

ce

handlers

properties

value

type_info

value

type_info

value

type_info

zend_class_entry

HashTable fordynamic properties

HashTable for__get etc. guards

guards zval

$prop1 zval

$prop2 zval

handler table

object store

ext. for internal objects

7

zend_object *refcount type_info

handle

ce

handlers

properties

value

type_info

value

type_info

value

type_info

zend_class_entry

HashTable fordynamic properties

HashTable for__get etc. guards

guards zval

$prop1 zval

$prop2 zval

handler table

object store

ext. for internal objects offset

7

zend_object *refcount type_info

handle

ce

handlers

properties

value

type_info

value

type_info

value

type_info

guards zval

$prop1 zval

$prop2 zval

object store

ext. for internal objects

offset

handlers table

offset

7

zend_object *refcount type_info

handle

ce

handlers

properties

value

type_info

value

type_info

value

type_info

guards zval

$prop1 zval

$prop2 zval

object store

ext. for internal objects

offset

free()

dtor()

clone()

handlers table

offset

5

references

value = LONG(42)

refcount = 3$i

$j

$k

$i = 42;$j = $i;$k = $i;

5

value = LONG(42)

refcount = 2$i

$k

$i = 42;$j = $i;$k = $i;$k++;

5

value = LONG(43)

refcount = 1

$j

value = LONG(42)

refcount = 2$i

$k

$i = 42;$j = $i;$k = $i;$k++;

5

value = LONG(43)

refcount = 1

$j

copy-on-write (COW)

value = LONG(42)

refcount = 3 is_ref = 1$i

$j

$k

$i = 42;$j =& $i;$k =& $i;

5

value = LONG(43)

refcount = 3 is_ref = 1$i

$j

$k

$i = 42;$j =& $i;$k =& $i;$k++;

5

$i = 42;$j =& $i;$k =& $i;

7

$i value

REFERENCE

$j value

REFERENCE

$k value

REFERENCE

refcount = 3 type_info

value = 42

LONG

zend_reference

$a = range(0,1000000);

$r =& $a;

7

$a value

REFERENCE

$r value

REFERENCE refcount = 2 type_info

value

ARRAY

zend_reference

refcount = 1 type_info

zend_array

$a = range(0,1000000);

$r =& $a;$v = $a;

7

$a value

REFERENCE

$r value

REFERENCE

$v value

ARRAY

refcount = 2 type_info

value

ARRAY

zend_reference

refcount = 2 type_info

zend_array

PHP 5 PHP 7

zval 32 bytes 16 bytes

HashTable element 80 bytes 36 bytes (incl. zval)

HashTable 72 bytes 56 bytes

object 96 bytes 40 bytes

PHP 5 PHP 7

zval 32 bytes 16 bytes

HashTable element 80 bytes 36 bytes (incl. zval)

HashTable 72 bytes 56 bytes

object 96 bytes 40 bytes

fewer allocationsless indirection

PHP 7 Alpha 1June 11th