0
0
mirror of https://github.com/phpv8/v8js.git synced 2024-12-22 19:51:51 +00:00

Merge branch 'issue-123', closes #123, closes #24

This commit is contained in:
Stefan Siegl 2014-11-16 23:56:04 +01:00
commit 75b7b27587
16 changed files with 226 additions and 37 deletions

6
.gitignore vendored
View File

@ -28,3 +28,9 @@ modules
v8js.la
/run-tests.php
.*.sw[poq]
/tests/*.diff
/tests/*.exp
/tests/*.out
/tests/*.php
/tests/*.sh

125
README.Win32.md Normal file
View File

@ -0,0 +1,125 @@
V8Js on Windows
===============
The V8Js PHP extension is primarily targeted at Unix platforms, especially
GNU/Linux. However it is possible (and supported) to build on Windows, using
Microsoft Visual Studio.
Building with MinGW or Cygwin is not officially supported; mainly since
Google v8 does not support builds on Cygwin (and building it on Cygwin is
currently broken).
Compared to installation on GNU/Linux it's way more tedious to install V8Js
on Windows, since you need to compile PHP with all its dependencies beforehand.
The problem is that Google v8 requires (at least) Visual Studio 2013 as it
uses certain C++11 features not available in Visual Studio 2012.
Unfortunately the [PHP for Windows](http://windows.php.net/) project still
relies on either Visual Studio 2012 or Visual Studio 2008.
It supplies pre-compiled binary archives of required dependencies, however also
compiled with Visual Studio 2008 and 2012 only.
Since it is not compatible to link a v8 compiled with Visual Studio 2013 with
a PHP interpreter compiled with Visual Studio 2012, you need to step up and
compile PHP with Visual Studio 2013. This requires to compile dependencies as
well, if you would like to use certain extensions or e.g. the Apache SAPI.
Compiling v8
------------
The Google v8 project already has excellent step-by-step guide on
[how to build with gyp](https://code.google.com/p/v8-wiki/wiki/BuildingWithGYP).
As a short run through:
* Download and install Python (make sure it adds python.exe to PATH during install)
from http://www.python.org/download/
* Install Git from https://github.com/msysgit/msysgit/releases/download/Git-1.9.4-preview20140929/Git-1.9.4-preview20140929.exe
* Install Subversion from http://sourceforge.net/projects/win32svn/files/latest/download
Then open a command prompt
```
cd \
git clone https://github.com/v8/v8.git
cd v8
svn co http://gyp.googlecode.com/svn/trunk build/gyp
svn co https://src.chromium.org/chrome/trunk/deps/third_party/icu46 third_party/icu
svn co http://src.chromium.org/svn/trunk/tools/third_party/python_26@89111 third_party/python_26
svn co http://src.chromium.org/svn/trunk/deps/third_party/cygwin@66844 third_party/cygwin
svn co http://googletest.googlecode.com/svn/trunk testing/gtest --revision 643
svn co http://googlemock.googlecode.com/svn/trunk testing/gmock --revision 410
python build\gyp_v8 -Dcomponent=shared_library
"\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.com" /build Release build/All.sln
```
(alternatively `start build/all.sln` ... and build within the Visual Studio GUI)
Compiling PHP
-------------
There [Build your own PHP on Windows](https://wiki.php.net/internals/windows/stepbystepbuild)
guide on the PHP wiki. However it concentrates on Visual Studio 2008 and 2012.
Since you need to use Visual Studio 2013 it doesn't apply very well.
This document concentrates on building V8Js for CLI SAPI (only). In order
to enable more extensions you need to provide further dependencies, which may
be more or less cumbersome to build with Visual Studio beforehand.
A quick run through:
* install 7Zip from http://downloads.sourceforge.net/sevenzip/7z920-x64.msi
* create directory \php-sdk
* Download http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip
* ... and unpack to \php-sdk
Open "VS2013 x86 Native Tools Command Prompt"
```
cd \php-sdk
bin\phpsdk_setvars.bat
bin\phpsdk_buildtree.bat phpdev
mkdir vc12
mkdir vc12\x86
mkdir vc12\x86\deps
mkdir vc12\x86\deps\bin
mkdir vc12\x86\deps\include
mkdir vc12\x86\deps\lib
```
* download PHP from http://php.net/get/php-5.5.18.tar.gz/from/a/mirror
and unpack to below `\php-sdk\phpdev\vc12\x86`
* from `\v8\build\Release\lib` copy `icui18n.lib`, `icuuc.lib` and `v8.lib`
to deps\lib folder
* from `\v8\include copy` all v8*.h files to deps\include folder
(still in "VS2013 x86 Native Tools Command Prompt")
```
cd \php-sdk\phpdev\vc12\x86\php-5.5.18\
buildconf
configure --disable-all --enable-cli --with-v8js
nmake
```
After nmake completes the php.exe is in Release_TS\ directory.
In order to try things out in place, copy over `icui18n.dll`, `icuuc.dll` and
`v8.dll` file from `\v8\build\Release` folder to
`\php-sdk\phpdev\vc12\x86\php-5.5.18\Release_TS\` first.
Then run
```
php.exe -d extension=php_v8js.dll -d extension_dir=\php-sdk\phpdev\vc12\x86\php-5.5.18\Release_TS\
```
Alternatively copy all stuff to c:\php\ (including the three DLL files from
v8 build).

View File

@ -33,6 +33,9 @@ repository](https://registry.hub.docker.com/u/stesie/v8js/).
You also might want to try the Debian & Ubuntu packages available from
the Jenkins site at https://jenkins.brokenpipe.de/
Building on Microsoft Windows is more complicated, see README.Win32.md file
for a quick run through.
Compile latest v8
-----------------

View File

@ -7,11 +7,13 @@ if (PHP_V8JS != "no") {
ADD_FLAG("CFLAGS_V8JS", "/EHcs");
ADD_FLAG("CFLAGS_V8JS", "/D _ALLOW_KEYWORD_MACROS");
ADD_FLAG("CFLAGS_V8JS", "/D ZEND_WIN32_FORCE_INLINE");
ADD_FLAG("CFLAGS_V8JS", "/D __STDC_LIMIT_MACROS");
AC_DEFINE("PHP_V8_API_VERSION", "3017015", "", false);
AC_DEFINE("PHP_V8_VERSION", "3.17.15", "", true);
EXTENSION("v8js", "v8js.cc v8js_convert.cc v8js_methods.cc v8js_variables.cc", "yes");
EXTENSION("v8js", "v8js.cc v8js_commonjs.cc v8js_convert.cc v8js_methods.cc v8js_variables.cc", "yes");
} else {
WARNING("v8js not enabled, headers or libs not found");

View File

@ -25,6 +25,12 @@ extern "C" {
#include "php_v8js.h"
}
#ifdef _WIN32
/* On Windows a symbol COMPILER is defined. However v8.h has an enum with that
* name which hence would be broken unless undefined here. */
#undef COMPILER
#endif
#include <v8.h>
#include <chrono>
@ -36,6 +42,14 @@ extern "C" {
#include <vector>
#include <mutex>
#ifndef PATH_MAX
/* Some platforms (Windows among others) don't have a PATH_MAX, for the moment
* just assume an arbitrary upper bound of 4096 chars.
* Anyways we should fix (get rid of) the code that uses PATH_MAX as it doesn't
* even check for buffer overflows. FIXME */
#define PATH_MAX 4096
#endif
/* V8Js Version */
#define V8JS_VERSION "0.1.5"

View File

@ -1,7 +1,12 @@
--TEST--
Test V8Js::setModuleLoader : CommonJS modules
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
<?php
if(!function_exists('json_encode')) {
die('SKIP');
}
require_once(dirname(__FILE__) . '/skipif.inc');
?>
--FILE--
<?php

View File

@ -46,10 +46,10 @@ object(V8Object)#%d (0) {
}
string(55) "Can't access V8Object after V8Js instance is destroyed!"
Warning: Uncaught exception 'V8JsScriptException' with message 'Can't access V8Object after V8Js instance is destroyed!' in %s/tests/ctx_lifetime.php:35
Warning: Uncaught exception 'V8JsScriptException' with message 'Can't access V8Object after V8Js instance is destroyed!' in %s%etests%ectx_lifetime.php:35
Stack trace:
#0 %s/tests/ctx_lifetime.php(35): unknown()
#0 %s%etests%ectx_lifetime.php(35): unknown()
#1 {main}
thrown in %s/tests/ctx_lifetime.php on line 35
thrown in %s%etests%ectx_lifetime.php on line 35
Fatal error: Call to undefined method V8Object::hello() in %s/tests/ctx_lifetime.php on line 35
Fatal error: Call to undefined method V8Object::hello() in %s%etests%ectx_lifetime.php on line 35

