Save 37% off PRO during our Black Friday Sale! »

From PHP to Machine Code - Vilnius PHP 2015

From PHP to Machine Code - Vilnius PHP 2015

What exactly happens when you run `php example.com`? I wanted to answer this, so I decided to build my own PHP interpreter. Let me tell you what I learned and what does fancy words like opcodes and bytecode cache mean.

With now two main rivals the standard PHP and HHVM from Facebook, there are plenty of choices to run your code fast. But they are both complicated projects, making it hard to understand the inner workings. Rather than relying on them to magically do the right thing, understand the principles of programming languages.

PyHP - https://github.com/juokaz/pyhp

9b1dc79f9ca74e47f98ff5ad9b5c46f3?s=128

Juozas Kaziukėnas

May 07, 2015
Tweet

Transcript

  1. FROM PHP TO MACHINE CODE

  2. hello my name is @JUOKAZ

  3. $>  PHP  EXAMPLE.PHP

  4. None
  5. EVERYONE SHOULD WRITE A COMPILER ONCE, AND THEN NEVER USE

    IT
  6. PyHP

  7. Python + PHP

  8. PYHP • PHP interpreter capable of running “any” PHP program

    • Written in Python • Very fast • Supports most of the basic PHP, except objects
  9. None
  10. EXECUTION LIFECYCLE Parse Compile to Opcodes Execute

  11. PARSE (TOKENIZE) • Parse the source code into labels/tokens •

    Parser uses a grammar file defining the structure of programs (Zend/zend_language_parser.y) • Turn tokens into a tree structure called AST (in PHP since 7.0)
  12. T_OPEN_TAG,  <?php\n,  1   T_WHITESPACE,  \n,  2   T_VARIABLE,  $a,

     3   T_WHITESPACE,  ,  3   =   T_WHITESPACE,  ,  3   T_CONSTANT_ENCAPSED_STRING,  "Hello  world",  3   ;   T_WHITESPACE,  \n\n,  3   T_PRINT,  print,  5   T_WHITESPACE,  ,  5   T_VARIABLE,  $a,  5   ; <?php   $a  =  'Hello  world';   print  $a; token_get_all()
  13. T_WHITESPACE,  \n\n,  3   T_PRINT,  print,  5   T_WHITESPACE,  ,

     5   T_VARIABLE,  $a,  5   ; array(          0:  Stmt_Assign(                  identifier:  Variable(                          identifier:  $a                  )                  expr:  Scalar_String(                          value:  Hello  World                  )          )          1:  Stmt_Echo(                  exprs:  array(                          0:  Variable(                                  identifier:  $a                          )                  )          )   )
  14. COMPILE TO OPCODES • Process tokens into opcodes • Opcode

    represents one operation in the VM, comparable to assembler commands • The result can be cached (“opcode cache”) • Collection of opcodes is called a bytecode • Install VLD extension to dump them or use http://3v4l.org/
  15. filename:              /tmp/example.php   function

     name:    (null)   number  of  ops:    4   compiled  vars:    !0  =  $a   line          #*  E  I  O  op                fetch                    ext    return    operands   -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐        3          0    E  >      ASSIGN                                                                !0,  'Hello+world'        5          1                PRINT                                                  ~1            !0                    2                FREE                                                                    ~1                    3            >  RETURN                                                                1 <?php   $a  =  'Hello  world';   print  $a;
  16. filename:              /tmp/example.php   function

     name:    (null)   number  of  ops:    9   compiled  vars:    !0  =  $a   line          #*  E  I  O  op                fetch                    ext    return    operands   -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐        3          0    E  >      ASSIGN                                                                !0,  'Hello+world'        5          1                IS_EQUAL                                            ~1            !0,  'Wrong'                    2            >  JMPZ                                                                    ~1,  -­‐>6        6          3        >      PRINT                                                  ~2            'ERROR'                    4                FREE                                                                    ~2        7          5            >  JMP                                                                      -­‐>8        8          6        >      PRINT                                                  ~3            !0                    7                FREE                                                                    ~3        9          8        >  >  RETURN                                                                1 <?php   $a  =  'Hello  world';   if  ($a  ==  'Wrong')  {  print  ‘ERROR';  }     else  {  print  $a;  }
  17. EXECUTE (ZEND ENGINE) • Iterate over a list of opcodes

    • Each opcode consumes/emits values, or jumps into a different position • Calling a function and running the main script is almost the same • Zend Engine takes care of memory management and everything else
  18. EXECUTION LOOP function  run(array  $bytecode,  array  $frame)  {    

         $pc  =  0;          while  ($pc  <  count($bytecode))  {                  $op  =  $bytecode[$bc];                  $result  =  $op-­‐>handle($frame);                  if  (isset($result))  {                          return  $result;                  }                  if  ($op  instanceof  Jump)  {                          $pc  =  $op-­‐>jump();                  }  else  {                          $pc++;                  }          }          die('Bytecode  missing  a  RETURN  statement');   }
  19. OPCODES class  Assign  {          function  __construct($variable)

     {                  $this-­‐>name  =  $variable;          }          function  handle($frame)  {                  $value  =  $frame-­‐>popValue();                  $frame-­‐>assignValue($this-­‐>name,  $value);          }   }   class  Return  {          function  handle($frame)  {                  $value  =  $frame-­‐>popValue();                  return  $value;          }   }
  20. CALL OPCODE class  Call  {          function

     __construct($function)  {                  $this-­‐>func  =  $function;          }          function  handle($frame)  {                  $arguments  =  $frame-­‐>popValue();                  $new_frame  =  new  Frame($frame);                  $new_frame-­‐>setArguments($arguments);                  $result  =  $interpreter-­‐>run($this-­‐>func,  $new_frame);                  $frame-­‐>pushValue($result);          }   }
  21. EXTENDING THE LANGUAGE • Modify the grammar file • Implement

    a handler for the new token in the parser • Add the logic for the new AST-node in the opcodes generator • If needed, add the logic for the new opcode in the interpreter
  22. None
  23. PHP IS SLOW

  24. SPECIALIZED CODE IS FAST

  25. SPECIALIZED CODE IS FAST • PHP is slower than C

    because it has to support dynamic code • eval() is the king of dynamic code • Strict typing makes life easier for compilers
  26. AUTOMATIC SPECIALIZATION - JIT

  27. JIT • Just-in-time compiler (Standard PHP is a AOT, Ahead-

    of-time, compiler) • Slower to start, likely very fast after N executions • Compiles code to machine code on execution • Re-compile “hot” code based on runtime information
  28. PyHP

  29. PYHP • Uses the PyPy/RPython technology stack • JIT support

    • Unit tested • Compiles in 10min
  30. WHY? • PHP is written in C, hard to play

    around with • Impossible to learn by looking at existing interpreters • Implement any new feature in a matter of minutes
  31. THINGS TO TRY • PHPPHP - A PHP VM implementation

    in PHP (https://github.com/ircmaxell/PHPPHP) • PyHP - A PHP VM implementation in Python (https://github.com/juokaz/pyhp) • HHVM - High-peformance PHP interpreter with JIT (http://hhvm.com/)
  32. None
  33. WHAT’S NEXT?

  34. PyHP.JS

  35. (PYTHON + JAVASCRIPT) + PHP

  36. https://www.destroyallsoftware.com/talks/the-birth-and- death-of-javascript

  37. QUESTIONS?

  38. THANKS! Juozas Kaziukėnas @juokaz