bcompiler: major change proposal
| From: | val khokhlov | Date: | Fri, 17 Sep 2004 21:33:20 +0000 |
| Subject: | bcompiler: major change proposal | ||
| Groups: | php.pecl.dev | ||
| Request: | Send a blank email to pecl-dev+get-1358@lists.php.net to get a copy of this message | ||
Hello All,
As i've told, i have a proposal for major extending/improving
bcompiler. Actually, i've just finished main code and tested it. So, in
brief, how Zend interpreter works:
1) parsing source file and creating opcode array:
EG(active_op_array) = zend_compile_file(file_handle, ZEND_INCLUDE TSRMLS_CC);
2) executing opcodes from this array:
zend_execute(EG(active_op_array) TSRMLS_CC);
That's why there're two ways for bcompiler to work:
1. Current (old) way
We pass steps 1) and 2), got the compiled _and_ already executed
bytecode and write it to file. Of course, we can't write _actual_ bytecode
at this stage, because we simply don't have access to it. We can fetch
_some_ bytecode areas - bytecode for a class, bytecode for a function, a
defined constant. That's why current bcompiler provides such functions, but
don't allow us to store bytecode for the script body
Bytecode restoring is not so simple - we need to manually parse stored
bytecode, restore corresponding structures and insert them to zend internal
data tables (classes, functions, constants). It's _essential_ that we don't
use zend_execute() this way. However, it causes some of compiler's code to
be placed into bcompiler.c (look at the bcompiler_read() function)
2. Proposed (new) way
Main difference is: we pass step 1), but _do not_ execute script, so we
got actual bytecode for it and simply store it. It gives us possibility to
store _whole_ script bytecode (script body, what is of most importance).
Also, we need to add bytecode for functions and classes, declared in the
file - it's not too difficult (except for the derived class, for which the
parent is declared in another file).
Bytecode restoring is _natural_ - we read opcode array and pass it to
zend_execute() function. So, we don't need to simulate zend_execute().
Zend engine will insert all constants, classes and functions to the
corresponding structures.
As i've said, the only difficult thing is adding a derived class, for
which parent is defined in another file. It's because Zend engine delays
inheritance binding until execution stage, but doesn't use class name for the
hash key in class_table. It's *very important* - previous versions of
bcompiler simply didn't store hash key for class in bytecode file. I had to
modify class bytecode structure to include hash key for it. It makes
bytecode incompatible! (Still, i'm going to make multi-version read/write support)
Old-way functions bcompiler_write_*() and New-way bcompiler_write_file()
can co-exist and don't cause any problems. bcompiler_read() and
bcompiler_load() can parse bytecode, but not execute - for executing
bytecode, use include() or require()...
Testing (os: win32; php 4.3.3 command-line):
main achievement - include "1.phb" has the same effect as include "1.php"
<<======================================(test.php)===============
<?
$_a = 2; /* set to 1 to write bytecode, 2 to read it */
dl("php_bcompiler.dll");
/* ------------ write a bytecode */
if ($_a == 1) {
$fh = fopen("1.phb", "w");
bcompiler_write_header($fh);
bcompiler_write_file($fh, "1.php");
bcompiler_write_footer($fh);
fclose($fh);
} else {
/* ------------ include bytecode */
include "1.phb";
}
?>
<<======================================(1.php)===============
<?
define('A', 1);
define('B', 2);
include "11.php";
//class classB { function classB() { echo "bb\n"; } }
function funcA($a1, $a2) { return $a1 + $a2; }
class classA extends classB {
function classA($a1, $a2) { $this->a1 = $a1; $this->a2 = $a2; }
function runA() { return $this->a1 + $this->a2; }
}
echo "func test: ".funcA(A, B)."\n";
$a = new classA(A, B);
$b = new classB();
echo "class test: ".$a->runA()."\n";
echo "parent=".get_parent_class($a)."\n";
$a->classB();
?>
<<======================================(11.php)===============
<?
class classB { function classB() { echo "bb\n"; } }
echo "test11\n";
?>
--
Best regards,
val mailto:val@vk.kiev.ua