View File

@ -24,8 +24,8 @@ $js->executeString($script);
?>
===EOF===
--EXPECTF--
Notice: Undefined variable: bar in %s/fatal_error_ignore_non_fatals.php on line 6
Notice: Undefined variable: bar in %s%efatal_error_ignore_non_fatals.php on line 6
Warning: Foo Bar! in %s/fatal_error_ignore_non_fatals.php on line 7
Warning: Foo Bar! in %s%efatal_error_ignore_non_fatals.php on line 7
blar foo
===EOF===

View File

@ -27,4 +27,4 @@ $js->executeString("PHP.foo();");
--EXPECTF--
nothing.
Fatal error: Call to a member function foo() on %s in %s/fatal_error_no_uninstall_inner_frame.php on line 15
Fatal error: Call to a member function foo() on %s in %s%efatal_error_no_uninstall_inner_frame.php on line 15

View File

@ -23,4 +23,4 @@ $js->executeString($script);
?>
===EOF===
--EXPECTF--
Fatal error: Call to a member function bar() on %s in %s/fatal_error_rethrow.php on line 7
Fatal error: Call to a member function bar() on %s in %s%efatal_error_rethrow.php on line 7

View File

@ -29,4 +29,4 @@ $bar->foo();
--EXPECTF--
nothing.
Fatal error: Call to a member function foo() on %s in %s/fatal_error_uninstall_in_first_frame.php on line 20
Fatal error: Call to a member function foo() on %s in %s%efatal_error_uninstall_in_first_frame.php on line 20

