Top Banner
Static Optimization of PHP Bytecode Nikita Popov
74

Static Optimization of PHP bytecode (PHPSC 2017)

Jan 22, 2018

Download

Technology

Nikita Popov
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Static Optimization of PHP bytecode (PHPSC 2017)

Static Optimizationof

PHP BytecodeNikita Popov

Page 2: Static Optimization of PHP bytecode (PHPSC 2017)

2

154

192 196212

476 486501

0

100

200

300

400

500

PHP 5.3 PHP 5.4 PHP 5.5 PHP 5.6 PHP 7.0 PHP 7.1 PHP 7.2

Req

/ S

ec

Stolen from Rasmus

Wordpress 4.8-alpha @ 20c

Page 3: Static Optimization of PHP bytecode (PHPSC 2017)

3

154

192 196212

476 486501

0

100

200

300

400

500

PHP 5.3 PHP 5.4 PHP 5.5 PHP 5.6 PHP 7.0 PHP 7.1 PHP 7.2

Req

/ S

ec

Stolen from Rasmus

Wordpress 4.8-alpha @ 20c

Page 4: Static Optimization of PHP bytecode (PHPSC 2017)

4

$a = 42;$b = 24;echo $a + $b;

Code

Page 5: Static Optimization of PHP bytecode (PHPSC 2017)

5

ASSIGN $a, 42ASSIGN $b, 24

T0 = ADD $a, $bECHO T0

$a = 42;$b = 24;echo $a + $b;

Compile

CodeOpcodes

Page 6: Static Optimization of PHP bytecode (PHPSC 2017)

6

ASSIGN $a, 42ASSIGN $b, 24

T0 = ADD $a, $bECHO T0

$a = 42;$b = 24;echo $a + $b;

Compile VirtualMachine

Execute

CodeOpcodes

Page 7: Static Optimization of PHP bytecode (PHPSC 2017)

7

ASSIGN $a, 42ASSIGN $b, 24

T0 = ADD $a, $bECHO T0

$a = 42;$b = 24;echo $a + $b;

Compile VirtualMachine

Execute

CodeOpcodes

Optimize

Page 8: Static Optimization of PHP bytecode (PHPSC 2017)

8

ASSIGN $a, 42ASSIGN $b, 24

T0 = ADD $a, $bECHO T0

$a = 42;$b = 24;echo $a + $b;

Compile VirtualMachine

Execute

CodeOpcodes

Optimize

SSA

Page 9: Static Optimization of PHP bytecode (PHPSC 2017)

9

Optimizations

Page 10: Static Optimization of PHP bytecode (PHPSC 2017)

10

$c = $a + $b;

T0 = ADD $a, $bASSIGN $c, T0

Optimizations

Specialization

Page 11: Static Optimization of PHP bytecode (PHPSC 2017)

11

$c = $a + $b;

T0 = ADD $a, $bASSIGN $c, T0

$c = ADD $a, $b

Optimizations

Specialization

Page 12: Static Optimization of PHP bytecode (PHPSC 2017)

12

$c = $a + $b;

T0 = ADD $a, $bASSIGN $c, T0

$c = ADD $a, $b

$c = ADD_INT $a, $b

Optimizations

Specialization

Page 13: Static Optimization of PHP bytecode (PHPSC 2017)

13

$c = $a + $b;

T0 = ADD $a, $bASSIGN $c, T0

$c = ADD $a, $b

$c = ADD_INT $a, $b

$c = ADD_INT_NO_OVERFLOW $a, $b

Optimizations

Specialization

Page 14: Static Optimization of PHP bytecode (PHPSC 2017)

14

Optimizations

Constant Propagation

$a = 2;$b = $a + 1;echo $a * $b;

Page 15: Static Optimization of PHP bytecode (PHPSC 2017)

15

Optimizations

Constant Propagation

$a = 2;$b = 3;echo 6;

Page 16: Static Optimization of PHP bytecode (PHPSC 2017)

16

Optimizations

Constant Propagation & Dead Code Elimination

echo 6;

Page 17: Static Optimization of PHP bytecode (PHPSC 2017)

17

Optimizations

Inlining

Page 18: Static Optimization of PHP bytecode (PHPSC 2017)

18

Optimizations

Inlining

function test() {var_dump(div(4, 2));

}

