📜 ⬆️ ⬇️

JPHP - New php engine for Java VM + JIT

I present to you my open-source project - JPHP . This is an alternative PHP implementation for JavaVM with JIT support. I started the project alone in October 2013 and in 4 months I implemented the php compiler into JVM bytecode. The language is supported at the level of PHP 5.3, the capabilities of PHP 5.4 and 5.5 are partially supported. By its ideology, the project resembles JRuby and Jython.

I prepared a small presentation that tells about the project and does not take much of your time:



There is a desire to talk about the project as much as possible, but I'm afraid everything cannot be put in one article. I hope it turned out not too messy.

')


Objective of the project


JPHP is not a replacement for Zend PHP or Facebook HHVM, because the plans did not include the implementation of all the zend php runtime libraries, such as CURL, PRCE, PDO, etc. The main reasons for starting the project were as follows:



Technical details


The entire language is written from scratch in Java using the ASM library to generate bytecode, it is used by all popular jvm languages, for example Groovy. Gradle was chosen as the build system.

To my surprise, the Java technology stack provides very convenient conditions for writing the jvm language. You do not need to write your VM with JIT, the garbage collector and the class system are already implemented, the head does not hurt about cross-platform, and the jvm bytecode itself is very easy to understand. However, there were many pitfalls, most of all because of the magic of the php language itself.

JIT allowed to increase performance by 1-10 times, depending on tests, on average by 1.5-3 times on real code. I also implemented an optimizer that helps make the code even faster.

Compatible with PHP?


It is necessary to distinguish between the language and the library to it, so compatibility at the level of languages ​​and libraries are different things. Already at the beginning of development, I realized that it was impossible for one person to write all the PHP libraries with proper compatibility. I decided to concentrate only on the language, although I implemented basic things such as spl autoloading, Reflection, ob_ * functions, <? ... ?> <? ... ?> and much more.

JPHP passes about 300+ unit tests from the original Zend PHP, including testing OOP, functions, operators, etc. There are also their tests. It helps to ensure that the language works properly. Next, I will list the features that are supported:



On the way implementation of traits from php 5.4.

JIT and performance