View File

@ -7,8 +7,11 @@ Test V8::executeString() : Time limit
$JS = <<< EOT
var text = "abcdefghijklmnopqrstuvwyxz0123456789";
var memory = "";
for (var i = 0; i < 1000000; ++i) {
memory += text;
for (var i = 0; i < 100; ++i) {
for (var j = 0; j < 10000; ++j) {
memory += text;
}
sleep(0);
}
EOT;

View File

@ -1,7 +1,12 @@
--TEST--
Test V8::executeString() : DOM object passed from PHP
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
<?php
if(!class_exists('DomDocument')) {
die('skip');
}
require_once(dirname(__FILE__) . '/skipif.inc');
?>
--FILE--
<?php

View File

@ -1,7 +1,12 @@
--TEST--
Test V8::executeString() : Check timezone handling
--SKIPIF--
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
<?php
if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
die('SKIP TZ not handled by v8 on Windows');
}
require_once(dirname(__FILE__) . '/skipif.inc');
?>
--FILE--
<?php

25
v8js.cc
View File

@ -21,7 +21,7 @@
#include <v8-debug.h>
#if PHP_V8_API_VERSION >= 3029036
#if !defined(_WIN32) && PHP_V8_API_VERSION >= 3029036
#include <libplatform/libplatform.h>
#endif
@ -478,10 +478,11 @@ static int php_v8js_v8_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) /
cb = v8::Local<v8::Function>::Cast(v8obj->Get(method_name));
}
v8::Local<v8::Value> jsArgv[argc];
v8::Local<v8::Value> *jsArgv = static_cast<v8::Local<v8::Value> *>(alloca(sizeof(v8::Local<v8::Value>) * argc));
v8::Local<v8::Value> js_retval;
for (i = 0; i < argc; i++) {
new(&jsArgv[i]) v8::Local<v8::Value>;
jsArgv[i] = v8::Local<v8::Value>::New(isolate, zval_to_v8js(*argv[i], isolate TSRMLS_CC));
}
@ -676,20 +677,6 @@ static void php_v8js_free_storage(void *object TSRMLS_DC) /* {{{ */
}
c->context.~Persistent();
/* Force garbage collection on our isolate, this is needed that V8 triggers
* our MakeWeak callbacks. Without these we won't remove our references
* on the PHP objects leading to memory leaks in PHP context.
*/
{
v8::Locker locker(c->isolate);
v8::Isolate::Scope isolate_scope(c->isolate);
#if PHP_V8_API_VERSION < 3028036
while(!v8::V8::IdleNotification()) {};
#else
while(!c->isolate->IdleNotification(500)) {};
#endif
}
/* Dispose yet undisposed weak refs */
for (std::map<zval *, v8js_persistent_obj_t>::iterator it = c->weak_objects.begin();
it != c->weak_objects.end(); ++it) {
@ -869,7 +856,7 @@ static void php_v8js_init(TSRMLS_D) /* {{{ */
return;
}
#if PHP_V8_API_VERSION >= 3029036
#if !defined(_WIN32) && PHP_V8_API_VERSION >= 3029036
v8::Platform* platform = v8::platform::CreateDefaultPlatform();
v8::V8::InitializePlatform(platform);
#endif
@ -1133,8 +1120,12 @@ static void php_v8js_timer_thread(TSRMLS_D)
}
// Sleep for 10ms
#ifdef _WIN32
concurrency::wait(10);
#else
std::chrono::milliseconds duration(10);
std::this_thread::sleep_for(duration);
#endif
}
}

View File