function div($a, $b) {if ($b == 0) {

return -1;}return $a / $b;

}

Page 19: Static Optimization of PHP bytecode (PHPSC 2017)

19

Optimizations

Inlining

function test() {var_dump(div(4, 2));

}

function div($a, $b) {if ($b == 0) {

return -1;}return $a / $b;

}

function test() {$a = 4;$b = 2;if ($b == 0) {

$retval = -1;goto end;

}$retval = $a / $b;goto end;

end:unset($a, $b);var_dump($retval);

}

Page 20: Static Optimization of PHP bytecode (PHPSC 2017)

20

Optimizations

Inlining + CP

function test() {var_dump(div(4, 2));

}

function div($a, $b) {if ($b == 0) {

return -1;}return $a / $b;

}

function test() {$a = 4;$b = 2;

$retval = 2;goto end;

end:unset($a, $b);var_dump(2);

}

Page 21: Static Optimization of PHP bytecode (PHPSC 2017)

21

Optimizations

Inlining + CP + DCE

function test() {var_dump(div(4, 2));

}

function div($a, $b) {if ($b == 0) {

return -1;}return $a / $b;

}

function test() {

var_dump(2);}

Page 22: Static Optimization of PHP bytecode (PHPSC 2017)

22

SSA Formand

Type Inference

Page 23: Static Optimization of PHP bytecode (PHPSC 2017)

23

$x = 42;if (cond) {

$x = 42.0;var_dump($x);

} else {$x = "42";var_dump($x);

}

var_dump($x);

Static Single Assignment (SSA) Form

Page 24: Static Optimization of PHP bytecode (PHPSC 2017)

24

$x = 42;if (cond) {

$x = 42.0;var_dump($x);

} else {$x = "42";var_dump($x);

}

var_dump($x);

Static Single Assignment (SSA) Form

Type of $x:int|float|string

Page 25: Static Optimization of PHP bytecode (PHPSC 2017)

25

$x = 42;if (cond) {

$x = 42.0;var_dump($x);

} else {$x = "42";var_dump($x);

}

var_dump($x);

Static Single Assignment (SSA) Form

Type of $x here:int

Type of $x here:float

Type of $x here:string

Type of $x here:float|string

Page 26: Static Optimization of PHP bytecode (PHPSC 2017)

26

$x = 42;if (cond) {

$x = 42.0;var_dump($x);

} else {$x = "42";var_dump($x);

}

var_dump($x);

Static Single Assignment (SSA) Form

Page 27: Static Optimization of PHP bytecode (PHPSC 2017)

27

Static Single Assignment (SSA) Form

$x_1 = 42;if (cond) {

$x_2 = 42.0;var_dump($x_2);

} else {$x_3 = "42";var_dump($x_3);

}

var_dump($x_?);

Page 28: Static Optimization of PHP bytecode (PHPSC 2017)

28

Static Single Assignment (SSA) Form

$x_1 = 42;if (cond) {

$x_2 = 42.0;var_dump($x_2);

} else {$x_3 = "42";var_dump($x_3);

}$x_4 = phi($x_2, $x_3);var_dump($x_4);

Page 29: Static Optimization of PHP bytecode (PHPSC 2017)

29

Static Single Assignment (SSA) Form

$x_1 : int

$x_2 : float

$x_3 : string

$x_4 : float|string

$x_1 = 42;if (cond) {

$x_2 = 42.0;var_dump($x_2);

} else {$x_3 = "42";var_dump($x_3);

}$x_4 = phi($x_2, $x_3);var_dump($x_4);

Page 30: Static Optimization of PHP bytecode (PHPSC 2017)

30

Type Inference

$x = 42;do {

$y = $x;$x = $x + 3.14;

} while (cond);

var_dump($y);

Page 31: Static Optimization of PHP bytecode (PHPSC 2017)

31

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

Page 32: Static Optimization of PHP bytecode (PHPSC 2017)

32

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

Page 33: Static Optimization of PHP bytecode (PHPSC 2017)

33

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

$x_1 : int

$x_2 : ∅$y_1 : ∅$x_3 : ∅

Page 34: Static Optimization of PHP bytecode (PHPSC 2017)

34

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

$x_1 : int

$x_2 : ∅$y_1 : ∅$x_3 : ∅

Page 35: Static Optimization of PHP bytecode (PHPSC 2017)

