hiphop php ã§PHPããã¸ã§ãã¬ã¼ããããC++ã³ã¼ããèªãã§ã¿ããã
PHP advent calendar ã§ãã
ã¯ãªã¹ãã¹éãã¾ãããã© 12/26æ¥ããéããã¾ãã(google docsã«ååæ¸ãå¿ãã¦ãããã ã)
åå 12/25æ¥ã¯ã@yoya ããã®ãWindows で PHP を build するãã§ããã
ä»åã¯ãfacebookの人が作った PHP を C++ に変換して高速動作させるという hiphop php ãã¸ã§ãã¬ã¼ããã C++ ã®ã³ã¼ããèªãã§ã¿ããã¨æãã¾ãã
C++ã¯å³æ ¼ãªéçåã¥ãã®è¨èªã§ãããPHPã¯åçåã¥ãã®è¨èªã§ãã
ãããã©ããã£ã¦ãå¤æãã¦ããã®ãï¼ã¨ãã話ã§ãã
é常ã«é·ããç ã話ã«ãªãã¾ãããå¯ãªãã§èªãã§ããã ãããå¬ããã§ãã
ééããªã©ããã¾ããããã²æãã¦ãã ããã
hiphop php ãå ¥ãããã
ããããhiphop php ãå
¥ããã®ã¯ããã大å¤ã§ãã
Scientific Linux 6.1 (64bit)ã§ã¤ã³ã¹ãã¼ã«ããã¨ãã¯ä»¥ä¸ã®ããã«ãããå
¥ãã¾ããã
#追å ãªãã¸ã㪠rpm -Uvh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm rpm -Uvh http://ftp.iij.ad.jp/pub/linux/fedora/epel/6/x86_64/epel-release-6-5.noarch.rpm #ã¢ãããã¼ãã¨éçºãã¼ã«ã®ã¤ã³ã¹ãã¼ã« yum -y update yum -y groupinstall "Development Tools" #ä¾åããã±ã¼ã¸ã§ yum ã§å ¥ããã®ãå ¥ãã. yum -y --enablerepo=rpmforge,epel install git cmake libssh2 gd gd-devel mysql-server mysql-devel php php-cli php-common php-mbstring php-pear python-devel icu libicu-devel oniguruma oniguruma-devel flex memcached libmemcached bison re2c mysql mysql-devel libxml2 libxml2-devel libmcrypt libmcrypt-devel php-mcrypt openssl binutils binutils-devel libcap libcap-devel gd zlib bzip2 bzip2-libs bzip2-devel pcre pcre-devel expat expat-devel gd gd-devel openldap openldap-devel readline readline-devel libc-client libc-client-devel ncurses ncurses-devel pam pam-devel libmcrypt libmcrypt-devel wget tbb tbb-devel # libmemcache # OSæ¨æºãå¤ãã®ã§ã¢ãããã¼ããã # cd /usr/local/src/ wget http://download.tangent.org/libmemcached-0.43.tar.gz tar -xvf libmemcached-0.43.tar.gz cd libmemcached-0.43 ./configure --prefix=/usr make make install # boost # OSæ¨æºãå¤ãã®ã§æ°ãããã¤ã /usr/ã«ä¸æ¸ãã§ããã # cd /usr/local/src/ wget 'http://sourceforge.net/projects/boost/files/boost/1.48.0/boost_1_48_0.tar.gz/download' tar -xvf boost_1_48_0.tar.gz cd boost_1_48_0 ./bootstrap.sh ./b2 install --prefix=/usr # download hiphop # å ã«ãã¦ã³ãã¼ãããªã㨠patchãæã«å ¥ããªã # cd /usr/local/src/ git clone git://github.com/facebook/hiphop-php.git # install libcurl # ãã¡ã§ã¯ /usr/ã«ä¸æ¸ããã # cd /usr/local/src/ wget http://curl.haxx.se/download/curl-7.20.0.tar.bz2 tar -xvf curl-7.20.0.tar.bz2 cp hiphop-php/src/third_party/libcurl.fb-changes.diff curl-7.20.0/ cd curl-7.20.0 sed -i 's/curl-old\///g' libcurl.fb-changes.diff sed -i 's/curl-new\///g' libcurl.fb-changes.diff patch -p0 < libcurl.fb-changes.diff ./configure --with-ssl --with-zlib --with-libidn --enable-sspi --enable-ldap --enable-ldaps --prefix=/usr make make install # install libevent # ãã¡ã§ã¯ /usr/ã«ä¸æ¸ããã # cd /usr/local/src/ wget http://monkey.org/~provos/libevent-1.4.13-stable.tar.gz tar -xvf libevent-1.4.13-stable.tar.gz cp hiphop-php/src/third_party/libevent-1.4.13.fb-changes.diff libevent-1.4.13-stable/ cd libevent-1.4.13-stable sed -i 's/libevent-1.4.13-stable\///g' libevent-1.4.13.fb-changes.diff sed -i 's/libevent-1.4.13-stable-fb\///g' libevent-1.4.13.fb-changes.diff patch -p0 < libevent-1.4.13.fb-changes.diff ./configure --prefix=/usr make make install ldconfig # install hiphop cd /usr/local/src/ cd hiphop-php/ export HPHP_HOME="/usr/local/src/hiphop-php" export HPHP_LIB="/usr/local/src/hiphop-php/bin" cmake -DCMAKE_PREFIX_PATH=/usr . make make install #export ã§ç°å¢å¤æ°ãå®ç¾©ãã¦ããããã°ã¢ã¦ãããã¨æ¶ããã®ã§æ³¨æã #æ¯åæå¹ã«ããã人ã¯ã ~/.bashrc ã«ã§ãã #ã³ããç¨ export HPHP_HOME="/usr/local/src/hiphop-php" export HPHP_LIB="/usr/local/src/hiphop-php/bin"
åè:http://d.hatena.ne.jp/eth0jp/20101224/1293138303
libevent 㨠curl ã« ããããå½ã¦ãªãã¨ãããªãã®ã§ã¤ã³ã¹ãã¼ã«ããã®ã¯ãªããªã大å¤ã§ãã
æ¢åã®RPMãªã©ããã£ããããã¨ç«¶åãã¦æ¶ç®ã«ãªã£ã¦ãã¾ãã¾ãã
(ãããã¸ããhiphop php ãæ®åããªãçç±ã®ä¸ã¤ãªæ°ããã)
hiphop phpã£ã¦ã©ããããæ©ããªãã®ï¼
è¦å´ãã¦ã¤ã³ã¹ãã¼ã«ããããã§ããããã©ããããæ©ããªããæ°ã«ãªãã¨ããã§ãã
DBã¨ãIOããã¨ããã«å¼ãã¥ããããã§ããã»ã»ã»
ç´ç²ãªå¦çé度ãè¦ã¦ããããã§ããã
ãã£ãããªã®ã§ãèªä½ã® Regexp_Assemble for PHP ã使ã£ã¦é度ãè¦ã¦è¡ãã¾ãããã
Regexp_Assebmle ã¯ãæ£è¦è¡¨ç¾ãä½ã£ã¦ãããã©ã¤ãã©ãªã§ãã
perl の Regexp::AssebmleãPHPã«ç§»æ¤ãããã®ã«ãªãã¾ãã
<?php require_once("Regexp_Assemble.php"); $reg = new Regexp_Assemble(); $reg->add('ãå ã¡ãã'); $reg->add('ãå ã¡ãã¾'); $reg->add('ãã«ã'); $reg->add('ãå æ§'); $reg->add('ãã«ããã¾'); $reg->add('å ä¸æ§'); $reg->add('ã«ããã¾'); $reg->add('ã¢ãã'); $reg->add('å ãã'); $reg->add('å åãã¾'); $reg->add('å ãã£ã'); $reg->add('å ã'); //(?:ã(?:å (?:ã¡ã[ã¾ã]|æ§)|ã«ããã¾)|å (?:ãã£ã|åãã¾|ãã|ä¸æ§|ã)|ã«ããã¾|ãã«ã|ã¢ãã) echo $reg->as_string();
ãã®ããã«ãåèªã追å ããã¨ãããã«å ¨ã¦ãããããæ£è¦è¡¨ç¾ãèªåçã«ä½ã£ã¦ããã¾ãã
æ£è¦è¡¨ç¾ãçæããå¦çã¯ãå¤æ¬¡å
é
åã§ç®¡çããã¦ãããè¤éãªå¦çãCPUã¨ã¡ã¢ãªããã«å転ããã¦å¦çãã¾ãã
éã«diskããããã¯ã¼ã¯ã¸ã®IOãªã©ã¯ã»ã¼ããã¾ããã
ç´ç²ã«å¦çç³»ã®é度ãå³ãããããã®ãã¹ãã«ã¯åãã¦ãããã³ããã¼ã¯ã ã¨æãã¾ãã
以ä¸ã®ãããªãã³ããã¼ã¯ãç¨æãã¾ããã
<?php require_once("Regexp_Assemble.php"); for($i = 0 ; $i < 10000 ; ++$i ) { $reg = new Regexp_Assemble(); $reg->add('ç¥å²¸ããã'); $reg->add('赤座ããã'); $reg->add('é»åº§ããã'); $str = $reg->as_string(); $reg = new Regexp_Assemble(); $reg->add('ã¹ãã£ã¼ãã»ã¸ã§ããº'); $reg->add('ã¹ãã£ã¼ãã»ã¦ã©ãºã¢ããã¯'); $str = $reg->as_string(); $reg = new Regexp_Assemble(); $reg->add('ãå ã¡ãã¾'); $reg->add('ãã«ã'); $reg->add('ãå æ§'); $reg->add('ãã«ããã¾'); $reg->add('å ä¸æ§'); $reg->add('ã«ããã¾'); $reg->add('ã¢ãã'); $reg->add('å ãã'); $reg->add('å åãã¾'); $reg->add('å ãã£ã'); $reg->add('å ã'); $str = $reg->as_string(); }
ãã¦ããã³ããã¼ã¯çµæãè¦ã¦ã¿ã¾ãããã
time php bench_php.php ãªã©ãã¦è¨æ¸¬ããçµæã® real ã®å¤ãè¦ã¦ã¿ã¾ãããã
åä½ã¯ç§ã§ãå°ããã»ã©æ©ãã§ãã
å¦çç³» | é度 |
PHP 5.3.3 | 15.260s |
PHP 5.4RC4 | 11.556s |
PHP 5.4 ã§ãPHPã®é度ãä¸ããã¾ããã
Regexp_Assemble for PHP ã¯ããã®æ©æµãåãã¦ãPHP 5.4RC4 㯠PHP5.3.3ã® 1.32åéã¨ãªãã¾ããã
hiphop php ã使ãã¨ã©ãã¾ã§æ©ããªãã®ã§ããããï¼
å¦çç³» | é度 |
PHP 5.3.3 | 15.260s |
PHP 5.4RC4 | 11.556s |
hiphop php | 5.022s |
hiphop phpã§ãã¤ããªå¤æããããã°ã©ã ããç´æ¥å®è¡ãã¦æ¸¬å®ãã¾ããã
src/hphp/hphp bench_php.php --keep-tempdir=1 --log=3 time /tmp/hphp_MdJIJ2/program --file bench_php.php
hiphop phpæ©ãã§ããã
PHP5.3ã®3åãPHP5.4ã® 2å以ä¸ã®éãã§ãã
ããã¤èµ¤ããªãã®ã«3åãæ©ãã¾ã
hiphop php ã«ãã£ã¦ facebookã®webãµã¼ãã®CPUãã©ãã£ãã¯ãç´50%ãã¼ã»ã³ãåæ¸ããã¨ããã®ã«å½ãã¯ãªãããã§ãã
http://developers.facebook.com/news.php?blog=1&story=358 ã®ç¿»è¨³ http://blog.candycane.jp/archives/275
HipHop for PHPã HipHopã«ããç§ãã¡ã¯ãã¼ã¸ã«ãã£ã¦ã¯ãWebãµã¼ãã¼ä¸ã§ç´50ãã¼ã»ã³ãã®CPU使ç¨éãåæ¸ã§ãã¾ããã CPUã®ä½¿ç¨éã®å°ãªãã¯ããµã¼ãã¼å°æ°ã®åæ¸ã«ã¤ãªãããããã¯ããå°ãªããªã¼ãã¼ããããæå³ãã¾ãã
ããããã©ããã£ããããããªã«é«éã«åä½ããã®ã§ããããï¼
ä½ãéæ³ã§ããããããããããã°ã©ã ã¯éæ³ã§åãã¦ããã®ã§ã¯ãªããè«ç建ã¦ã¦æ¸ãããã½ã¼ã¹ã³ã¼ãã®éãã«åãã¦ãã¾ãã
ã©ããªã½ã¼ã¹ã³ã¼ãã ã¨ãããªã«ãæ©ããªãã®ã§ãããï¼
ä»å㯠hiphop phpãã©ããã£ã¦ã PHPã C++ ã«å¤æãã¦ããã®ãã«ã¤ãã¦ã¿ã¦ããããã¨æãã¾ãã
(ããã¾ã§åãµã)
ãªãã ãã³ã ã¯ãã¾ã
ã¸ã§ãã¬ã¼ããããã³ã¼ããèªããã
hiphop php ãã¤ã³ã¹ãã¼ã«ããã¨ã hphpã³ãã³ã㧠PHP ã C++ ã«å¤æããã³ã³ãã¤ã«ãã¦å®è¡ãã¦ããã¾ãã
-m server ãªãã¸ã§ã³ãä»ããã¨ãèªåãhttpdã«ããªã£ã¦ãwebå¿çãè¿ãã¦ããã¾ãã
hiphop php 㯠/tmp/ 以ä¸ã«ã ãã£ã¬ã¯ããªãä½ã£ã¦ã³ã¼ããåãã¾ãã
ã³ã³ãã¤ã«ãçµããã¨å¤æã®ã½ã¼ã¹ãªã©ã¯æ¶ããã¡ããã®ã§ãåé¤ãããªãããã« --keep-tempdir=1 ãªãã·ã§ã³ãã¤ãã¾ãã
ã¾ããã©ã®ãã³ãã©ãªã«åããããããããªããªãã®ã§ã --log=3 ãªãã·ã§ã³ãã¤ãã¾ãã
src/hphp/hphp test.php --keep-tempdir=1 --log=3
å¤æãããã½ã¼ã¹ã¯ä»¥ä¸ã®ãããªãã£ã¬ã¯ããªæ§æã«ãªã£ã¦ãã¾ãã
åå | å½¹å² |
CMakeFiles | ã¡ã¤ã¯é¢ä¿ãã³ã³ãã¤ã«ããä¸éãã¡ã¤ã«ãªã©ãè¦ãªãã¦ããã |
php | PHPãC++ã«å¤æããã³ã¼ããæ ¼ç´ãããã主æ¦å ´ |
sys | hiphop php ã®ã·ã¹ãã é¢ä¿ã§PHPåä½ã§å¤ãããã®ãã¯ããã¿ããã |
cls | php classãå¤æããçµæãã¯ã©ã¹ãç¡ãæã¯ä½ãããªãã |
ãã以å¤ã«ãã hiphop php èªä½ããã£ã¦ããã©ã³ã¿ã¤ã ãããã¾ãã
ã©ã³ã¿ã¤ã ã¯ãhiphopãã¤ã³ã¹ãã¼ã«ãããã£ã¬ã¯ããªã® src/runtime/ 以ä¸ã«ããã¾ãã
ä»å㯠/usr/local/src/hiphop-php/src/runtime ã«ãªãã¾ãã
ä»åã¯ã phpãã©ã®ããã«å¤æãããããªã®ã§ãphpãã£ã¬ã¯ããªã®ä¸ãè¦ã¦è¡ãã¾ãããã
ããã«ã¯ãPHPã®ãã¡ã¤ã«åã¨ååã® cpp ãããã¾ãã
test.php ã«å¯¾å¿ããã«ã¯ã test.cpp test.h test.fws.h ã§ãã
æ©é hello wolrdããã£ã¦ã¿ã¾ãããã
以ä¸ã®ãã㪠hello worldãç¨æãã¾ããã
<?php echo "hello world";
ã§ã¯ãhiphop php ã§C++ã«å¤æãã¾ãã
src/hphp/hphp test.php --keep-tempdir=1 --log=3
logãªãã·ã§ã³ã«ãã詳細ãªåºåãããã¾ãã
running hphp... creating temporary directory /tmp/hphp_vlzsBB ... parsing inputs... parsing inputs took 0'00" (5 ms) wall time pre-optimizing... pre-optimizing took 0'00" (0 ms) wall time inferring types... inferring types took 0'00" (0 ms) wall time post-optimizing... post-optimizing took 0'00" (0 ms) wall time creating CPP files... creating CPP files took 0'00" (48 ms) wall time compiling and linking CPP files... compiling and linking CPP files took 0'56" (56326 ms) wall time running executable /tmp/hphp_vlzsBB/program --file test.php... hello worldall files saved in /tmp/hphp_vlzsBB ... running hphp took 0'56" (56802 ms) wall time
ãã¦ãã½ã¼ã¹ã³ã¼ããè¦ã¦ã¿ã¾ãããã
å ã®PHPã®ã³ã¼ã test.php
<?php echo "hello world";
hphp_test/php/test.h
#ifndef __GENERATED_php_test_h70588221__ #define __GENERATED_php_test_h70588221__ // Declarations namespace HPHP { /////////////////////////////////////////////////////////////////////////////// // Includes and Functions Variant pm_php$test_php(bool incOnce, LVariableTable* variables, Globals *globals); // Constants /////////////////////////////////////////////////////////////////////////////// } #endif // __GENERATED_php_test_h70588221__
php/test.fws.h
#ifndef __GENERATED_php_test_fws_h1c89c124__ #define __GENERATED_php_test_fws_h1c89c124__ namespace HPHP { /////////////////////////////////////////////////////////////////////////////// // 1. Static Strings extern StaticString s_ss3994978b; // 2. Static Arrays // 3. Static Variants /////////////////////////////////////////////////////////////////////////////// } #endif // __GENERATED_php_test_fws_h1c89c124__
hphp_test/php/test.cpp
#include <runtime/base/hphp.h> #include <sys/literal_strings_remap.h> #include <sys/scalar_arrays_remap.h> #include <sys/scalar_integers_remap.h> #include <sys/global_variables.h> #include <sys/cpputil.h> #include <php/test.fws.h> #include <php/test.h> // Dependencies #include <runtime/ext/ext.h> namespace hphp_impl_starter {} namespace HPHP { /////////////////////////////////////////////////////////////////////////////// /* preface starts */ extern CallInfo ci_; /* preface finishes */ Variant pm_php$test_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test.php, pm_php$test_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; echo(NAMSTR(s_ss3994978b, "hello world")); return true; } namespace hphp_impl_splitter {} /////////////////////////////////////////////////////////////////////////////// }
hello worldã®æååãè¦ãã¾ããã
NAMVARã£ã¦ãã¯ããããã¾ãããããã¯ä½ã§ããããï¼
runtime/base/macros.h ã§ä»¥ä¸ã®ããã«å®ç¾©ããã¦ãã¾ãã
#define NAMVAR(nam, str) (nam)
ãããã¤ã¾ããæååã®æ¹ã¯ãããã°ã«äººéãèªããããã«è²¼ã£ã¦ããã ãã¨ããã ãã§ããã
echo(NAMSTR(s_ss3994978b, "hello world"));
â
âNAMSTR ãã¯ãã§ç½®æ
â
echo(s_ss3994978b);
ãã¯ãç½®æããã¦æ®ã£ã s_ss3994978bã£ã¦ä½ãã§ãããï¼
ããã¯ãphp/test.fws.h ããããã¡ã¤ã«ã«å®ç¾©ãããã¾ãã
hphp_test/php/test.fws.h
extern StaticString s_ss3994978b;
extern ããã¦ãã¾ãããå®æ
ã¯ã©ãã§ãããï¼
sys\literal_strings_0.no.cpp
#include <runtime/base/complex_types.h> #include <sys/literal_strings_remap.h> namespace HPHP { /////////////////////////////////////////////////////////////////////////////// StaticString s_ss3994978b("hello world"); void init_literal_varstrings() { extern void sys_init_literal_varstrings(); sys_init_literal_varstrings(); } /////////////////////////////////////////////////////////////////////////////// }
å®ç¾©ãããã¾ããã
StaticString s_ss3994978b("hello world");
s_ss3994978bã¯ãStaticStringåã§ããã
StaticStringåã¨ã¯ãã©ãããå®ç¾©ãããã¦ããã®ã§ããããï¼
/** * A StaticString can be co-accessed by multiple threads, therefore they are * not thread local, and they have to be allocated BEFORE any thread starts, * so that they won't be garbage collected by MemoryManager. This is used by * constant strings, so they can be pre-allocated before request handling. */ class StaticString : public String { public: static StringDataSet &TheStaticStringSet(); static void FinishInit(); static void ResetAll(); // only supposed to be called during program shutdown public: friend class StringUtil; friend class LiteralStringInitializer; StaticString(litstr s); StaticString(litstr s, int length); // binary string StaticString(std::string s); StaticString(const StaticString &str); ~StaticString() { // prevent ~SmartPtr from calling decRefCount after data is released m_px = NULL; } StaticString& operator=(const StaticString &str); private: void init(litstr s, int length); void insert(); StringData m_data; static StringDataSet *s_stringSet; }; extern const StaticString empty_string;
é¢ç½ãã®ã¯ã std::string ã§ã¯ãªãã¨ãããã¨ã§ãã
ãã¹ã¦èªä½ããªãã¨å«ãªäººãªã®ããªã
class StaticString : public String â class String : public SmartPtr<StringData> â class StringData
ããã§ãããããã¾ããã
ã¤ã¾ããhello world ã®ã³ã¼ãããã£ã¨åç´åãã¦æ¸ãã¨ããããªæãã«ãªãã¾ãã
echo(NAMSTR(s_ss3994978b, "hello world")); â â â StaticString s_ss3994978b("hello world"); echo(s_ss3994978b);
hello world! ããããã£ãæã§ã次ããPHPã®ä¸»è¦ãªæ©è½ãã©ãããC++ã³ã¼ãã«ãªã£ã¦ããããè¦ã¦ãã¾ãã
ããããå
ã¯ãçµæ§é·ããªãã®ã§ããããã¼includeããã¼ã ã¹ãã¼ã¹ãªã©ã®çç¥ãã¦ãã¾ãã
ã¡ããã¨ãããã®ãè¦ããæ¹ã¯ãzipã§ãã¦ã³ãã¼ããã¦ä¸ããã
zipã«ã¯ãä»åã®è¨äºãæ¸ããã調æ»ãããã¼ã¿ä¸å¼ãå
¥ã£ã¦ãã¾ãã
http://rtilabs.net/files/2011_12_25/hphp_test.zip
å¤æ°ã¯ï¼
次ã«å¤æ°ã使ã£ã¦ã¿ã¾ãããã
test8.php
<?php $a = 1; $b = "hello"; $c = 2; $c = "str"; $d = array(); $d[] = 10; $d['ex'] = 20; $d[] = 30; var_dump($a,$b,$c,$d);
hphp_test8/php/test8.fws.h
// 1. Static Strings extern StaticString s_ss27b9150a; extern StaticString s_ssf8576bd5; extern StaticString s_ss5c5509b0; extern StaticString s_ssaa9bf7c4; extern StaticString s_ssd2bea2d3; extern StaticString s_sse6f62137; extern StaticString s_ss8f83bd9c; // 2. Static Arrays extern StaticArray s_sa00000000; // 3. Static Variants extern const VarNR &s_svi542bad8b; extern const VarNR &s_svid7a79683; extern const VarNR &s_svifc87a5f7;
hphp_test8/php/test8.cpp
/* preface starts */ extern CallInfo ci_; /* preface finishes */ Variant pm_php$test8_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test8.php, pm_php$test8_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); Variant &v_b ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ssf8576bd5, "b")) : g->GV(b); Variant &v_c ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss5c5509b0, "c")) : g->GV(c); Variant &v_d ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ssaa9bf7c4, "d")) : g->GV(d); v_a = 1LL; v_b = NAMSTR(s_sse6f62137, "hello"); v_c = 2LL; v_c = NAMSTR(s_ss8f83bd9c, "str"); v_d = s_sa00000000; v_d.append((NAMVAR(s_svi542bad8b, 10LL))); v_d.set(NAMSTR(s_ssd2bea2d3, "ex"), (NAMVAR(s_svid7a79683, 20LL)), true); v_d.append((NAMVAR(s_svifc87a5f7, 30LL))); LINE(14,(x_var_dump(4, v_a, Array(array_createvi(3, toVPOD(v_b), toVPOD(v_c), toVPOD(v_d)))))); return true; }
PHPã®å¤æ°ã¯ãVariantåã§è¡¨ç¾ãã¦ãã¾ãã
Variantã¨ããã°ãåãæããªããªãã§ãå
¥ããããåã®å称ã«ãã使ãããååã§ãã
PHPã®åãæããªãå¤æ°ã表ç¾ããã®ã«é©ããååã ã¨æãã¾ãã
ãã¦ãVariantåã¯ã©ãå®è£ ããã¦ããã®ã§ããããï¼
class Variant { public: friend class Array; friend class VariantVectorBase; /** * Variant does not formally derive from Countable, however it has a * _count field and implements all of the methods from Countable. */ IMPLEMENT_COUNTABLE_METHODS_NO_STATIC ä¸ç¥ /** * Constructors. We can't really use template<T> here, since that will make * Variant being able to take many other external types, messing up those * operator overloads. */ Variant(bool v) : _count(0), m_type(KindOfBoolean) { m_data.num = (v?1:0);} Variant(int v) : _count(0), m_type(KindOfInt32 ) { m_data.num = v;} Variant(int64 v) : _count(0), m_type(KindOfInt64 ) { m_data.num = v;} Variant(uint64 v) : _count(0), m_type(KindOfInt64 ) { m_data.num = v;} Variant(long v) : _count(0), m_type(KindOfInt64 ) { m_data.num = v;} Variant(double v) : _count(0), m_type(KindOfDouble ) { m_data.dbl = v;} ä¸ç¥ };
_count 㨠m_typeãããåç
§ã«ã¦ã³ãããã£ã¦ãã¦ãä½åã管çãããã©ã°ã使ã£ã Variant ã§ããã¨ãããã¨ããããã¾ãã
ããã§ã¯ãC++ ã® boost any ã§ã¯ãªãèªåã§å®è£
ããã¦ãã¾ãããã
ã¾ãã template ã使ã£ã Variant ã§ã¯ãªããæãªããã®ä½åãã®ãã©ã°ãä¿æããVariant ã§å®è£
ããã¦ãã¾ãã
PHP ã® ãã¼ã¿åã¨ã®ç¸æ§ãªã®ã§ããããï¼ ããã¨ããboost any のように template で作る場合 new が発生してしまうã®ã§ããããé¿ããããã§ããããï¼
ç¥ã£ã¦ãã人ããããæãã¦ä¸ããã
ã³ã¼ããæ¯è¼ãã¦ã¿ããã
ãã¦ãã³ã¼ããé·ããªã£ã¦ãã¾ã£ã¦è¦éããæªãã§ããã
PHPã¨C++ã対訳ãã¦æ¯è¼ãã¦ã¿ã¾ãããã
PHP>$a = 1; â C++>v_a = 1LL; PHP>$b = "hello"; â C++>v_b = NAMSTR(s_sse6f62137, "hello"); PHP>$c = 2; PHP>$c = "str"; â C++>v_c = 2LL; C++>v_c = NAMSTR(s_ss8f83bd9c, "str"); PHP>$d = array(); PHP>$d[] = 10; PHP>$d['ex'] = 20; PHP>$d[] = 30; â C++>v_d = s_sa00000000; C++>v_d.append((NAMVAR(s_svi542bad8b, 10LL))); C++>v_d.set(NAMSTR(s_ssd2bea2d3, "ex"), (NAMVAR(s_svid7a79683, 20LL)), true); C++>v_d.append((NAMVAR(s_svifc87a5f7, 30LL)));
ã¿ãã¨ã«PHPã®ã³ã¼ãã Variantåãçã㦠C++ ã§è¡¨ç¾ããã¦ãã¾ãã
é¢ç½ãã§ããã
å¤æ°ãã ãããåãã£ãã¨ããã§ã次ã¯é åå¦çã«ã¤ãã¦è¦ã¦ããã¾ãã
é å
ååã®ã½ã¼ã¹ããé åå¦çã®é¨åãè¦ã¦ã¿ã¾ãããã
PHP>$d = array(); PHP>$d[] = 10; PHP>$d['ex'] = 20; PHP>$d[] = 30; â C++>v_d = s_sa00000000; C++>v_d.append((NAMVAR(s_svi542bad8b, 10LL))); C++>v_d.set(NAMSTR(s_ssd2bea2d3, "ex"), (NAMVAR(s_svid7a79683, 20LL)), true); C++>v_d.append((NAMVAR(s_svifc87a5f7, 30LL)));
対訳ã§è¦ã¦è¡ãã¾ãããã
$d[] = 10;
âã¨ããã³ã¼ãã¯ãappendã¡ã½ããã®å¼ã³åºãã«å¤ããã¾ãããâ
v_d.append((NAMVAR(s_svi542bad8b, 10LL)));
$d['ex'] = 20;
âã¨ããã³ã¼ãã¯ãsetã¡ã½ããã®å¼ã³åºãã«å¤ããã¾ãããâ
v_d.set(NAMSTR(s_ssd2bea2d3, "ex"), (NAMVAR(s_svid7a79683, 20LL)), true);
ã¨ããã§ãæåã®åæåã«å©ç¨ãã¦ãã s_sa00000000 ã¨ã¯ãªããªã®ã§ããããï¼
C++>v_d = s_sa00000000; C++>v_d.append((NAMVAR(s_svi542bad8b, 10LL))); C++>v_d.set(NAMSTR(s_ssd2bea2d3, "ex"), (NAMVAR(s_svid7a79683, 20LL)), true); C++>v_d.append((NAMVAR(s_svifc87a5f7, 30LL)));
s_sa00000000 ã®å®ç¾©ã§ãããphp/test8.fws.h ã§å®ç¾©ããã¦ãã¾ãã
extern StaticArray s_sa00000000;
extern ãªã®ã§ãå®æ
ã¯å¥ã§ãããã ãåã¯ãããã¾ããã
StaticArrayåã§ããStaticArrayåã®å®ç¾©ãè¦ã¦ã¿ã¾ãããã
/** * A StaticArray can be co-accessed by multiple threads, therefore they are * not thread local, and they have to be allocated BEFORE any thread starts, * so that they won't be garbage collected by MemoryManager. This is used by * scalar arrays, so they can be pre-allocated before request handling. */ class StaticArray : public Array { public: StaticArray() { } StaticArray(ArrayData *data) : Array(data) { m_px->setStatic(); m_px->onSetStatic(); } ~StaticArray() { // prevent ~SmartPtr from calling decRefCount after data is released m_px = NULL; } };
å¤æ°ã¯ Variantå ãããã¾ããã StaticArrayåã¯ä½ãããã®ã§ããããï¼
StaticArray ã§è¡ããã¦ããæ©è½ã®ã²ã¨ã¤ã§ãéçã«æ±ºå®ã§ããé
åã®æé©åãããã¾ãã
èªæãªé åã®æé©å
test5.php
<?php $a = array(); $a[] = 0; $a['er'] = 'x'; $a['acx'] = array('oge','hoge'); $a[] = 2; var_dump($a);
ãããC++ã«å¤æããã¨ä»¥ä¸ã®ããã«ãªãã¾ããã
hphp_test5/php/test5.cpp
/* preface starts */ extern CallInfo ci_; /* preface finishes */ Variant pm_php$test5_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test5.php, pm_php$test5_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); v_a = s_sa00000000; v_a.append((NAMVAR(s_svif01bca90, 0LL))); v_a.set(NAMSTR(s_ssfde820e1, "er"), (NAMVAR(s_svse59fa416, "x")), true); v_a.set(NAMSTR(s_ssf04a85df, "acx"), (s_sva905e1b1b), true); v_a.append((NAMVAR(s_svi90d5f98c, 2LL))); LINE(8,(x_var_dump(1, v_a))); return true; }
対訳ã§è¼ãã¦ã¿ã¾ãããã
PHP>$a = array(); C++>v_a = s_sa00000000; PHP>$a[] = 0; C++>v_a.append((NAMVAR(s_svif01bca90, 0LL))); PHP>$a['er'] = 'x'; C++>v_a.set(NAMSTR(s_ssfde820e1, "er"), (NAMVAR(s_svse59fa416, "x")), true); PHP>$a['acx'] = array('oge','hoge'); C++>v_a.set(NAMSTR(s_ssf04a85df, "acx"), (s_sva905e1b1b), true); //ããï¼ PHP>$a[] = 2; C++>v_a.append((NAMVAR(s_svi90d5f98c, 2LL)));
array('oge','hoge'); ã®å§¿ãããã¾ããã
代ããã« s_sva905e1b1b ã¨ããå¤æ°ã«ãªã£ã¦ãã¾ãã
PHP>$a['acx'] = array('oge','hoge'); C++>v_a.set(NAMSTR(s_ssf04a85df, "acx"), (s_sva905e1b1b), true); //ããï¼
array('oge','hoge');ã®ä»£ããã«æ¸ãã¦ãã s_sva905e1b1b ã£ã¦ä½ã§ããããï¼
sys\scalar_arrays.no.cpp
StaticArray s_sa905e1b1b; VarNR s_sva905e1b1b; StaticArray s_sa00000000; void ScalarArrays::initializeNamed() { s_sa905e1b1b = sa_[1]; s_sva905e1b1b = s_sa905e1b1b; s_sa00000000 = sa_[0]; }
åããã©ãã§ããã sa_[1] ã¨ããå¤æ°ã®å¤ã«ãªã£ã¦ãã¾ãã
sa_[1]ã¨ã¯ä½ã§ããããï¼
array('oge','hoge') ãåºå®åãããã¼ã¿ãªã®ã§ãã
ããããã¼ã¿ã«ã¯ gz å§ç¸®ãããã¦ãã¾ãã
sys\scalar_arrays_0.no.cpp
static const char sa_cdata[63] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4b, 0xb4, 0x32, 0xb2, 0xaa, 0xce, 0xb4, 0x32, 0xb0, 0x4e, 0xb4, 0x32, 0xb0, 0xaa, 0xae, 0xcd, 0xb4, 0x32, 0x04, 0xb2, 0xa0, 0x42, 0xc5, 0x56, 0xc6, 0x56, 0x4a, 0xf9, 0xe9, 0xa9, 0x4a, 0xd6, 0x20, 0xe1, 0x62, 0x2b, 0x13, 0x2b, 0xa5, 0x0c, 0x30, 0xb7, 0xb6, 0x16, 0x00, 0x63, 0x28, 0xf5, 0x8a, 0x37, 0x00, 0x00, 0x00, }; StaticArray ScalarArrays::sa_[2]; void ScalarArrays::initialize() { SystemScalarArrays::initialize(); ArrayUtil::InitScalarArrays(sa_, 2, sa_cdata, 63); ScalarArrays::initializeNamed(); }
ArrayUtil::InitScalarArraysã¨ããé¢æ°ã§åæåãã¦ãã¾ããããã®é¢æ°ã®å®ä½ã¯ãããªæãã§ãã
runtime/base/array/array_util.cpp
void ArrayUtil::InitScalarArrays(Array arrs[], int nArrs, const char *scalarArrayData, int scalarArrayDataSize) { int len = scalarArrayDataSize; char *uncompressed = gzdecode(scalarArrayData, len); if (uncompressed == NULL) { throw Exception("Bad scalarArrayData %p", scalarArrayData); } String s = String(uncompressed, len, AttachString); Variant v(f_unserialize(s)); ASSERT(v.isArray()); Array scalarArrays = v; ASSERT(scalarArrays.size() == nArrs); for (int i = 0; i < nArrs; i++) { arrs[i] = scalarArrays[i]; arrs[i].setStatic(); } }
ãã¼ã¿ãPHPã®å½ä»¤ã§ãããgzdecodeã§è§£åãã¦ããã¨æããã¾ãã
hiphopã¯PHPã®å½ä»¤ãèªåã§åå®è£
ãã¦ãããããªã®ã§ãããã®ä½¿ãåãã§ããã
åæåã§1度ã ããã¼ã¿ã解åããã®ã§ãä½è¨ãªCPUã³ã¹ããæããã¾ããããå§ç¸®ãããã¨å®è¡ãã¡ã¤ã«ãå°ãããªãã¡ãªãããããã¾ãã
(ã¨ã¯ãã£ã¦ããhiphopãçæãããã¤ããªã¯å·¨å¤§ã§ããã©ã»ã»ã»)
å¤æ°ã®æååå¼ã³åºã
test13.php
<?php $a = "b"; $b = 20; $c = $$a; var_dump($c);
PHPã«ã¯ã $$a ã®ããã«ãå¤æ°ã®ä¸ã«å
¥ã£ã¦ããæååã表ãã¦ããå¤æ°åã«ã¢ã¯ã»ã¹ãããã¨ãã§ãã¾ãã
ãããè¡ã C++ ã³ã¼ãã¯ã©ããªãã§ããããï¼
hphp_test13/php/test13.cpp
/* preface starts */ extern CallInfo ci_; /* preface finishes */ Variant pm_php$test13_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test13.php, pm_php$test13_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); Variant &v_b ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ssf8576bd5, "b")) : g->GV(b); Variant &v_c ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss5c5509b0, "c")) : g->GV(c); v_a = NAMSTR(s_ssf8576bd5, "b"); v_b = 20LL; v_c.assignVal(variables->get(toString(v_a))); LINE(7,(x_var_dump(1, v_c))); return true; }
variables->get ã¨ããã®ãããã£ã½ãã§ããã
ã³ã¼ãã対訳ããã¦ã¿ã¾ãããã
$c = $$a; â v_c.assignVal(variables->get(toString(v_a)));
variablesã¯ã Variant pm_php$test13_php(bool incOnce, LVariableTable* variables, Globals *globals) ã«ããã¨ããã§ãã
ãã¼ã«ã«å¤æ°ã管çããã¨ãªã¢ã ã¨æããã¾ãã
LVariableTableåã¯ã Arrayããæ´¾çãã¦ããã¯ã©ã¹ã¿ããã§ãã
Arrayããæ´¾çãããã®ã¯ä¾¿å®ä¸ã ã¨ã¯æãã¾ãã
PHPã®å ´åããå¤æ°åããéè¦ã«ãªã£ã¦ããããã$arr[å¤æ°å]=å¤ ã¨ãPHPã®Mapããã¯ã«ä½¿ãã Arrayæ§é ã便å©ã ã£ãããã§ãããã
LVariableTableåã®å®ç¾©ãè¦ã¦ã¿ã¾ãããã
/** * L-value variable table that can get/set a variable's value by its name. The * reason we have both RVariableTable and LVariableTable, instead of just this * one, is because LVariableTable requires all variables to be Variant type, * taking away type inference. If we can tell no dynamic variable was used in * l-value context, we don't have to use LVariableTable. Of course, ideally * even RVariableTable is not needed, meaning no dynamic variable is ever used. */ class LVariableTable : public Array { public: virtual ~LVariableTable() {} Variant &get(CVarRef s) { return getImpl(s.toString()); } Variant &get(CStrRef s) { return getImpl(s); } Variant &get(litstr s) { return getImpl(s);} virtual Variant &getVar(CStrRef s, SuperGlobal sg) { ASSERT(sg == SgNormal); return getImpl(s); } /** * Code-generated sub-class may override this function by generating one * entry per variable. */ virtual bool exists(CStrRef s) const { return Array::exists(s, true); } /** * Code-generated sub-class will implement this function by generating one * entry per variable. */ virtual Variant &getImpl(CStrRef s); virtual Array getDefinedVars(); };
å¤æ°ãã©ã®ããã«å¤æããããã ããããããã¾ããã
次ã¯ãé¢æ°ãã©ã®ããã«æ±ããã¦ããã®ãè¦ã¦ããã¾ãã
é¢æ°
PHPã®é¢æ°ãã©ã®ããã«å¤æããããè¦ã¦ããã¾ãã
test12.php
<?php function myfunc($v) { return $v + 1; } $a = myfunc(3); var_dump($a);
hphp_test12/php/test12.cpp
/* preface starts */ extern CallInfo ci_; extern CallInfo ci_myfunc; /* preface finishes */ /* SRC: test12.php line 3 */ Numeric f_myfunc(CVarRef v_v) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(1, toVPOD(v_v)), r); return (v_v + 1LL); } namespace hphp_impl_splitter {} Variant ifa_myfunc(void *extra, int count, INVOKE_FEW_ARGS_IMPL_ARGS) { if (UNLIKELY(count < 1)) throw_missing_arguments("myfunc", count+1); CVarRef arg0(UNLIKELY(count <= 0) ? null_variant : a0); return (f_myfunc(arg0)); } Variant i_myfunc(void *extra, CArrRef params) { return invoke_func_few_handler(extra, params, &ifa_myfunc); } CallInfo ci_myfunc((void*)&i_myfunc, (void*)&ifa_myfunc, 1, 0, 0x0000000000000000LL); Variant pm_php$test12_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test12.php, pm_php$test12_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); { LINE(8,0); const Numeric &tmp0((f_myfunc(NAMVAR(s_svia6bfbbdd, 3LL)))); v_a.assignVal(tmp0); } LINE(9,(x_var_dump(1, v_a))); return true; }
ããã¶ãé·ã C++ ã³ã¼ãã«ãªãã¾ããã
myfunc ã¨ååã®ã¤ãé¢æ°ã3ã¤ãããã¾ãã
f_myfunc , ifa_myfunc , i_myfunc
ãã ãç´æ¥å¼ã°ãã¦ããã®ã¯ãé¢æ°ã®å®ä½ãæ¸ãã¦ãã f_myfunc ã ãã®ããã§ãã
{ LINE(8,0); const Numeric &tmp0((f_myfunc(NAMVAR(s_svia6bfbbdd, 3LL)))); v_a.assignVal(tmp0); } âââf_myfunc ãå¼ã³åºãââ Numeric f_myfunc(CVarRef v_v) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(1, toVPOD(v_v)), r); return (v_v + 1LL); }
ä»ã¯ä½ã«ä½¿ã£ã¦ããã®ã§ããããï¼ ä»ã¯ããããªãã®ã§ãç½®ãã¨ãã¦å ã«é²ã¿ã¾ãããã
é¢æ°ã®å®ä½ãè¦ã¦ã¿ã¾ãã
Numeric f_myfunc(CVarRef v_v) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(1, toVPOD(v_v)), r); return (v_v + 1LL); }
æ»ãå¤ã Numericåã«ãªã£ã¦ãã¾ãã
ããã¯ãé¢æ°ã®ä¸èº«ãè¦ã¦ãæ»ãå¤ã« intåãè¿ããã¹ãããªãã®ã§æé©åãã¦ããã!!ã¨æãã¾ããããããå®ã¯ããã ã®ã Variant ã® typedef ã§ãã
typedef Variant Numeric;
intå¤ã Variantãçµç±ãããªãã¦ããæ®å¿µã§ãã
intå¤ã2^31ãè¶
ãã¦ãã¾ã£ãã¨ãã« floatåã«å¤æãããã¨ãã® PHP ã®ä»æ§ãé¿ãã¦ããã®ã§ããããï¼
ä»ã®åãè¿ãå ´åã¯ã©ããªãã®ã§ããããï¼
ä»ã®æ¹ãè¿ãé¢æ°ãå®ç¾©ãã¦ã¿ã¦ãæåã観å¯ãã¦ã¿ã¾ãã
æååã®ã¿ãè¿ãé¢æ°
æååã®ã¿ãè¿ãå ´å㯠Stringåã«ãªãã¾ãã
test28.php
<?php function myfunc($x, $v = 1) { return "abc!" . $x . $v; } $a = myfunc(5); var_dump($a);
test28/php/test28.cpp
String f_myfunc(CVarRef v_x, CVarRef v_v // = NAMVAR(s_svib794f8ce, 1LL) ) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(2, toVPOD(v_x), toVPOD(v_v)), r); return concat3(NAMSTR(s_ss34734aeb, "abc!"), toString(v_x), toString(v_v)); }
Stringåã¯ãVariant ã§ã¯ãªããæååãæ ¼ç´ããå°ç¨ã®åã§ãã
runtime/base/type_string.h
class String : public SmartPtr<StringData> { ç¥ }
ç¶æ¿ãã¦ãã StringDataåã¯ãããã¬ãã«ã®ã¯ã©ã¹ã§ãã
class StringData {
ç¥
}
Arrayãè¿ãå ´åã¯
<?php function myfunc($x) { return array($x); } $a = myfunc(5); var_dump($a);
Array f_myfunc(CVarRef v_x) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(1, toVPOD(v_x)), r); return Array(array_createvi(1, toVPOD(v_x))); }
Arrayåã¯ãVariant ã§ã¯ãªããé åãæ ¼ç´ããå°ç¨ã®åã§ãã
class Array : public SmartPtr<ArrayData> { ç¥ }
ç¶æ¿ãã¦ãã ArrayDataåã¯ä»¥ä¸ã®ããã«å®ç¾©ããã¦ãã¾ãã
runtime/base/array/array_data.h
class ArrayData : public Countable { ç¥ }
é¢æ°ãè¿ãå ´å
<?php function myfunc($x) { return function() { return 1; }; } $a = myfunc(5); var_dump($a);
p_Closure f_myfunc(CVarRef v_x) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(1, toVPOD(v_x)), r); return LINE(7,(p_Closure(NEWOBJ(c_Closure)(&ci_07358007151305723156_1, NULL)))); }
é
åãè¿ãå ´åãp_Closure ã¨ããåã«ãªãã¾ãã
ã¯ãã¼ã¸ã£ã®å³å¯ãªå®ç¾©ã¨ã¯ã¡ãã£ã¨éã£ã¦ãããããã§ãããããããååã«ãªã£ã¦ãã¾ãã
p_Closureåã§ãããããã¯ã¡ãã£ã¨ããªããã¼ãªååã¥ãããã£ã¦ããããã§ãã
p_Closureåã®å¤§å
ã®åã c_Closure åã§ãã
FORWARD_DECLARE_CLASS_BUILTIN(Closure); class c_Closure : public ExtObjectData { ç¥ }
ãã®ã¨ããFORWARD_DECLARE_CLASS_BUILTINãã¯ãã«ãã£ã¦ã typedef SmartObject
ãªãã¤ã¼ããgrepãã«ããããããã¼ãã¼æ¸ãæ¹ããã¦ã»ããã§ããã
#define FORWARD_DECLARE_CLASS(cls) \ class c_##cls; \ typedef SmartObject<c_##cls> p_##cls; \ #define FORWARD_DECLARE_CLASS_BUILTIN(cls) \ FORWARD_DECLARE_CLASS(cls) \ extern ObjectData *coo_##cls(); \ extern const ObjectStaticCallbacks cw_##cls;
æååãNULLã帰ãå ´å
<?php function myfunc($x) { if ($x % 2 == 0) { return $x; } return NULL; } $x = myfunc(5); var_dump($x);
Variant f_myfunc(CVarRef v_x) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(1, toVPOD(v_x)), r); if (equal(modulo(toInt64(v_x), 2LL), 0LL)) { { return v_x; } } return null; }
ãã¡ãæ··ã
<?php function myfunc($x) { if ($x % 4 == 0) { return $x; } else if ($x % 3 == 0) { return ""; } return NULL; } $x = myfunc(5); var_dump($x);
Variant f_myfunc(CVarRef v_x) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(1, toVPOD(v_x)), r); if (equal(modulo(toInt64(v_x), 4LL), 0LL)) { { return v_x; } } else if (equal(modulo(toInt64(v_x), 3LL), 0LL)) { { return NAMSTR(s_ss00000000, ""); } } return null; }
ããããªããªã¨ã¼ã·ã§ã³ã帰ãå ´å㯠Variant ã«ãªãã¾ãã
ããã¯å½ç¶ã¨ããã°å½ç¶ã§ããã
æ»ãå¤ãè¿ããªãé¢æ°
æå¾ã«ãæ»ãå¤ãè¿ããªãé¢æ°ã¯ã©ã®ããã«å¤æãããã®ã§ããããï¼
test15.php
<?php function say($str) { echo $str; } say("hello world!");
void f_say(CVarRef v_str) { FUNCTION_INJECTION_NOMEM(say); INTERCEPT_INJECTION("say", array_createvi(1, toVPOD(v_str)), ); echo(toString(v_str)); }
ã¡ããã¨æ»ãå¤ã void åã«ãªãã¾ããã
é¢æ°ã®æ»ãå¤ã®ã¾ã¨ã
å ´å | å | åè |
æ°å¤å | Numeric | Variantã®typedef |
æåå | String | |
é å | Array | |
é¢æ° | p_Closure | typedef SmartObject |
å¥ã®å¤ã¨æ··å | Variant | |
å¤ãè¿ããªã | void |
å°æ¥ã®æé©åã«æå¾
ãããã¨ããã§ãã
é¢æ°ã®ãã£ãã©ã«ãå¼æ°
<?php function myfunc($x, $v = 1) { return $x + $v + 1; } $a = myfunc(5); var_dump($a);
PHP ã«ã¯ã function myfunc($x, $v = 1) ã®ããã«ã ãã£ãã©ã«ãå¼æ°ãã¤ãããã¾ããã
ããã¯ãã©ããªãã®ã§ããããï¼
/* preface finishes */ /* SRC: test14.php line 3 */ Numeric f_myfunc(CVarRef v_x, CVarRef v_v // = NAMVAR(s_svib794f8ce, 1LL) ) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(2, toVPOD(v_x), toVPOD(v_v)), r); return (v_x + (v_v + 1LL)); } namespace hphp_impl_splitter {} Variant ifa_myfunc(void *extra, int count, INVOKE_FEW_ARGS_IMPL_ARGS) { if (UNLIKELY(count < 1)) throw_missing_arguments("myfunc", count+1); CVarRef arg0(UNLIKELY(count <= 0) ? null_variant : a0); CVarRef arg1(count <= 1 ? (NAMVAR(s_svib794f8ce, 1LL)) : a1); return (f_myfunc(arg0, arg1)); } Variant i_myfunc(void *extra, CArrRef params) { return invoke_func_few_handler(extra, params, &ifa_myfunc); } CallInfo ci_myfunc((void*)&i_myfunc, (void*)&ifa_myfunc, 2, 0, 0x0000000000000000LL); Variant pm_php$test14_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test14.php, pm_php$test14_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); { LINE(8,0); const Numeric &tmp0((f_myfunc(NAMVAR(s_svi6a15d700, 5LL)))); v_a.assignVal(tmp0); } LINE(9,(x_var_dump(1, v_a))); return true; }
åååæ§ã myfunc ã¨ããååã®é¢æ°ã3ã¤ä½ããã¦ãã¾ãã
é¢æ°ã®å®æ ãè¦ã¦ã¿ã¾ãããã
Numeric f_myfunc(CVarRef v_x, CVarRef v_v // = NAMVAR(s_svib794f8ce, 1LL) ) { FUNCTION_INJECTION(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(2, toVPOD(v_x), toVPOD(v_v)), r); return (v_x + (v_v + 1LL)); }
第äºå¼æ° v_v ãããã¾ãã
親åã«ãã CVarRef v_v // = NAMVAR(s_svib794f8ce, 1LL) ã¨ãã³ã¡ã³ããæ¯ããã¦ãã¾ãã
ãããã¼ãã¡ã¤ã«ã®æ¹ãã¿ãã¨ãªãã¦ãã¨ã¯ãªãC++ãã£ãã©ã«ãã®å¼æ°ã§ãã
php/test14.h
// Includes and Functions Numeric f_myfunc(CVarRef v_x, CVarRef v_v = NAMVAR(s_svib794f8ce, 1LL)); Variant pm_php$test14_php(bool incOnce, LVariableTable* variables, Globals *globals);
ããã¯ãC++ã®ç¹æ§ã§ããã£ãã©ã«ãå¼æ°ããããã¼ããå®æ
ã®ã©ã¡ããã«ããæ¸ããªãããã§ãã
ã¾ã¼ããã¦ããªãã¨ããã§ãããæ´å²ãé·ãè¨èªã ãã«ä»æ¹ãªãã®ããããã¾ããã
é¢æ°ã®å¼æ°ã®åæå®
åããªãPHPã§ããã arrayåãªã©ã¯é¢æ°ã®å¼æ°ã§åæå®ããããã¨ãã§ãã¾ãã
åãæå®ãããã¨ã§C++ã«å¤æããã³ã¼ããã©ãå¤ãããè¦ã¦ã¿ã¾ãããã
test16.php
<?php function myfunc(array $arr) //arrayã®ã¿ { return $arr[0]; } $a = array(); $a[] = 'a'; $a[] = 'b'; $a[] = 'c'; $b = myfunc($a); var_dump($b);
extern CallInfo ci_myfunc; extern CallInfo ci_; /* preface finishes */ /* SRC: test16.php line 3 */ Variant ft_myfunc(CArrRef v_arr) { FUNCTION_INJECTION_NOMEM(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(1, toVPOD(v_arr)), r); return LINE(5,(v_arr.rvalAt(0LL, AccessFlags::Error))); } Variant f_myfunc(CVarRef v_arr) { if(!v_arr.isArray()) { throw_unexpected_argument_type(1,"myfunc()","Array",v_arr); return null; } return ft_myfunc(v_arr.toCArrRef()); } namespace hphp_impl_splitter {} namespace hphp_impl_splitter {} Variant ifa_myfunc(void *extra, int count, INVOKE_FEW_ARGS_IMPL_ARGS) { if (UNLIKELY(count < 1)) return throw_missing_typed_argument("myfunc", 0, 1); CVarRef arg0(a0); return (f_myfunc(arg0)); } Variant i_myfunc(void *extra, CArrRef params) { return invoke_func_few_handler(extra, params, &ifa_myfunc); } CallInfo ci_myfunc((void*)&i_myfunc, (void*)&ifa_myfunc, 1, 0, 0x0000000000000000LL); Variant pm_php$test16_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test16.php, pm_php$test16_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); Variant &v_b ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ssf8576bd5, "b")) : g->GV(b); v_a = s_sa00000000; v_a.append((NAMVAR(s_svs27b9150a, "a"))); v_a.append((NAMVAR(s_svsf8576bd5, "b"))); v_a.append((NAMVAR(s_svs5c5509b0, "c"))); { LINE(13,0); const Variant &tmp0((f_myfunc(v_a))); v_b.assignVal(tmp0); } LINE(14,(x_var_dump(1, v_b))); return true; }
myfuncã¨ããååã®é¢æ°ã3ã¤ãã1ã¤å¢ãã¦ã4ã¤ã«ãªã£ã¦ãã¾ãã¾ããã
注ç®ãããã®ã¯ã ä»ã¾ã§é¢æ°ã®å®ä½ãå®ç¾©ãã¦ãã f_myfunc ã ft_myfuncã¸å¦çãæãããããã·ã¼ã«ãªã£ãç¹ã§ãã
//ä»ã¾ã§ããã«å®æ ããã£ãã Variant f_myfunc(CVarRef v_arr) { if(!v_arr.isArray()) { throw_unexpected_argument_type(1,"myfunc()","Array",v_arr); return null; } return ft_myfunc(v_arr.toCArrRef()); } //é¢æ°ã®å®ä½ã移åããã Variant ft_myfunc(CArrRef v_arr) { FUNCTION_INJECTION_NOMEM(myfunc); INTERCEPT_INJECTION("myfunc", array_createvi(1, toVPOD(v_arr)), r); return LINE(5,(v_arr.rvalAt(0LL, AccessFlags::Error))); }
f_myfunc 㧠function myfunc(array $arr) ã®åãã§ãã¯ãå
¥ã£ã¦ãã¾ãã¾ããã
åãæå®ãã¦ããããã¨ã§ãä½è¨ãªå¦çãå¢ãã¦ãã¾ãã¾ããããã
åãæ確ã«æ¸ãã¨ãããæé©åãããã½ã¼ã¹ãã¸ã§ãã¬ã¼ãããããã¨æããããä½è¨ãªå¦çãå
¥ã£ã¦é
ããªã£ã¦ãã¾ãã¨ã¯ãç®èãªãã®ã§ãã
PHPã¯åçè¨èªã§ãããåãã§ãã¯ã¯å®è¡æã«è¡ããªããã°ãããªãããã§ãããã¯ä»æ¹ãªãã®ã§ããããã©ãã
ãã ãåãæ確ã«æ¸ãã¨ãããã¨ã¯ãããã°ã©ã ã®å¯èªæ§ãä¿å®æ§ãä¸ãããã¨ã§ãããããããªã«ã¼ãã³ãæã¾ãããã¨è¨ã£ã¦ãåããããªãã¨ããé¸æããããã¨ã¯æããªãã¨ã ã¨æãã¾ãã
åãåé¤ãããã¨ã§æé©åãããæããã£ããããã£ã¨å¥ã®ã¨ãããè¦ç´ãã¹ãã§ãã
çµã¿è¾¼ã¿é¢æ°
PHPã®åè¾¼ã¿é¢æ°ãã©ã®ããã«C++ã«ãªãã®ãè¦ã¦è¡ãã¾ãããã
test9.php
<?php $a = "hello"; $b = strstr($a,"he"); var_dump($a,$b);
// Dependencies #include <runtime/ext/ext.h> ä¸ç¥ /* preface starts */ extern CallInfo ci_; /* preface finishes */ Variant pm_php$test9_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test9.php, pm_php$test9_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); Variant &v_b ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ssf8576bd5, "b")) : g->GV(b); v_a = NAMSTR(s_sse6f62137, "hello"); { LINE(3,0); const Variant &tmp0((x_strstr(toString(v_a), NAMVAR(s_svs546f1cb9, "he")))); v_b.assignVal(tmp0); } LINE(5,(x_var_dump(2, v_a, Array(array_createvi(1, toVPOD(v_b)))))); return true; }
PHPã® strstr ã¯ã x_strstr ã¨ããé¢æ°ã«å¤ããã¾ããã
$b = strstr($a,"he"); ââââ const Variant &tmp0((x_strstr(toString(v_a), NAMVAR(s_svs546f1cb9, "he")))); v_b.assignVal(tmp0);
x_strstrã¨ã¯ä½ã§ããããï¼
runtime/ext/profile/extprofile_string.h
inline Variant x_strstr(CStrRef haystack, CVarRef needle) { FUNCTION_INJECTION_BUILTIN(strstr); TAINT_OBSERVER(TAINT_BIT_MUTATED, TAINT_BIT_NONE); return f_strstr(haystack, needle); }
ããã«ä¾åãã¦ãã f_strstrã£ã¦ãªããªã®ãã
runtime/ext/ext_string.cpp
Variant f_strstr(CStrRef haystack, CVarRef needle) { Variant ret = f_strpos(haystack, needle); if (same(ret, false)) { return false; } return haystack.substr(ret.toInt32()); }
ããã¶ãåããã©ãæ¸ãæ¹ã§ãããããhaystack.substr ã£ã¦ä½ï¼
ãªããCStrRefã¯ã Stringåã® typedef ã§ãã
typedef const String & CStrRef;
ãªã®ã§ãæ¢ãã¹ãã¯ãString::substrã§ãã
String::substr(haystack.substr) ã®å®è£
ãè¦ã¦ã¿ã¾ãããã
String String::substr(int start, int length /* = 0x7FFFFFFF */, bool nullable /* = false */) const { int len = size(); char *ret = string_substr(data(), len, start, length, nullable); if (ret) { return String(ret, len, AttachString); } return String(); }
ã¾ããããã·ã¼ã§ããã
string_substrã£ã¦ä½ï¼
runtime/base/zend/zend_string.cpp
char *string_substr(const char *s, int &len, int start, int length, bool nullable) { ASSERT(s); if (string_substr_check(len, start, length)) { len = length; return string_duplicate(s + start, length); } len = 0; if (nullable) { return NULL; } return string_duplicate("", 0); }
ã«ã¼ãã³ãªãã£ã
å¼ã³åºãå±¥æ´ãè¦ãã¨ãããªæãã§ããï¼
ãªãããã£ã¨å¤§èãªæé©åãæå¾
ããã®ã§ãããã¡ãã£ã¨æ®å¿µã§ãã
ã¾ã ã¾ã æ©ããªãå¯è½æ§ãããã¨ãã©ã¹æèã§ãã¾ãããã
x_strstr â f_strstr â String::substr â string_substr â ã¾ã ç¶ãã®ï¼
ç¡åé¢æ°
PHP5.3 ããç¡åé¢æ°ã¨æç¸(ãã£ããã£)ãå
¥ã£ã¦ã表ç¾åãä¸ããã¾ããã
ã¯ãã¼ã¸ã£ãã«ãªã¼åãã§ããããã«ãªãã¾ããã
以åããevalã create_functionã§ç¡çããã§ãã¦ããã®ãããæ©è½çã«ãªã£ãæãã§ããã
ãã¦ãç¡åé¢æ°ã¯ã©ã®ããã« C++ ã«å¤æããã¦ããã®ã§ããããï¼
test10.php
<?php $func = function($param1) { return $param1 + 1; }; $a = $func(10); var_dump($a);
/* preface starts */ extern CallInfo ci_; extern CallInfo ci_08511066943069959013_1; /* preface finishes */ /* SRC: test10.php line 3 */ Numeric f_08511066943069959013_1(void *extra, CVarRef v_param1) { FUNCTION_INJECTION(08511066943069959013_1); INTERCEPT_INJECTION("08511066943069959013_1", array_createvi(1, toVPOD(v_param1)), r); return (v_param1 + 1LL); } namespace hphp_impl_splitter {} Variant ifa_08511066943069959013_1(void *extra, int count, INVOKE_FEW_ARGS_IMPL_ARGS) { if (UNLIKELY(count < 1)) throw_missing_arguments("08511066943069959013_1", count+1); CVarRef arg0(UNLIKELY(count <= 0) ? null_variant : a0); return (f_08511066943069959013_1(extra, arg0)); } Variant i_08511066943069959013_1(void *extra, CArrRef params) { return invoke_func_few_handler(extra, params, &ifa_08511066943069959013_1); } CallInfo ci_08511066943069959013_1((void*)&i_08511066943069959013_1, (void*)&ifa_08511066943069959013_1, 1, 0, 0x0000000000000000LL); Variant pm_php$test10_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test10.php, pm_php$test10_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_func ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_sse63d8c2d, "func")) : g->GV(func); Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); { LINE(6,0); p_Closure tmp0((p_Closure(NEWOBJ(c_Closure)(&ci_08511066943069959013_1, NULL)))); v_func = tmp0; } { const CallInfo *cit0; void *vt0; get_call_info_or_fail(cit0, vt0, v_func); LINE(8,0); Variant tmp1(((cit0->getFunc1Args())(vt0, 1, 10LL))); v_a.assignVal(tmp1); } LINE(9,(x_var_dump(1, v_a))); return true; }
ç¡åé¢æ°ã¯ãéçãªé¢æ°ã«ãªã£ã¦ãã¾ãã
ããã¦ããããå
ãããããã« p_Closureåã®ã¯ã©ã¹ãããã¾ãã
C++11ãã ç¡åé¢æ°(ã©ã ãå¼)ãC++ã«ãå ãã£ãã®ã§ãhiphop ã®ç»å ´ãããå°ãé
ããã°ãC++11ã®ç¡åé¢æ°(ã©ã ãå¼)ã«ãªã£ã¦ãããããªæ°ããã¾ãã
(ãã㦠boost lambdaã使ãããªãã£ãã®ã¯è¬ã§ãã)
ãã®ãã¨èª¬æããã®ã§ãããç¡åé¢æ°ã¯ã ä»ã¾ã§åä½ãè¬ã ã£ãã ifa_* ã®ååãæã¤é¢æ°ãçµç±ãã¦å®è¡ãããããã§ãã
Variant tmp1(((cit0->getFunc1Args())(vt0, 1, 10LL))); â â â Variant ifa_08511066943069959013_1(void *extra, int count, INVOKE_FEW_ARGS_IMPL_ARGS) { if (UNLIKELY(count < 1)) throw_missing_arguments("08511066943069959013_1", count+1); CVarRef arg0(UNLIKELY(count <= 0) ? null_variant : a0); return (f_08511066943069959013_1(extra, arg0)); } â â â Numeric f_08511066943069959013_1(void *extra, CVarRef v_param1) { FUNCTION_INJECTION(08511066943069959013_1); INTERCEPT_INJECTION("08511066943069959013_1", array_createvi(1, toVPOD(v_param1)), r); return (v_param1 + 1LL); }
æ©éãå¼ã³åºããé ã«è¦ã¦ã¿ã¾ãããã
{ LINE(6,0); p_Closure tmp0((p_Closure(NEWOBJ(c_Closure)(&ci_08511066943069959013_1, NULL)))); v_func = tmp0; }
c_Closure ã¯ã p_Closure ã®å
ã«ãªã£ããã®ã§ãã
typedef SmartObject
å¼æ°ã§æ¸¡ãã¦ãã ci_08511066943069959013_1 ã¨ããã®ã¯ä½ã§ããããï¼
ããã¯ãä¸ã®æ¹ã§å®ç¾©ããã¦ãããCallInfoåã§ãã
CallInfo ci_08511066943069959013_1((void*)&i_08511066943069959013_1, (void*)&ifa_08511066943069959013_1, 1, 0, 0x0000000000000000LL);
é¢æ°ã¸ã®ãã¤ã³ã¿ã渡ãã¦ããããã§ãã
CallInfoã¯ã©ã®ãããªã¯ã©ã¹ãªã®ã§ããããï¼
ã¯ã©ã¹ã®å®ç¾©ãè¦ã¦ã¿ã¾ãããã
runtime/base/builtin_functions.h
class CallInfo { public: enum Flags { VarArgs = 0x1, RefVarArgs = 0x2, Method = 0x4, StaticMethod = 0x8, CallMagicMethod = 0x10, // Special flag for __call handler MixedVarArgs = 0x20, Protected = 0x40, Private = 0x80 }; CallInfo(void *inv, void *invFa, int ac, int flags, int64 refs) : m_invoker(inv), m_invokerFewArgs(invFa), m_argCount(ac), m_flags(flags), m_refFlags(refs) {} void *m_invoker; void *m_invokerFewArgs; // remove in time ãä¸ç¥ã FuncInvoker getFunc() const { return (FuncInvoker)m_invoker; } FuncInvokerFewArgs getFuncFewArgs() const { return (FuncInvokerFewArgs)m_invokerFewArgs; } typedef Variant (*FuncInvoker0Args)( void*, int); typedef Variant (*FuncInvoker1Args)( void*, int, CVarRef); typedef Variant (*FuncInvoker2Args)( void*, int, CVarRef, CVarRef); typedef Variant (*FuncInvoker3Args)( void*, int, CVarRef, CVarRef, CVarRef); typedef Variant (*FuncInvoker4Args)( void*, int, CVarRef, CVarRef, CVarRef, CVarRef); ãä¸ç¥ã typedef Variant (*FuncInvoker10Args)( void*, int, CVarRef, CVarRef, CVarRef, CVarRef, CVarRef, CVarRef, CVarRef, CVarRef, CVarRef, CVarRef); FuncInvoker0Args getFunc0Args() const { return (FuncInvoker0Args)m_invokerFewArgs; } FuncInvoker1Args getFunc1Args() const { return (FuncInvoker1Args)m_invokerFewArgs; } FuncInvoker2Args getFunc2Args() const { return (FuncInvoker2Args)m_invokerFewArgs; } FuncInvoker3Args getFunc3Args() const { return (FuncInvoker3Args)m_invokerFewArgs; } FuncInvoker4Args getFunc4Args() const { return (FuncInvoker4Args)m_invokerFewArgs; } ãä¸ç¥ã FuncInvoker10Args getFunc10Args() const { return (FuncInvoker10Args)m_invokerFewArgs; } ãç¥ã };
ã©ããããCallInfo㯠C++ã®é¢æ°ãã¤ã³ã¿ãçµç±ãã¦ã¦ã¼ã¶ã®é¢æ°ãå¼ã³åºãã¦ããã¿ããã§ããã
ç¡åé¢æ°ãå¼ã³åºãããéç¨ã詳細ã«è¦ã¦ããã¾ãã
//ç¡åé¢æ°ã§å¼ã³åºãé¢æ°ãã»ãããã CallInfo ci_08511066943069959013_1((void*)&i_08511066943069959013_1, (void*)&ifa_08511066943069959013_1, 1, 0, 0x0000000000000000LL); Variant pm_php$test10_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test10.php, pm_php$test10_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_func ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_sse63d8c2d, "func")) : g->GV(func); Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); //ç¡åé¢æ°ã«å²ãå½ã¦ãå¤æ° v_func ã®åæå { LINE(6,0); p_Closure tmp0((p_Closure(NEWOBJ(c_Closure)(&ci_08511066943069959013_1, NULL)))); v_func = tmp0; } //ç¡åé¢æ°ãå®è¡ããçµæã v_a ã«æ ¼ç´ãã { const CallInfo *cit0; void *vt0; get_call_info_or_fail(cit0, vt0, v_func); //cit0 ã« v_func ãç´ä»ãã. LINE(8,0); Variant tmp1(((cit0->getFunc1Args())(vt0, 1, 10LL))); v_a.assignVal(tmp1); } //çµæã var_dump ãã¦è¡¨ç¤º LINE(9,(x_var_dump(1, v_a))); return true; }
ã©ããããã®é¨åã§ç¡åé¢æ°ãå®è¡ãã¦ããããã§ããã
CallInfo::getFunc1Args ã¡ã½ãã ã§ãç¡åé¢æ°ã®é¢æ°ãã¤ã³ã¿ãçµç±ãã¦å®è¡ãã¦ãã¾ãã
Variant tmp1(((cit0->getFunc1Args())(vt0, 1, 10LL)));
ä¸ã«ãã¡ãã£ã¨åºã¦ãã¾ãããã CallInfo::getFunc1Args ã¡ã½ãã ã¯ãé¢æ°ãã¤ã³ã¿ãè¿ãé¢æ°ã«ãªã£ã¦ãã¾ãã
typedef Variant (*FuncInvoker1Args)( void*, int, CVarRef); FuncInvoker1Args getFunc1Args() const { return (FuncInvoker1Args)m_invokerFewArgs; }
å®è¡ãããã¨ããã¾ã§ããããã¾ãã
ãã ãåé¡ãä¸ã¤ããã¾ãã
ããã¯ãã©ã®ããã«ãã¦ã cit0->getFunc1Args() ã« ifa_08511066943069959013_1 é¢æ°ã¸ã®ãã¤ã³ã¿ãæ ¼ç´ãããã§ãã
ç¡åé¢æ°ã®æ
å ±ã¯ v_funcå¤æ°ã«æ ¼ç´ããã¦ãã¾ãã
ä»åãå¼ã³åºãã«ä½¿ã£ã CallInfo* cit0 ã¸ã©ããã£ã¦æ
å ±ã渡ããã®ã§ããããï¼
éµã«ãªãã®ã¯ã get_call_info_or_fail é¢æ°ã§ãã
//ç¡åé¢æ°ãå®è¡ããçµæã v_a ã«æ ¼ç´ãã { const CallInfo *cit0; void *vt0; get_call_info_or_fail(cit0, vt0, v_func); //両è ãç´ä»ãã. LINE(8,0); Variant tmp1(((cit0->getFunc1Args())(vt0, 1, 10LL))); v_a.assignVal(tmp1); }
get_call_info_or_failé¢æ°ã®è©³ç´°ãè¦ã¦ã¿ã¾ãããã
runtime/base/builtin_functions.cpp
void get_call_info_or_fail(const CallInfo *&ci, void *&extra, CVarRef func) { if (UNLIKELY(!get_call_info(ci, extra, func))) { if (func.isObject()) { o_invoke_failed( func.objectForCall()->o_getClassName().c_str(), "__invoke", true); } else { throw InvalidFunctionCallException(func.toString().data()); } } }
ããã£ã±ãªã§get_call_info ã¨ããé¢æ°ãèªãã§ãã¾ãã
runtime/base/builtin_functions.cpp
bool get_call_info(const CallInfo *&ci, void *&extra, CVarRef func) { Variant::TypedValueAccessor tv_func = func.getTypedAccessor(); if (Variant::GetAccessorType(tv_func) == KindOfObject) { ObjectData *d = Variant::GetObjectData(tv_func); ci = d->t___invokeCallInfoHelper(extra); return ci != NULL; } if (LIKELY(Variant::IsString(tv_func))) { StringData *sd = Variant::GetStringData(tv_func); return get_call_info(ci, extra, sd->data(), sd->hash()); } return false; }
ãªãããããã£ã½ãã«ã¼ãã³ã«ãã¾ããã
第ä¸å¼æ° func ã¤ã¾ããv_func ã¨ããç¡åé¢æ°ã®é¢æ°æ
å ±ããã£ã¦ããå¤æ°ã調ã¹ã¦ã 第ä¸å¼æ° ci ã«æ ¼ç´ãã¦ãã¾ãã
ãããã£ã¦ãç¡åé¢æ°ã CallInfo ãªãã¸ã§ã¯ãã«é¢é£ä»ãã¦ãå®è¡ãã¦ããã®ã§ãã
ããããçµæ§åããã©ãé£ã³åºãæ¹ã§ããããã
C++11ãåºããã¨ã§ãããC++11㪠lambdaãçæãã¦æ¬²ãããã®ã§ãã
æç¸(ãã£ããã£)
ç¡åé¢æ°ã§å¤æ°ãæç¸(ãã£ããã£)ãããã¨ãã§ãã¾ãã
ãã£ããã£ã¯ã©ã®ããã«C++ã«å¤æãããã®ã§ããããï¼
test27.php
<?php $cap = 10; $func = function($a) use($cap) { return $a + $cap + 1; }; $c = $func(2); //2 + 10 + 1 var_dump($c);
php/test27.cpp
extern CallInfo ci_; extern CallInfo ci_07296613028076329051_1; FORWARD_DECLARE_CLASS(Closure$07296613028076329051_1); class c_Closure$07296613028076329051_1 : public c_Closure { public: DECLARE_OBJECT_ALLOCATION_NO_SWEEP(c_Closure$07296613028076329051_1) Variant v_cap; c_Closure$07296613028076329051_1(const CallInfo *func, void *extra, CVarRef r_cap) : c_Closure(func, extra) { v_cap.assignVal(r_cap); } }; /* preface finishes */ /* SRC: test27.php line 4 */ Numeric f_07296613028076329051_1(void *extra, CVarRef v_a) { FUNCTION_INJECTION(07296613028076329051_1); INTERCEPT_INJECTION("07296613028076329051_1", array_createvi(1, toVPOD(v_a)), r); c_Closure$07296613028076329051_1 *closure ATTRIBUTE_UNUSED = (c_Closure$07296613028076329051_1*)extra; Variant v_cap; v_cap.assignVal(closure->v_cap); return (v_a + (v_cap + 1LL)); } namespace hphp_impl_splitter {} Variant ifa_07296613028076329051_1(void *extra, int count, INVOKE_FEW_ARGS_IMPL_ARGS) { if (UNLIKELY(count < 1)) throw_missing_arguments("07296613028076329051_1", count+1); CVarRef arg0(UNLIKELY(count <= 0) ? null_variant : a0); return (f_07296613028076329051_1(extra, arg0)); } Variant i_07296613028076329051_1(void *extra, CArrRef params) { return invoke_func_few_handler(extra, params, &ifa_07296613028076329051_1); } CallInfo ci_07296613028076329051_1((void*)&i_07296613028076329051_1, (void*)&ifa_07296613028076329051_1, 1, 0, 0x0000000000000000LL); IMPLEMENT_OBJECT_ALLOCATION_NO_DEFAULT_SWEEP(c_Closure$07296613028076329051_1) Variant pm_php$test27_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test27.php, pm_php$test27_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_cap ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ssf0ead937, "cap")) : g->GV(cap); Variant &v_func ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_sse63d8c2d, "func")) : g->GV(func); Variant &v_c ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss5c5509b0, "c")) : g->GV(c); v_cap = 10LL; { LINE(7,0); p_Closure tmp0((p_Closure$07296613028076329051_1(NEWOBJ(c_Closure$07296613028076329051_1)(&ci_07296613028076329051_1, NULL, v_cap)))); v_func = tmp0; } { const CallInfo *cit0; void *vt0; get_call_info_or_fail(cit0, vt0, v_func); LINE(9,0); Variant tmp1(((cit0->getFunc1Args())(vt0, 1, 2LL))); v_c.assignVal(tmp1); } LINE(10,(x_var_dump(1, v_c))); return true; }
ä¸ããçºãã¦ã¿ã¦ãç¡åé¢æ°ã®æã¨ã®éããè¦ã¦ã¿ã¾ãããã
ç¡åé¢æ°ã«ãªãã£ãã¯ã©ã¹ãçæããã¦ãã¾ãã
FORWARD_DECLARE_CLASS(Closure$07296613028076329051_1); class c_Closure$07296613028076329051_1 : public c_Closure { public: DECLARE_OBJECT_ALLOCATION_NO_SWEEP(c_Closure$07296613028076329051_1) Variant v_cap; c_Closure$07296613028076329051_1(const CallInfo *func, void *extra, CVarRef r_cap) : c_Closure(func, extra) { v_cap.assignVal(r_cap); } };
ç¡åé¢æ°ãæç¸ããå¤æ°ã管çããããã®ã¯ã©ã¹ã ã¨æããã¾ãã
ä»åãã£ããã£ããcapå¤æ°ã£ã½ãååãè¦ãã¾ããã
次ã«ã«ã¼ãã³ãè¦ã¦è¡ãã¾ãããã
v_cap ã¨ããå¤æ°ãp_Closure tmp0 ã®åæåæã«æ¸¡ãã¦ãã¾ãã
ããã§ãã®å¤æ°ã®å¤ããã³ãã¼ãã¦ä¿æãããã¿ããã§ãã
Variant pm_php$test27_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test27.php, pm_php$test27_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_cap ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ssf0ead937, "cap")) : g->GV(cap); Variant &v_func ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_sse63d8c2d, "func")) : g->GV(func); Variant &v_c ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss5c5509b0, "c")) : g->GV(c); v_cap = 10LL; { LINE(7,0); p_Closure tmp0((p_Closure$07296613028076329051_1(NEWOBJ(c_Closure$07296613028076329051_1)(&ci_07296613028076329051_1, NULL, v_cap)))); v_func = tmp0; } { const CallInfo *cit0; void *vt0; get_call_info_or_fail(cit0, vt0, v_func); LINE(9,0); Variant tmp1(((cit0->getFunc1Args())(vt0, 1, 2LL))); v_c.assignVal(tmp1); } LINE(10,(x_var_dump(1, v_c))); return true; }
ãã以å¤ã¯ãç¡åé¢æ°ã®æã¨åãã«æãã¾ãã
get_call_info_or_fail(cit0, vt0, v_func); ã§ãconst CallInfo *cit0; ã«ç¡åé¢æ°ã®é¢æ°ãé¢é£ä»ãã¦ã cit0->getFunc1Args() ãçµç±ãã¦ãå¼ã³åºãã¾ãã
å¼ã³åºãããã¨ãifa_* ç³»ã®é¢æ°ã§ãã ifa_07296613028076329051_1 ãçµç±ãã¦ãç¡åé¢æ°æ¬ä½ãå¼ã³åºããã¾ãã
Variant ifa_07296613028076329051_1(void *extra, int count, INVOKE_FEW_ARGS_IMPL_ARGS) { if (UNLIKELY(count < 1)) throw_missing_arguments("07296613028076329051_1", count+1); CVarRef arg0(UNLIKELY(count <= 0) ? null_variant : a0); return (f_07296613028076329051_1(extra, arg0)); } â Numeric f_07296613028076329051_1(void *extra, CVarRef v_a) { FUNCTION_INJECTION(07296613028076329051_1); INTERCEPT_INJECTION("07296613028076329051_1", array_createvi(1, toVPOD(v_a)), r); c_Closure$07296613028076329051_1 *closure ATTRIBUTE_UNUSED = (c_Closure$07296613028076329051_1*)extra; Variant v_cap; v_cap.assignVal(closure->v_cap); return (v_a + (v_cap + 1LL)); }
ãã®æã void *extra ã«ã¯ããã£ããã£ããcapå¤æ°ã®æ
å ±ãã㤠ã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ãå
¥ãã¾ãã
ããã«ããããã£ããã£ããæ¬æ°ã«ç¡åé¢æ°ãã¢ã¯ã»ã¹ã§ãã¾ãã
ãã£ã¨ãé¢æ°ãçµããã¾ããã
ã¾ã ç ããªãã§ããï¼
ç ããªããªãã次ã¯å¶å¾¡æãè¦ã¦è¡ãã¾ãããã
ifæ
å¶å¾¡æã®ä»£è¡¨æ ¼ IFæãè¦ã¦è¡ãã¾ãããã
test18.php
<?php $a = 10; if ($a == 10 ){ echo "10"; } else { echo "else!"; }
Variant pm_php$test18_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test18.php, pm_php$test18_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); v_a = 10LL; if (equal(v_a, 10LL)) { { echo(NAMSTR(s_ssa4ae39ed, "10")); } } else { { echo(NAMSTR(s_ss2dcad959, "else!")); } } return true;
ããã¯ã綺éºã« C++ã®IFæã«ãªãã¾ããã
æå¥ã®è¨ããããããã¾ããã
PHPã® == æ¯è¼æ¼ç®å㯠equalé¢æ°å¼ã³åºãã«å¤ããã¾ããã
PHPã® == æ¯è¼æ¼ç®åã£ã¦ã¯ã»ãããã®ã§ãåç´ãª C++ ã® ==æ¯è¼æ¼ç®å ã«å¤æã§ããªãã®ãç¡çã¯ããã¾ããã
===æ¼ç®å
PHPãdisã人ãæ¯åæ¯åæ¨çã«ããã¦ãã¦ããã®äººæ°ã«å«å¦¬ããããªã === æ¯è¼æ¼ç®åãè¦ã¦ãã¾ãã
test19.php
<?php $a = 10; if ($a === 10 ){ echo "10"; } else { echo "else!"; }
Variant pm_php$test19_php(bool incOnce, LVariableTable* variables, Globals *globals) { PSEUDOMAIN_INJECTION(run_init::test19.php, pm_php$test19_php); LVariableTable *gVariables ATTRIBUTE_UNUSED = (LVariableTable *)g; Variant &v_a ATTRIBUTE_UNUSED = (variables != gVariables) ? variables->get(NAMSTR(s_ss27b9150a, "a")) : g->GV(a); v_a = 10LL; if (same(v_a, 10LL)) { { echo(NAMSTR(s_ssa4ae39ed, "10")); } } else { { echo(NAMSTR(s_ss2dcad959, "else!")); } } return true; }
è¦ã¦ã®éãã§ãã
PHPã® ===æ¯è¼æ¼ç®åã¯ãsameé¢æ°å¼ã³åºãã«å¤ããã¾ããã
ãªããããã£ããªãã»ã©ç°¡åã§ããã
PHP | hiphop php |
== | equal |
=== | same |
å¾ç·¨ã«ç¶ã
è¨äºãé·ããã¦ããã¬ãã¥ã¼ã§ã¯åé¡ãªãã®ã«ãæ稿ããã¨ãã«ã¶ã£ãåããã¦åãã¦ãã¾ãã¿ããã§ãã
ã¯ã¦ãªãã¤ã¢ãªã¼ã®éçã«æãã§ãããã§ããããã
hiphop php でPHPからジェネレートされたC++コードを読んでみよう(後編)ã«ç¶ãã¾ãã