@ -471,10 +471,11 @@ static void php_v8js_named_property_enumerator(const v8::PropertyCallbackInfo<v8
// prefix enumerated property names with '$' so they can be
// dereferenced unambiguously (ie, don't conflict with method
// names)
char prefixed[key_len + 1];
char *prefixed = static_cast<char *>(emalloc(key_len + 1));
prefixed[0] = '$';
strncpy(prefixed + 1, key, key_len);
result->Set(result_len++, V8JS_STRL(prefixed, key_len));
efree(prefixed);
} else {
// even numeric indices are enumerated as strings in JavaScript
result->Set(result_len++, V8JS_FLOAT((double) index)->ToString());
@ -492,12 +493,13 @@ static void php_v8js_invoke_callback(const v8::FunctionCallbackInfo<v8::Value>&
v8::Local<v8::Object> self = info.Holder();
v8::Local<v8::Function> cb = v8::Local<v8::Function>::Cast(info.Data());
int argc = info.Length(), i;
v8::Local<v8::Value> argv[argc];
v8::Local<v8::Value> *argv = static_cast<v8::Local<v8::Value> *>(alloca(sizeof(v8::Local<v8::Value>) * argc));
v8::Local<v8::Value> result;
V8JS_TSRMLS_FETCH();
for (i=0; i<argc; i++) {
new(&argv[i]) v8::Local<v8::Value>;
argv[i] = info[i];
}
@ -595,8 +597,9 @@ static void php_v8js_fake_call_impl(const v8::FunctionCallbackInfo<v8::Value>& i
// use php_v8js_php_callback to actually execute the method
v8::Local<v8::Function> cb = PHP_V8JS_CALLBACK(isolate, method_ptr, tmpl);
uint32_t i, argc = args->Length();
v8::Local<v8::Value> argv[argc];
v8::Local<v8::Value> *argv = static_cast<v8::Local<v8::Value> *>(alloca(sizeof(v8::Local<v8::Value>) * argc));
for (i=0; i<argc; i++) {
new(&argv[i]) v8::Local<v8::Value>;
argv[i] = args->Get(i);
}
return_value = cb->Call(info.This(), (int) argc, argv);
@ -1093,6 +1096,10 @@ v8::Handle<v8::Value> zval_to_v8js(zval *value, v8::Isolate *isolate TSRMLS_DC)
case IS_LONG:
v = Z_LVAL_P(value);
/* On Windows there are max and min macros, which would clobber the
* method names of std::numeric_limits< > otherwise. */
#undef max
#undef min
if (v < - std::numeric_limits<int32_t>::min() || v > std::numeric_limits<int32_t>::max()) {
jsValue = V8JS_FLOAT((double)v);
} else {
@ -1142,12 +1149,32 @@ int v8js_to_zval(v8::Handle<v8::Value> jsValue, zval *return_value, int flags, v
{
v8::String::Utf8Value str(jsValue);
const char *cstr = ToCString(str);
/* cstr has two timezone specifications:
*
* example from Linux:
* Mon Sep 08 1975 09:00:00 GMT+0000 (UTC)
*
* example from Windows:
* Mon Sep 08 1975 11:00:00 GMT+0200 (W. Europe Daylight Time)
*
* ... problem is, that PHP can't parse the second timezone
* specification as returned by v8 running on Windows. And as a
* matter of that fails due to inconsistent second timezone spec
*/
char *date_str = estrdup(cstr);
char *paren_ptr = strchr(date_str, '(');
if (paren_ptr != NULL) {
*paren_ptr = 0;
}
zend_class_entry *ce = php_date_get_date_ce();
#if PHP_VERSION_ID < 50304
zval *param;
MAKE_STD_ZVAL(param);
ZVAL_STRING(param, cstr, 1);
ZVAL_STRING(param, date_str, 0);
object_init_ex(return_value, ce TSRMLS_CC);
zend_call_method_with_1_params(&return_value, ce, &ce->constructor, "__construct", NULL, param);
@ -1158,9 +1185,12 @@ int v8js_to_zval(v8::Handle<v8::Value> jsValue, zval *return_value, int flags, v
}
#else
php_date_instantiate(ce, return_value TSRMLS_CC);
if (!php_date_initialize((php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC), (char *) cstr, strlen(cstr), NULL, NULL, 0 TSRMLS_CC)) {
if (!php_date_initialize((php_date_obj *) zend_object_store_get_object(return_value TSRMLS_CC), date_str, strlen(date_str), NULL, NULL, 0 TSRMLS_CC)) {
efree(date_str);
return FAILURE;
}
efree(date_str);
#endif
}
else if (jsValue->IsObject())