35

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

$x_1 : int

$x_2 : int$y_1 : ∅$x_3 : ∅

Page 36: Static Optimization of PHP bytecode (PHPSC 2017)

36

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

$x_1 : int

$x_2 : int$y_1 : ∅$x_3 : ∅

Page 37: Static Optimization of PHP bytecode (PHPSC 2017)

37

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

$x_1 : int

$x_2 : int$y_1 : int$x_3 : float

Page 38: Static Optimization of PHP bytecode (PHPSC 2017)

38

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

$x_1 : int

$x_2 : int$y_1 : int$x_3 : float

Page 39: Static Optimization of PHP bytecode (PHPSC 2017)

39

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

$x_1 : int

$x_2 : int|float$y_1 : int$x_3 : float

Page 40: Static Optimization of PHP bytecode (PHPSC 2017)

40

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

$x_1 : int

$x_2 : int|float$y_1 : int$x_3 : float

Page 41: Static Optimization of PHP bytecode (PHPSC 2017)

41

Type Inference

$x_1 = 42;do {

$x_2 = phi($x_1, $x_3);$y_1 = $x_2;$x_3 = $x_2 + 3.14;

} while (cond);

var_dump($y_1);

$x_1 : int

$x_2 : int|float$y_1 : int|float$x_3 : float

Page 42: Static Optimization of PHP bytecode (PHPSC 2017)

42

Type Inference

$a = 2**62;$b = 2**62;var_dump($a + $b);// float(9.2233720368548E+18)

Page 43: Static Optimization of PHP bytecode (PHPSC 2017)

43

Type Inference

$a = 2**62;$b = 2**62;var_dump($a + $b);// float(9.2233720368548E+18)

Accurate type inference requires value range inference!

Page 44: Static Optimization of PHP bytecode (PHPSC 2017)

44

Type Inference

$a = 2**62;$b = 2**62;var_dump($a + $b);// float(9.2233720368548E+18)

Accurate type inference requires value range inference!

Same basic concept as type inference,but technically more involved…

Page 45: Static Optimization of PHP bytecode (PHPSC 2017)

45

Optimization obstacles

Page 46: Static Optimization of PHP bytecode (PHPSC 2017)

46

eval()?

variable variables?

Page 47: Static Optimization of PHP bytecode (PHPSC 2017)

47

eval()?

variable variables?

Don't optimize functions using those!

Page 48: Static Optimization of PHP bytecode (PHPSC 2017)

48

function test() {$foobar = 42;func($foobar);var_dump($foobar); // int(42)?

}

References

Page 49: Static Optimization of PHP bytecode (PHPSC 2017)

function func(&$ref) {$ref = 24;

}

function test() {$foobar = 42;func($foobar);var_dump($foobar); // int(42)? nope!

}

49

References

Page 50: Static Optimization of PHP bytecode (PHPSC 2017)

// file1.phpfunction func(&$ref) {

$ref = 24;}

// file2.phpfunction test() {

$foobar = 42;func($foobar);var_dump($foobar); // int(42)? nope!

}

50

References

Page 51: Static Optimization of PHP bytecode (PHPSC 2017)

51

References

Files compiledindependently

// file1.phpfunction func(&$ref) {

$ref = 24;}

// file2.phpfunction test() {

$foobar = 42;func($foobar);var_dump($foobar); // int(42)? nope!

}

Page 52: Static Optimization of PHP bytecode (PHPSC 2017)

52

The devil is in the details…

Page 53: Static Optimization of PHP bytecode (PHPSC 2017)

53

$a = 1;$b = 1;var_dump($a + $b); // ???

Page 54: Static Optimization of PHP bytecode (PHPSC 2017)

54

// file1.php$a = 1;$b = 1;var_dump($a + $b); // ???

// file2.php// EVIL CODE HERErequire 'file1.php';

Page 55: Static Optimization of PHP bytecode (PHPSC 2017)

55

// file1.php$a = 1;$b = 1;var_dump($a + $b); // ???

// file2.php$b = new class {

function __destruct() {$GLOBALS['b'] = 2;

}};require 'file1.php'; // int(3)

Page 56: Static Optimization of PHP bytecode (PHPSC 2017)

56

Pseudo-main scope is a lost cause!

Page 57: Static Optimization of PHP bytecode (PHPSC 2017)