What code do you think can affect performance? If you are familiar with Facebook HHVM, then I think you know what. The main problem with PHP performance is the global space for variables, the magic of variables, just magic, when you can access a variable by name at run time. For this reason, JPHP can compile the same code in different ways. Where there is no magic with variables, the compiler converts the variables into indices and, at run time, will immediately refer to them at the index. Let me give you some examples:

 $var = 'foobar'; $x = 'var'; ${$x} = 'chanched'; //   

 $global_var = 100500; include 'file.php'; //  ,  include   global scope   

 function foobar() { $x = 100500; $var = get_defined_vars(); //    } 


Therefore, when it is assumed that variables are accessed by name at run time, JPHP saves a table of variable names, and when it does not, it does not save and refers to variables immediately by indices.

The magic of variables slows down your JPHP code about 2 times. In Zend, PHP code works the same way under any conditions.

Optimizer


The JPHP optimizer does quite a lot, here’s a small list of its features.

1. Constant expressions
 $x = (20 + 30) . 'foobar'; //     1  


2. Static constants
There are constants that JPHP knows at compile time, and there are dynamic constants declared via define . Static is the system constant __FILE__, __DIR__, __CLASS__ , constants java extensions, constants that are declared within the same file through const . All of them can be replaced at compile time:
 include __DIR__ . '/core.php'; //      


3. Immutable functions and methods
These are functions and methods, the result of which is unchanged, or which can be counted once during compilation, they do not affect the global environment and therefore it is safe.

 for ($i = 0; $i < 100500; $i++){ $x = cos(1) + 3; //  1    ,   100500 } 

In this example, the cos () function is system and immutable, and the parameter passed to the function is constant, so the result cos (1) will never change.

The immutable also includes functions / methods declared by the programmer, which have no parameters and return a constant expression. Calling such a function in JPHP is comparable in speed with reference to a constant, for example:

 function getVersion(){ return '1.0'; } $x = getVersion(); //   define('VERSION', '1.0'); $x = VERSION; //    =     


4. Impossible conditions
If in if or else if you have a constant expression that is false, the compiler will drop the extra condition altogether. So far, only if, else and elseif are supported. For example, this can be very useful:

 if (TRACE_ENABLED){ //  TRACE_ENABLED = false,       log("Log text..."); } 


Caching classes, functions, bytecode?


The JPHP work model allows you to store compiled code in memory, i.e. classes and functions. Once compiled and loaded class will be used repeatedly. In the future, this will allow writing http servers, performance frameworks not inferior to Phalcon on PHP itself. Data is easy to store between requests, and the http server can be written on php itself, which I will discuss below.

In JPHP there is a special class Environment that allows you to create isolated environments for executing scripts, this is somewhat similar to a sandbox from the runkit extension. Each such environment has its own set of classes, functions and global variables.



I will use this class in the example below to organize a multi-threaded http server.

How to try? Build a test project?


To do this, you need to install Java (1.6+) and the Gradle build system (1.4+). Download the source from the git repository. JetBrains IDEA allows you to import a project from build.gradle. At this stage there is a test project in the jphp-example-project folder. This project is assembled into an executable jar file, inside which the php sources are located. When starting the jar, the bootstrap.php file is executed. You can build a jar with the command:

 gradle jar 

Or immediately run through:

 gradle exampleStart 


The project is built in the build/libs/ folder in the jar file.

GUI? Programs?


I also wrote a wrapper extension for Swing (Java library for GUI). It allows you to create cross-platform GUI programs. For those who are familiar with Swing, I want to hope - I pretty much simplified api and layouts. A small window on the GUI:

  use php\lang\System; use php\swing\SwingUtilities; use php\swing\UIForm; use php\swing\UIDialog; use php\swing\UIButton; SwingUtilities::invokeLater(function(){ $form = new UIForm(); $form->size = [500, 500]; $form->moveToCenter(); $form->visible = true; $p = new UIButton(); $p->size = [300, 40]; $p->align = 'top'; $p->h = 30; $p->text = ''; $p->on('click', function(){ UIDialog::message('', ''); }); $form->add($p); $form->on('windowClosing', function(){ System::halt(0); }); }); 


Multithreaded HTTP server?


On JPHP you can quite write a multi-threaded http server. For this, I imported the Socket and ServerSokect , as well as the Thread thread classes.

  use php\concurrent\ExecutorService; use php\io\IOException; use php\lang\Environment; use php\net\ServerSocket; $server = new ServerSocket(); $server->bind('localhost', 8080); $service = ExecutorService::newFixedThreadPool(5); // create a thread pool echo "Start HTTP Server on http://localhost:8080/ ...\n"; while (true) { $socket = $server->accept(); echo "Connect client ... \n"; $service->execute(function() use ($socket) { // processing a http request in a thread ob_implicit_flush(true); $out = $socket->getOutput(); try { $out->write("HTTP/1.1 200 OK\r\n"); $out->write("Content-Type: text/html\r\n"); $out->write("Connection: close\r\n\r\n"); $out->write("Hello world!"); $out->flush(); } catch (IOException $e) { echo "Error: " . $e->getMessage(), "\n"; } finally { // JPHP supports `finally` as in PHP 5.5 $socket->shutdownOutput(); } }, new Environment()); } 


Such a server quickly gives content, I tested through the ab utility and the results are impressive. On my machine (Java 7, i3, Windows 7) such a server is able to process 4000-5000 requests per second ( ab -n50000 -c100 localhost ab -n50000 -c100 localhost ) and do not fall.

What's next?


I plan to develop JPHP myself, bring it to release, implement all language features to PHP 5.5. Maybe I'll try to implement compatibility with Android (like Roboto for JRuby). I implement normal extensions based on namespaces and OOP, in part I have already implemented something - streams, sockets, gui, json.

See the rest in the presentation. Thank you for attention.

Source: https://habr.com/ru/post/216651/


All Articles