57

function test() {$obj = new stdClass;$obj->prop = 42;// Code not using $obj in any wayvar_dump($obj->prop); // ???

}

Page 58: Static Optimization of PHP bytecode (PHPSC 2017)

58

function test() {$obj = new stdClass;$obj->prop = 42;// Code not using $obj in any wayvar_dump($obj->prop); // ???

}

set_error_handler(function($_1, $_2, $_3, $_4, $scope) {$scope['obj']->prop = "foobar";

});

Page 59: Static Optimization of PHP bytecode (PHPSC 2017)

59

function test() {$obj = new stdClass;$obj->prop = 42;// Code not using $obj in any wayvar_dump($obj->prop); // ???

}

set_error_handler(function($_1, $_2, $_3, $_4, $scope) {$scope['obj']->prop = "foobar";

});

Could generate warning

Page 60: Static Optimization of PHP bytecode (PHPSC 2017)

60

function test() {$obj = new stdClass;$obj->prop = 42;// Code not using $obj in any wayvar_dump($obj->prop); // ???

}

set_error_handler(function($_1, $_2, $_3, $_4, $scope) {$scope['obj']->prop = "foobar";

});

Could generate warning

95% of instructions havesome error condition

Page 61: Static Optimization of PHP bytecode (PHPSC 2017)

61

Object properties (and references)are a lost cause :(

Page 62: Static Optimization of PHP bytecode (PHPSC 2017)

• Constant Propagation, Dead Code Elimination, etc. only really effective with inlining

62

Inlining

Page 63: Static Optimization of PHP bytecode (PHPSC 2017)

• Constant Propagation, Dead Code Elimination, etc. only really effective with inlining

• Inlining only works if callee is known• Only within single file (thanks opcache)

• Non-private/final instance methods can be overridden

63

Inlining

Page 64: Static Optimization of PHP bytecode (PHPSC 2017)

• Constant Propagation, Dead Code Elimination, etc. only really effective with inlining

• Inlining only works if callee is known• Only within single file (thanks opcache)

• Non-private/final instance methods can be overridden

• Backtraces change

64

Inlining

Page 65: Static Optimization of PHP bytecode (PHPSC 2017)

65

Results

Page 66: Static Optimization of PHP bytecode (PHPSC 2017)

66

Results (microbenchmarks)

Page 67: Static Optimization of PHP bytecode (PHPSC 2017)

67

Results (libraries/applications)

• phpseclib RSA enc/dec: 18%

• Aerys Huffman coding: 8%

Page 68: Static Optimization of PHP bytecode (PHPSC 2017)

68

Results (libraries/applications)

• phpseclib RSA enc/dec: 18%

• Aerys Huffman coding: 8%

• WordPress: 3%

• MediaWiki: 1%

Page 69: Static Optimization of PHP bytecode (PHPSC 2017)

69

Type Inference Stats

Page 70: Static Optimization of PHP bytecode (PHPSC 2017)

70

State

• SSA + Type Inference in PHP 7.1

• Specialization in PHP 7.1

Page 71: Static Optimization of PHP bytecode (PHPSC 2017)

71

State

• SSA + Type Inference in PHP 7.1

• Specialization in PHP 7.1

• Inlining, Constant Propagation, DCE, etc. not in PHP 7.1

Page 72: Static Optimization of PHP bytecode (PHPSC 2017)

72

State

• SSA + Type Inference in PHP 7.1

• Specialization in PHP 7.1

• Inlining, Constant Propagation, DCE, etc. not in PHP 7.1

• Currently work underway on dynasm JIT using SSA + type inference framework

Page 73: Static Optimization of PHP bytecode (PHPSC 2017)

73

State

• SSA + Type Inference in PHP 7.1

• Specialization in PHP 7.1

• Inlining, Constant Propagation, DCE, etc. not in PHP 7.1

• Currently work underway on dynasm JIT using SSA + type inference framework

Nikita Popov, Biagio Cosenza, Ben Juurlink, and Dmitry Stogov.Static optimization in PHP 7. In CC'17, pages 65-75. ACM, 2017.http://nikic.github.io/pdf/cc17_static_optimization.pdf

Page 74: Static Optimization of PHP bytecode (PHPSC 2017)

74

@nikita_ppv

https://joind.in/talk/57be5

Questions?