From 97cc819adec87537928e83ea7e56ee94f84a57e6 Mon Sep 17 00:00:00 2001 From: Albert Date: Thu, 3 Jun 2021 09:33:51 +0800 Subject: [PATCH 01/64] support php8 --- v8js_array_access.cc | 4 + v8js_class.cc | 55 +++- v8js_class.h | 5 + v8js_convert.cc | 4 + v8js_exceptions.cc | 22 +- v8js_methods.cc | 9 + v8js_object_export.cc | 17 +- v8js_v8.h | 5 + v8js_v8object_class.cc | 652 +++++++++++++++++++++++++++++++---------- v8js_v8object_class.h | 2 +- 10 files changed, 619 insertions(+), 156 deletions(-) diff --git a/v8js_array_access.cc b/v8js_array_access.cc index 7c5218a0..3151781c 100644 --- a/v8js_array_access.cc +++ b/v8js_array_access.cc @@ -50,7 +50,11 @@ static zval v8js_array_access_dispatch(zend_object *object, const char *method_n fci.params = params; fci.object = object; +#if (PHP_MAJOR_VERSION < 8) fci.no_separation = 0; +#else + fci.named_params = NULL; +#endif zend_call_function(&fci, NULL); zval_dtor(&fci.function_name); diff --git a/v8js_class.cc b/v8js_class.cc index 4e9be672..95768987 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -506,7 +506,11 @@ static PHP_METHOD(V8Js, __construct) V8JS_GLOBAL(isolate)->DefineOwnProperty(context, object_name_js, php_obj, v8::ReadOnly); /* Export public property values */ + #if (PHP_MAJOR_VERSION < 8) HashTable *properties = zend_std_get_properties(getThis()); + #else + HashTable *properties = zend_std_get_properties(Z_OBJ_P(getThis())); + #endif zval *value; zend_string *member; @@ -665,7 +669,6 @@ static void v8js_compile_script(zval *this_ptr, const zend_string *str, const ze static void v8js_execute_script(zval *this_ptr, v8js_script *res, long flags, long time_limit, size_t memory_limit, zval **return_value) { v8js_ctx *c = Z_V8JS_CTX_OBJ_P(this_ptr); - if (res->ctx != c) { zend_error(E_WARNING, "Script resource from wrong V8Js object passed"); ZVAL_BOOL(*return_value, 0); @@ -1306,7 +1309,33 @@ const zend_function_entry v8js_methods[] = { /* {{{ */ /* V8Js object handlers */ +#if PHP_VERSION_ID >= 80000 +static SINCE74(zval*, void) v8js_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot) /* {{{ */ +{ + v8js_ctx *c = Z_V8JS_CTX_OBJ(object); + V8JS_CTX_PROLOGUE_EX(c, SINCE74(value,)); + + /* Check whether member is public, if so, export to V8. */ + zend_property_info *property_info = zend_get_property_info(c->std.ce, member, 1); + if(!property_info || + (property_info != ZEND_WRONG_PROPERTY_INFO && + (property_info->flags & ZEND_ACC_PUBLIC))) { + /* Global PHP JS object */ + v8::Local object_name_js = v8::Local::New(isolate, c->object_name); + v8::Local jsobj = V8JS_GLOBAL(isolate)->Get(v8_context, object_name_js).ToLocalChecked()->ToObject(v8_context).ToLocalChecked(); + + if (ZSTR_LEN(member) > std::numeric_limits::max()) { + zend_throw_exception(php_ce_v8js_exception, + "Property name exceeds maximum supported length", 0); + return SINCE74(value,); + } + + /* Write value to PHP JS object */ + v8::Local key = V8JS_SYML(ZSTR_VAL(member), static_cast(ZSTR_LEN(member))); + jsobj->DefineOwnProperty(v8_context, key, zval_to_v8js(value, isolate), v8::ReadOnly); + } +#else static SINCE74(zval*, void) v8js_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */ { v8js_ctx *c = Z_V8JS_CTX_OBJ_P(object); @@ -1314,6 +1343,7 @@ static SINCE74(zval*, void) v8js_write_property(zval *object, zval *member, zval /* Check whether member is public, if so, export to V8. */ zend_property_info *property_info = zend_get_property_info(c->std.ce, Z_STR_P(member), 1); + if(!property_info || (property_info != ZEND_WRONG_PROPERTY_INFO && (property_info->flags & ZEND_ACC_PUBLIC))) { @@ -1331,12 +1361,31 @@ static SINCE74(zval*, void) v8js_write_property(zval *object, zval *member, zval v8::Local key = V8JS_SYML(Z_STRVAL_P(member), static_cast(Z_STRLEN_P(member))); jsobj->DefineOwnProperty(v8_context, key, zval_to_v8js(value, isolate), v8::ReadOnly); } +#endif /* Write value to PHP object */ SINCE74(return,) std_object_handlers.write_property(object, member, value, NULL); } /* }}} */ +#if PHP_VERSION_ID >= 80000 +static void v8js_unset_property(zend_object *object, zend_string *member, void **cache_slot) /* {{{ */ +{ + V8JS_BEGIN_CTX_OBJ(c, object) + + /* Global PHP JS object */ + v8::Local object_name_js = v8::Local::New(isolate, c->object_name); + v8::Local jsobj = V8JS_GLOBAL(isolate)->Get(v8_context, object_name_js).ToLocalChecked()->ToObject(v8_context).ToLocalChecked(); + + if (ZSTR_LEN(member) > std::numeric_limits::max()) { + zend_throw_exception(php_ce_v8js_exception, + "Property name exceeds maximum supported length", 0); + return; + } + + /* Delete value from PHP JS object */ + v8::Local key = V8JS_SYML(ZSTR_VAL(member), static_cast(ZSTR_LEN(member))); +#else static void v8js_unset_property(zval *object, zval *member, void **cache_slot) /* {{{ */ { V8JS_BEGIN_CTX(c, object) @@ -1346,13 +1395,15 @@ static void v8js_unset_property(zval *object, zval *member, void **cache_slot) / v8::Local jsobj = V8JS_GLOBAL(isolate)->Get(v8_context, object_name_js).ToLocalChecked()->ToObject(v8_context).ToLocalChecked(); if (Z_STRLEN_P(member) > std::numeric_limits::max()) { - zend_throw_exception(php_ce_v8js_exception, + zend_throw_exception(php_ce_v8js_exception, "Property name exceeds maximum supported length", 0); return; } /* Delete value from PHP JS object */ v8::Local key = V8JS_SYML(Z_STRVAL_P(member), static_cast(Z_STRLEN_P(member))); +#endif + jsobj->Delete(v8_context, key); /* Unset from PHP object */ diff --git a/v8js_class.h b/v8js_class.h index aaf28078..cabdee83 100644 --- a/v8js_class.h +++ b/v8js_class.h @@ -84,8 +84,13 @@ static inline struct v8js_ctx *v8js_ctx_fetch_object(zend_object *obj) { } #define Z_V8JS_CTX_OBJ_P(zv) v8js_ctx_fetch_object(Z_OBJ_P(zv)); +#define Z_V8JS_CTX_OBJ(zv) v8js_ctx_fetch_object(zv); +#if PHP_VERSION_ID >= 80000 +#define ZEND_ACC_DTOR 0 +#endif + PHP_MINIT_FUNCTION(v8js_class); #endif /* V8JS_CLASS_H */ diff --git a/v8js_convert.cc b/v8js_convert.cc index 8dc07f44..b70d20ff 100644 --- a/v8js_convert.cc +++ b/v8js_convert.cc @@ -148,7 +148,11 @@ v8::Local zval_to_v8js(zval *value, v8::Isolate *isolate) /* {{{ */ ce = php_date_get_date_ce(); if (instanceof_function(Z_OBJCE_P(value), ce)) { zval dtval; + #if PHP_VERSION_ID >= 80000 + zend_call_method_with_0_params(Z_OBJ_P(value), NULL, NULL, "getTimestamp", &dtval); + #else zend_call_method_with_0_params(value, NULL, NULL, "getTimestamp", &dtval); + #endif v8::Date::New(isolate->GetEnteredOrMicrotaskContext(), ((double)Z_LVAL(dtval) * 1000.0)).ToLocal(&jsValue); zval_dtor(&dtval); } else diff --git a/v8js_exceptions.cc b/v8js_exceptions.cc index 4ec809b5..89903d6e 100644 --- a/v8js_exceptions.cc +++ b/v8js_exceptions.cc @@ -50,8 +50,14 @@ void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8:: object_init_ex(return_value, php_ce_v8js_script_exception); +#if PHP_VERSION_ID >= 80000 +#define PHPV8_EXPROP(type, name, value) \ + zend_update_property##type(php_ce_v8js_script_exception, Z_OBJ_P(return_value), #name, sizeof(#name) - 1, value); +#else #define PHPV8_EXPROP(type, name, value) \ zend_update_property##type(php_ce_v8js_script_exception, return_value, #name, sizeof(#name) - 1, value); +#endif + if (tc_message.IsEmpty()) { spprintf(&message_string, 0, "%s", exception_string); @@ -128,7 +134,19 @@ void v8js_throw_script_exception(v8::Isolate *isolate, v8::TryCatch *try_catch) } } /* }}} */ - +#if PHP_VERSION_ID >= 80000 +#define V8JS_EXCEPTION_METHOD(property) \ + static PHP_METHOD(V8JsScriptException, get##property) \ + { \ + zval *value, rv; \ + \ + if (zend_parse_parameters_none() == FAILURE) { \ + return; \ + } \ + value = zend_read_property(php_ce_v8js_script_exception, Z_OBJ_P(getThis()), #property, sizeof(#property) - 1, 0, &rv); \ + RETURN_ZVAL(value, 1, 0); \ + } +#else #define V8JS_EXCEPTION_METHOD(property) \ static PHP_METHOD(V8JsScriptException, get##property) \ { \ @@ -140,6 +158,8 @@ void v8js_throw_script_exception(v8::Isolate *isolate, v8::TryCatch *try_catch) value = zend_read_property(php_ce_v8js_script_exception, getThis(), #property, sizeof(#property) - 1, 0, &rv); \ RETURN_ZVAL(value, 1, 0); \ } +#endif + /* {{{ proto string V8JsEScriptxception::getJsFileName() */ diff --git a/v8js_methods.cc b/v8js_methods.cc index 7f7f9261..519748b0 100644 --- a/v8js_methods.cc +++ b/v8js_methods.cc @@ -311,8 +311,13 @@ V8JS_METHOD(require) ZVAL_STRING(¶ms[0], module_base_cstr); ZVAL_STRING(¶ms[1], module_id); + #if (PHP_MAJOR_VERSION < 8) call_result = call_user_function_ex(EG(function_table), NULL, &c->module_normaliser, &normaliser_result, 2, params, 0, NULL); + #else + call_result = call_user_function(EG(function_table), NULL, &c->module_normaliser, + &normaliser_result, 2, params); + #endif } isolate->Enter(); @@ -435,7 +440,11 @@ V8JS_METHOD(require) zend_try { ZVAL_STRING(¶ms[0], normalised_module_id); + #if (PHP_MAJOR_VERSION < 8) call_result = call_user_function_ex(EG(function_table), NULL, &c->module_loader, &module_code, 1, params, 0, NULL); + #else + call_result = call_user_function(EG(function_table), NULL, &c->module_loader, &module_code, 1, params); + #endif } zend_catch { v8js_terminate_execution(isolate); diff --git a/v8js_object_export.cc b/v8js_object_export.cc index b36a3474..59263aa1 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -137,8 +137,11 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c } else { fci.params = NULL; } - +#if (PHP_MAJOR_VERSION < 8) fci.no_separation = 1; +#else + fci.named_params = NULL; +#endif info.GetReturnValue().Set(V8JS_NULL); { @@ -640,8 +643,12 @@ v8::Local v8js_named_property_callback(v8::Local property_n zval php_value; zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); + #if PHP_VERSION_ID >= 80000 + zend_object &zobject = *object; + #else zval zobject; ZVAL_OBJ(&zobject, object); + #endif v8js_function_tmpl_t *tmpl_ptr = reinterpret_cast(self->GetAlignedPointerFromInternalField(0)); v8::Local tmpl = v8::Local::New(isolate, *tmpl_ptr); @@ -796,7 +803,11 @@ v8::Local v8js_named_property_callback(v8::Local property_n const zend_object_handlers *h = object->handlers; if (callback_type == V8JS_PROP_QUERY) { + #if PHP_VERSION_ID >= 80000 + if (h->has_property(&zobject, Z_STR_P(&zname), 0, NULL)) { + #else if (h->has_property(&zobject, &zname, 0, NULL)) { + #endif ret_value = V8JS_UINT(v8::None); } else { ret_value = v8::Local(); // empty handle @@ -807,7 +818,11 @@ v8::Local v8js_named_property_callback(v8::Local property_n if(!property_info || (property_info != ZEND_WRONG_PROPERTY_INFO && property_info->flags & ZEND_ACC_PUBLIC)) { + #if PHP_VERSION_ID >= 80000 + h->unset_property(&zobject, Z_STR_P(&zname), NULL); + #else h->unset_property(&zobject, &zname, NULL); + #endif ret_value = V8JS_TRUE(); } else { diff --git a/v8js_v8.h b/v8js_v8.h index 7292ac0e..67c9d7b4 100644 --- a/v8js_v8.h +++ b/v8js_v8.h @@ -82,6 +82,11 @@ int v8js_get_properties_hash(v8::Local jsValue, HashTable *retval, in (ctx) = Z_V8JS_CTX_OBJ_P(object); \ V8JS_CTX_PROLOGUE(ctx); +#define V8JS_BEGIN_CTX_OBJ(ctx, object) \ + v8js_ctx *(ctx); \ + (ctx) = Z_V8JS_CTX_OBJ(object); \ + V8JS_CTX_PROLOGUE(ctx); + #if PHP_VERSION_ID < 70400 #define SINCE74(x,y) y diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index 11c4768a..2fce6ba4 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -21,7 +21,8 @@ #include "v8js_v8.h" #include "v8js_v8object_class.h" -extern "C" { +extern "C" +{ #include "ext/date/php_date.h" #include "ext/standard/php_string.h" #include "zend_interfaces.h" @@ -43,9 +44,38 @@ static zend_object_handlers v8js_v8generator_handlers; #define V8JS_V8_INVOKE_FUNC_NAME "V8Js::V8::Invoke" - /* V8 Object handlers */ +#if PHP_VERSION_ID >= 80000 +static int v8js_v8object_has_property(zend_object *object, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */ +{ + int retval = false; + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); + + if (!obj->ctx) + { + zend_throw_exception(php_ce_v8js_exception, + "Can't access V8Object after V8Js instance is destroyed!", 0); + return false; + } + + V8JS_CTX_PROLOGUE_EX(obj->ctx, false); + v8::Local v8obj = v8::Local::New(isolate, obj->v8obj); + v8::Local jsObj; + if (!v8obj->IsObject() || !v8obj->ToObject(v8_context).ToLocal(&jsObj)) + { + return false; + } + + if (ZSTR_LEN(member) > std::numeric_limits::max()) + { + zend_throw_exception(php_ce_v8js_exception, + "Member name length exceeds maximum supported length", 0); + return false; + } + + v8::Local jsKey = V8JS_ZSYM(member); +#else static int v8js_v8object_has_property(zval *object, zval *member, int has_set_exists, void **cache_slot) /* {{{ */ { /* param has_set_exists: @@ -56,9 +86,10 @@ static int v8js_v8object_has_property(zval *object, zval *member, int has_set_ex int retval = false; v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); - if (!obj->ctx) { + if (!obj->ctx) + { zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); + "Can't access V8Object after V8Js instance is destroyed!", 0); return false; } @@ -66,25 +97,28 @@ static int v8js_v8object_has_property(zval *object, zval *member, int has_set_ex v8::Local v8obj = v8::Local::New(isolate, obj->v8obj); v8::Local jsObj; - if (Z_TYPE_P(member) != IS_STRING || !v8obj->IsObject() || !v8obj->ToObject(v8_context).ToLocal(&jsObj)) { + if (Z_TYPE_P(member) != IS_STRING || !v8obj->IsObject() || !v8obj->ToObject(v8_context).ToLocal(&jsObj)) + { return false; } - if (Z_STRLEN_P(member) > std::numeric_limits::max()) { + if (Z_STRLEN_P(member) > std::numeric_limits::max()) + { zend_throw_exception(php_ce_v8js_exception, - "Member name length exceeds maximum supported length", 0); + "Member name length exceeds maximum supported length", 0); return false; } v8::Local jsKey = V8JS_ZSYM(Z_STR_P(member)); - +#endif /* Skip any prototype properties */ - if (!jsObj->HasRealNamedProperty(v8_context, jsKey).FromMaybe(false) - && !jsObj->HasRealNamedCallbackProperty(v8_context, jsKey).FromMaybe(false)) { + if (!jsObj->HasRealNamedProperty(v8_context, jsKey).FromMaybe(false) && !jsObj->HasRealNamedCallbackProperty(v8_context, jsKey).FromMaybe(false)) + { return false; } - if (has_set_exists == 2) { + if (has_set_exists == 2) + { /* property_exists(), that's enough! */ return true; } @@ -92,27 +126,30 @@ static int v8js_v8object_has_property(zval *object, zval *member, int has_set_ex /* We need to look at the value. */ v8::Local jsVal = jsObj->Get(v8_context, jsKey).ToLocalChecked(); - if (has_set_exists == 0 ) { + if (has_set_exists == 0) + { /* isset(): We make 'undefined' equivalent to 'null' */ - return !( jsVal->IsNull() || jsVal->IsUndefined() ); + return !(jsVal->IsNull() || jsVal->IsUndefined()); } /* empty() */ retval = jsVal->BooleanValue(isolate); /* for PHP compatibility, [] should also be empty */ - if (jsVal->IsArray() && retval) { + if (jsVal->IsArray() && retval) + { v8::Local array = v8::Local::Cast(jsVal); retval = (array->Length() != 0); } /* for PHP compatibility, '0' should also be empty */ v8::Local str; - if (jsVal->IsString() && retval && jsVal->ToString(v8_context).ToLocal(&str) - && str->Length() == 1) { + if (jsVal->IsString() && retval && jsVal->ToString(v8_context).ToLocal(&str) && str->Length() == 1) + { uint16_t c = 0; str->Write(isolate, &c, 0, 1); - if (c == '0') { + if (c == '0') + { retval = false; } } @@ -121,14 +158,43 @@ static int v8js_v8object_has_property(zval *object, zval *member, int has_set_ex } /* }}} */ +#if PHP_VERSION_ID >= 80000 +static zval *v8js_v8object_read_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */ +{ + zval *retval = rv; + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); + + if (!obj->ctx) + { + zend_throw_exception(php_ce_v8js_exception, + "Can't access V8Object after V8Js instance is destroyed!", 0); + return retval; + } + + V8JS_CTX_PROLOGUE_EX(obj->ctx, retval); + v8::Local v8obj = v8::Local::New(isolate, obj->v8obj); + + if (v8obj->IsObject()) + { + if (ZSTR_LEN(member) > std::numeric_limits::max()) + { + zend_throw_exception(php_ce_v8js_exception, + "Member name length exceeds maximum supported length", 0); + return retval; + } + + v8::Local jsKey = V8JS_ZSYM(member); + v8::Local jsObj = v8obj->ToObject(v8_context).ToLocalChecked(); +#else static zval *v8js_v8object_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */ { zval *retval = rv; v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); - if (!obj->ctx) { + if (!obj->ctx) + { zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); + "Can't access V8Object after V8Js instance is destroyed!", 0); return SINCE74(object, retval); } @@ -137,21 +203,23 @@ static zval *v8js_v8object_read_property(zval *object, zval *member, int type, v if (Z_TYPE_P(member) == IS_STRING && v8obj->IsObject()) { - if (Z_STRLEN_P(member) > std::numeric_limits::max()) { + if (Z_STRLEN_P(member) > std::numeric_limits::max()) + { zend_throw_exception(php_ce_v8js_exception, - "Member name length exceeds maximum supported length", 0); + "Member name length exceeds maximum supported length", 0); return retval; } v8::Local jsKey = V8JS_ZSYM(Z_STR_P(member)); v8::Local jsObj = v8obj->ToObject(v8_context).ToLocalChecked(); - +#endif /* Skip any prototype properties */ - if (jsObj->HasRealNamedProperty(v8_context, jsKey).FromMaybe(false) - || jsObj->HasRealNamedCallbackProperty(v8_context, jsKey).FromMaybe(false)) { + if (jsObj->HasRealNamedProperty(v8_context, jsKey).FromMaybe(false) || jsObj->HasRealNamedCallbackProperty(v8_context, jsKey).FromMaybe(false)) + { v8::MaybeLocal jsVal = jsObj->Get(v8_context, jsKey); - - if (!jsVal.IsEmpty() && v8js_to_zval(jsVal.ToLocalChecked(), retval, obj->flags, isolate) == SUCCESS) { + + if (!jsVal.IsEmpty() && v8js_to_zval(jsVal.ToLocalChecked(), retval, obj->flags, isolate) == SUCCESS) + { return retval; } } @@ -161,73 +229,148 @@ static zval *v8js_v8object_read_property(zval *object, zval *member, int type, v } /* }}} */ -static zval *v8js_v8object_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot) /* {{{ */ +#if PHP_VERSION_ID >= 80000 +static zval *v8js_v8object_get_property_ptr_ptr(zend_object *object, zend_string *member, int type, void **cache_slot) /* {{{ */ +#else +static zval *v8js_v8object_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot) /* {{{ */ +#endif { return NULL; } /* }}} */ -static SINCE74(zval*, void) v8js_v8object_write_property(zval *object, zval *member, zval *value, void **cache_slot ) /* {{{ */ +#if PHP_VERSION_ID >= 80000 +static SINCE74(zval *, void) v8js_v8object_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot) /* {{{ */ +{ + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); + + if (!obj->ctx) + { + zend_throw_exception(php_ce_v8js_exception, + "Can't access V8Object after V8Js instance is destroyed!", 0); + return SINCE74(value, ); + } + + V8JS_CTX_PROLOGUE_EX(obj->ctx, SINCE74(value, )); + v8::Local v8objHandle = v8::Local::New(isolate, obj->v8obj); + + if (ZSTR_LEN(member) > std::numeric_limits::max()) + { + zend_throw_exception(php_ce_v8js_exception, + "Member name length exceeds maximum supported length", 0); + return SINCE74(value, ); + } + + v8::Local v8obj; + if (v8objHandle->IsObject() && v8objHandle->ToObject(v8_context).ToLocal(&v8obj)) + { + v8obj->CreateDataProperty(v8_context, V8JS_ZSYM(member), zval_to_v8js(value, isolate)); + } +#else +static SINCE74(zval *, void) v8js_v8object_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */ { v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); - if (!obj->ctx) { + if (!obj->ctx) + { zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); - return SINCE74(value,); + "Can't access V8Object after V8Js instance is destroyed!", 0); + return SINCE74(value, ); } - V8JS_CTX_PROLOGUE_EX(obj->ctx, SINCE74(value,)); + V8JS_CTX_PROLOGUE_EX(obj->ctx, SINCE74(value, )); v8::Local v8objHandle = v8::Local::New(isolate, obj->v8obj); - if (Z_STRLEN_P(member) > std::numeric_limits::max()) { + if (Z_STRLEN_P(member) > std::numeric_limits::max()) + { zend_throw_exception(php_ce_v8js_exception, - "Member name length exceeds maximum supported length", 0); - return SINCE74(value,); + "Member name length exceeds maximum supported length", 0); + return SINCE74(value, ); } v8::Local v8obj; - if (v8objHandle->IsObject() && v8objHandle->ToObject(v8_context).ToLocal(&v8obj)) { + if (v8objHandle->IsObject() && v8objHandle->ToObject(v8_context).ToLocal(&v8obj)) + { v8obj->CreateDataProperty(v8_context, V8JS_ZSYM(Z_STR_P(member)), zval_to_v8js(value, isolate)); } - - return SINCE74(value,); +#endif + return SINCE74(value, ); } /* }}} */ +#if PHP_VERSION_ID >= 80000 +static void v8js_v8object_unset_property(zend_object *object, zend_string *member, void **cache_slot) /* {{{ */ +{ + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); + + if (!obj->ctx) + { + zend_throw_exception(php_ce_v8js_exception, + "Can't access V8Object after V8Js instance is destroyed!", 0); + return; + } + + V8JS_CTX_PROLOGUE(obj->ctx); + v8::Local v8objHandle = v8::Local::New(isolate, obj->v8obj); + + if (ZSTR_LEN(member) > std::numeric_limits::max()) + { + zend_throw_exception(php_ce_v8js_exception, + "Member name length exceeds maximum supported length", 0); + return; + } + + v8::Local v8obj; + if (v8objHandle->IsObject() && v8objHandle->ToObject(v8_context).ToLocal(&v8obj)) + { + v8obj->Delete(v8_context, V8JS_ZSYM(member)); + } +} +#else static void v8js_v8object_unset_property(zval *object, zval *member, void **cache_slot) /* {{{ */ { v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); - if (!obj->ctx) { + if (!obj->ctx) + { zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); + "Can't access V8Object after V8Js instance is destroyed!", 0); return; } V8JS_CTX_PROLOGUE(obj->ctx); v8::Local v8objHandle = v8::Local::New(isolate, obj->v8obj); - if (Z_STRLEN_P(member) > std::numeric_limits::max()) { + if (Z_STRLEN_P(member) > std::numeric_limits::max()) + { zend_throw_exception(php_ce_v8js_exception, - "Member name length exceeds maximum supported length", 0); + "Member name length exceeds maximum supported length", 0); return; } v8::Local v8obj; - if (v8objHandle->IsObject() && v8objHandle->ToObject(v8_context).ToLocal(&v8obj)) { + if (v8objHandle->IsObject() && v8objHandle->ToObject(v8_context).ToLocal(&v8obj)) + { v8obj->Delete(v8_context, V8JS_ZSYM(Z_STR_P(member))); } } +#endif /* }}} */ +#if PHP_VERSION_ID >= 80000 +static HashTable *v8js_v8object_get_properties(zend_object *object) /* {{{ */ +{ + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); +#else static HashTable *v8js_v8object_get_properties(zval *object) /* {{{ */ { v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); - - if (obj->properties == NULL) { +#endif + if (obj->properties == NULL) + { #if PHP_VERSION_ID < 70300 - if (GC_G(gc_active)) { + if (GC_G(gc_active)) + { /* the garbage collector is running, don't create more zvals */ return NULL; } @@ -236,26 +379,31 @@ static HashTable *v8js_v8object_get_properties(zval *object) /* {{{ */ ALLOC_HASHTABLE(obj->properties); zend_hash_init(obj->properties, 0, NULL, ZVAL_PTR_DTOR, 0); - if (!obj->ctx) { + if (!obj->ctx) + { /* Half-constructed object, probably due to unserialize call. * Just pass back properties hash so unserialize can write to * it (instead of crashing the engine). */ return obj->properties; } - } else if (!obj->properties->u.v.nIteratorsCount) { + } + else if (!obj->properties->u.v.nIteratorsCount) + { zend_hash_clean(obj->properties); } - if (!obj->ctx) { + if (!obj->ctx) + { zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); + "Can't access V8Object after V8Js instance is destroyed!", 0); return NULL; } V8JS_CTX_PROLOGUE_EX(obj->ctx, NULL); v8::Local v8obj = v8::Local::New(isolate, obj->v8obj); - if (v8js_get_properties_hash(v8obj, obj->properties, obj->flags, isolate) == SUCCESS) { + if (v8js_get_properties_hash(v8obj, obj->properties, obj->flags, isolate) == SUCCESS) + { return obj->properties; } @@ -263,27 +411,156 @@ static HashTable *v8js_v8object_get_properties(zval *object) /* {{{ */ } /* }}} */ +#if PHP_VERSION_ID >= 80000 +static HashTable *v8js_v8object_get_debug_info(zend_object *object, int *is_temp) /* {{{ */ +#else static HashTable *v8js_v8object_get_debug_info(zval *object, int *is_temp) /* {{{ */ +#endif { *is_temp = 0; return v8js_v8object_get_properties(object); } /* }}} */ +static ZEND_FUNCTION(zend_v8object_func) +{ + RETVAL_STR_COPY(EX(func)->common.function_name); + + zval *argv = NULL; + int argc = ZEND_NUM_ARGS(); + zend_string *method = EX(func)->common.function_name; + zend_object *object = Z_OBJ_P(getThis()); + + /* Cleanup trampoline */ + ZEND_ASSERT(EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE); + zend_string_release(EX(func)->common.function_name); + zend_free_trampoline(EX(func)); + EX(func) = NULL; + + v8js_v8object *obj = v8js_v8object_fetch_object(object); + + if (!obj->ctx) + { + zend_throw_exception(php_ce_v8js_exception, + "Can't access V8Object after V8Js instance is destroyed!", 0); + return; + } + + if (obj->v8obj.IsEmpty()) + { + return; + } + + if (ZSTR_LEN(method) > std::numeric_limits::max()) + { + zend_throw_exception(php_ce_v8js_exception, + "Method name length exceeds maximum supported length", 0); + return; + } + + if (argc > 0) + { + argv = (zval *)safe_emalloc(sizeof(zval), argc, 0); + zend_get_parameters_array_ex(argc, argv); + } + + /* std::function relies on its dtor to be executed, otherwise it leaks + * some memory on bailout. */ + { + std::function(v8::Isolate *)> v8_call = [obj, method, argc, argv, object, &return_value](v8::Isolate *isolate) + { + int i = 0; + + v8::Local v8_context = isolate->GetEnteredOrMicrotaskContext(); + v8::Local method_name = V8JS_SYML(ZSTR_VAL(method), static_cast(ZSTR_LEN(method))); + v8::Local v8obj = v8::Local::New(isolate, obj->v8obj)->ToObject(v8_context).ToLocalChecked(); + v8::Local thisObj; + v8::Local cb; + + if (method_name->Equals(v8_context, V8JS_SYM(V8JS_V8_INVOKE_FUNC_NAME)).FromMaybe(false)) + { + cb = v8::Local::Cast(v8obj); + } + else + { + v8::Local slot; + + if (!v8obj->Get(v8_context, method_name).ToLocal(&slot)) + { + return v8::MaybeLocal(); + } + + cb = v8::Local::Cast(slot); + } + + // If a method is invoked on V8Object, then set the object itself as + // "this" on JS side. Otherwise fall back to global object. + if (obj->std.ce == php_ce_v8object) + { + thisObj = v8obj; + } + else + { + thisObj = V8JS_GLOBAL(isolate); + } + + v8::Local *jsArgv = static_cast *>(alloca(sizeof(v8::Local) * argc)); + + for (i = 0; i < argc; i++) + { + new (&jsArgv[i]) v8::Local; + jsArgv[i] = v8::Local::New(isolate, zval_to_v8js(&argv[i], isolate)); + } + + v8::MaybeLocal result = cb->Call(v8_context, thisObj, argc, jsArgv); + + if (obj->std.ce == php_ce_v8object && !result.IsEmpty() && result.ToLocalChecked()->StrictEquals(thisObj)) + { + /* JS code did "return this", retain object identity */ + ZVAL_OBJ(return_value, object); + zval_copy_ctor(return_value); + result = v8::MaybeLocal(); + } + + return result; + }; + + v8js_v8_call(obj->ctx, &return_value, obj->flags, obj->ctx->time_limit, obj->ctx->memory_limit, v8_call); + } + + if (argc > 0) + { + efree(argv); + } + + if (V8JSG(fatal_error_abort)) + { + /* Check for fatal error marker possibly set by v8js_error_handler; just + * rethrow the error since we're now out of V8. */ + zend_bailout(); + } +} + static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_string *method, const zval *key) /* {{{ */ { v8js_v8object *obj = v8js_v8object_fetch_object(*object_ptr); +#if PHP_VERSION_ID < 80000 zend_function *f; +#else + zend_internal_function *f; +#endif - if (!obj->ctx) { + if (!obj->ctx) + { zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); + "Can't access V8Object after V8Js instance is destroyed!", 0); return NULL; } - if (ZSTR_LEN(method) > std::numeric_limits::max()) { + if (ZSTR_LEN(method) > std::numeric_limits::max()) + { zend_throw_exception(php_ce_v8js_exception, - "Method name length exceeds maximum supported length", 0); + "Method name length exceeds maximum supported length", 0); return NULL; } @@ -291,18 +568,25 @@ static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_st v8::Local jsKey = V8JS_STRL(ZSTR_VAL(method), static_cast(ZSTR_LEN(method))); v8::Local v8obj = v8::Local::New(isolate, obj->v8obj); - if (!obj->v8obj.IsEmpty() && v8obj->IsObject() && !v8obj->IsFunction()) { + if (!obj->v8obj.IsEmpty() && v8obj->IsObject() && !v8obj->IsFunction()) + { v8::Local jsObj; v8::Local jsObjSlot; - if (v8obj->ToObject(v8_context).ToLocal(&jsObj) - && jsObj->Has(v8_context, jsKey).FromMaybe(false) - && jsObj->Get(v8_context, jsKey).ToLocal(&jsObjSlot) - && jsObjSlot->IsFunction()) { - f = (zend_function *) ecalloc(1, sizeof(*f)); + if (v8obj->ToObject(v8_context).ToLocal(&jsObj) && jsObj->Has(v8_context, jsKey).FromMaybe(false) && jsObj->Get(v8_context, jsKey).ToLocal(&jsObjSlot) && jsObjSlot->IsFunction()) + { +#if PHP_VERSION_ID < 80000 + f = (zend_function *)ecalloc(1, sizeof(*f)); f->type = ZEND_OVERLOADED_FUNCTION_TEMPORARY; f->common.function_name = zend_string_copy(method); return f; +#else + f = (zend_internal_function *)ecalloc(1, sizeof(*f)); + f->type = ZEND_ACC_CALL_VIA_HANDLER; + f->handler = ZEND_FN(zend_v8object_func); + f->function_name = zend_string_copy(method); + return (zend_function *)f; +#endif } } @@ -317,31 +601,36 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I v8js_v8object *obj = v8js_v8object_fetch_object(object); - if (!obj->ctx) { + if (!obj->ctx) + { zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); + "Can't access V8Object after V8Js instance is destroyed!", 0); return FAILURE; } - if (obj->v8obj.IsEmpty()) { + if (obj->v8obj.IsEmpty()) + { return FAILURE; } - if (ZSTR_LEN(method) > std::numeric_limits::max()) { + if (ZSTR_LEN(method) > std::numeric_limits::max()) + { zend_throw_exception(php_ce_v8js_exception, - "Method name length exceeds maximum supported length", 0); + "Method name length exceeds maximum supported length", 0); return FAILURE; } - if (argc > 0) { - argv = (zval*)safe_emalloc(sizeof(zval), argc, 0); + if (argc > 0) + { + argv = (zval *)safe_emalloc(sizeof(zval), argc, 0); zend_get_parameters_array_ex(argc, argv); } /* std::function relies on its dtor to be executed, otherwise it leaks * some memory on bailout. */ { - std::function< v8::MaybeLocal(v8::Isolate *) > v8_call = [obj, method, argc, argv, object, &return_value](v8::Isolate *isolate) { + std::function(v8::Isolate *)> v8_call = [obj, method, argc, argv, object, &return_value](v8::Isolate *isolate) + { int i = 0; v8::Local v8_context = isolate->GetEnteredOrMicrotaskContext(); @@ -350,12 +639,16 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I v8::Local thisObj; v8::Local cb; - if (method_name->Equals(v8_context, V8JS_SYM(V8JS_V8_INVOKE_FUNC_NAME)).FromMaybe(false)) { + if (method_name->Equals(v8_context, V8JS_SYM(V8JS_V8_INVOKE_FUNC_NAME)).FromMaybe(false)) + { cb = v8::Local::Cast(v8obj); - } else { + } + else + { v8::Local slot; - if (!v8obj->Get(v8_context, method_name).ToLocal(&slot)) { + if (!v8obj->Get(v8_context, method_name).ToLocal(&slot)) + { return v8::MaybeLocal(); } @@ -364,23 +657,27 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I // If a method is invoked on V8Object, then set the object itself as // "this" on JS side. Otherwise fall back to global object. - if (obj->std.ce == php_ce_v8object) { + if (obj->std.ce == php_ce_v8object) + { thisObj = v8obj; } - else { + else + { thisObj = V8JS_GLOBAL(isolate); } v8::Local *jsArgv = static_cast *>(alloca(sizeof(v8::Local) * argc)); - for (i = 0; i < argc; i++) { - new(&jsArgv[i]) v8::Local; + for (i = 0; i < argc; i++) + { + new (&jsArgv[i]) v8::Local; jsArgv[i] = v8::Local::New(isolate, zval_to_v8js(&argv[i], isolate)); } v8::MaybeLocal result = cb->Call(v8_context, thisObj, argc, jsArgv); - if (obj->std.ce == php_ce_v8object && !result.IsEmpty() && result.ToLocalChecked()->StrictEquals(thisObj)) { + if (obj->std.ce == php_ce_v8object && !result.IsEmpty() && result.ToLocalChecked()->StrictEquals(thisObj)) + { /* JS code did "return this", retain object identity */ ZVAL_OBJ(return_value, object); zval_copy_ctor(return_value); @@ -393,11 +690,13 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I v8js_v8_call(obj->ctx, &return_value, obj->flags, obj->ctx->time_limit, obj->ctx->memory_limit, v8_call); } - if (argc > 0) { + if (argc > 0) + { efree(argv); } - if(V8JSG(fatal_error_abort)) { + if (V8JSG(fatal_error_abort)) + { /* Check for fatal error marker possibly set by v8js_error_handler; just * rethrow the error since we're now out of V8. */ zend_bailout(); @@ -407,32 +706,52 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I } /* }}} */ +#if PHP_VERSION_ID >= 80000 +static int v8js_v8object_get_closure(zend_object *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr, bool call) /* {{{ */ +{ + zend_internal_function *invoke; + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); +#else static int v8js_v8object_get_closure(zval *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr) /* {{{ */ { zend_function *invoke; v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); - - if (!obj->ctx) { +#endif + if (!obj->ctx) + { zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); + "Can't access V8Object after V8Js instance is destroyed!", 0); return FAILURE; } V8JS_CTX_PROLOGUE_EX(obj->ctx, FAILURE); v8::Local v8obj = v8::Local::New(isolate, obj->v8obj); - if (!v8obj->IsFunction()) { + if (!v8obj->IsFunction()) + { return FAILURE; } - invoke = (zend_function *) ecalloc(1, sizeof(*invoke)); +#if PHP_VERSION_ID < 80000 + invoke = (zend_function *)ecalloc(1, sizeof(*invoke)); invoke->type = ZEND_OVERLOADED_FUNCTION_TEMPORARY; invoke->common.function_name = zend_string_init(V8JS_V8_INVOKE_FUNC_NAME, sizeof(V8JS_V8_INVOKE_FUNC_NAME) - 1, 0); - *fptr_ptr = invoke; +#else + invoke = (zend_internal_function *)ecalloc(1, sizeof(*invoke)); + invoke->type = ZEND_ACC_CALL_VIA_HANDLER; + invoke->handler = ZEND_FN(zend_v8object_func); + invoke->function_name = zend_string_init(V8JS_V8_INVOKE_FUNC_NAME, sizeof(V8JS_V8_INVOKE_FUNC_NAME) - 1, 0); + *fptr_ptr = (zend_function *)invoke; +#endif - if (zobj_ptr) { + if (zobj_ptr) + { +#if PHP_VERSION_ID >= 80000 + *zobj_ptr = object; +#else *zobj_ptr = Z_OBJ_P(object); +#endif } *ce_ptr = NULL; @@ -445,7 +764,8 @@ static void v8js_v8object_free_storage(zend_object *object) /* {{{ */ { v8js_v8object *c = v8js_v8object_fetch_object(object); - if (c->properties) { + if (c->properties) + { zend_hash_destroy(c->properties); FREE_HASHTABLE(c->properties); c->properties = NULL; @@ -453,7 +773,8 @@ static void v8js_v8object_free_storage(zend_object *object) /* {{{ */ zend_object_std_dtor(&c->std); - if(c->ctx) { + if (c->ctx) + { c->v8obj.Reset(); c->ctx->v8js_v8objects.remove(c); } @@ -463,11 +784,11 @@ static void v8js_v8object_free_storage(zend_object *object) /* {{{ */ static zend_object *v8js_v8object_new(zend_class_entry *ce) /* {{{ */ { v8js_v8object *c; - c = (v8js_v8object *) ecalloc(1, sizeof(v8js_v8object) + zend_object_properties_size(ce)); + c = (v8js_v8object *)ecalloc(1, sizeof(v8js_v8object) + zend_object_properties_size(ce)); zend_object_std_init(&c->std, ce); c->std.handlers = &v8js_v8object_handlers; - new(&c->v8obj) v8::Persistent(); + new (&c->v8obj) v8::Persistent(); return &c->std; } @@ -480,10 +801,10 @@ static zend_object *v8js_v8object_new(zend_class_entry *ce) /* {{{ */ /* {{{ proto V8Object::__construct() */ -PHP_METHOD(V8Object,__construct) +PHP_METHOD(V8Object, __construct) { zend_throw_exception(php_ce_v8js_exception, - "Can't directly construct V8 objects!", 0); + "Can't directly construct V8 objects!", 0); RETURN_FALSE; } /* }}} */ @@ -493,7 +814,7 @@ PHP_METHOD(V8Object,__construct) PHP_METHOD(V8Object, __sleep) { zend_throw_exception(php_ce_v8js_exception, - "You cannot serialize or unserialize V8Object instances", 0); + "You cannot serialize or unserialize V8Object instances", 0); RETURN_FALSE; } /* }}} */ @@ -503,17 +824,17 @@ PHP_METHOD(V8Object, __sleep) PHP_METHOD(V8Object, __wakeup) { zend_throw_exception(php_ce_v8js_exception, - "You cannot serialize or unserialize V8Object instances", 0); + "You cannot serialize or unserialize V8Object instances", 0); RETURN_FALSE; } /* }}} */ /* {{{ proto V8Function::__construct() */ -PHP_METHOD(V8Function,__construct) +PHP_METHOD(V8Function, __construct) { zend_throw_exception(php_ce_v8js_exception, - "Can't directly construct V8 objects!", 0); + "Can't directly construct V8 objects!", 0); RETURN_FALSE; } /* }}} */ @@ -523,7 +844,7 @@ PHP_METHOD(V8Function,__construct) PHP_METHOD(V8Function, __sleep) { zend_throw_exception(php_ce_v8js_exception, - "You cannot serialize or unserialize V8Function instances", 0); + "You cannot serialize or unserialize V8Function instances", 0); RETURN_FALSE; } /* }}} */ @@ -533,12 +854,11 @@ PHP_METHOD(V8Function, __sleep) PHP_METHOD(V8Function, __wakeup) { zend_throw_exception(php_ce_v8js_exception, - "You cannot serialize or unserialize V8Function instances", 0); + "You cannot serialize or unserialize V8Function instances", 0); RETURN_FALSE; } /* }}} */ - static void v8js_v8generator_free_storage(zend_object *object) /* {{{ */ { v8js_v8generator *c = v8js_v8generator_fetch_object(object); @@ -551,11 +871,11 @@ static void v8js_v8generator_free_storage(zend_object *object) /* {{{ */ static zend_object *v8js_v8generator_new(zend_class_entry *ce) /* {{{ */ { v8js_v8generator *c; - c = (v8js_v8generator *) ecalloc(1, sizeof(v8js_v8generator) + zend_object_properties_size(ce)); + c = (v8js_v8generator *)ecalloc(1, sizeof(v8js_v8generator) + zend_object_properties_size(ce)); zend_object_std_init(&c->v8obj.std, ce); c->v8obj.std.handlers = &v8js_v8generator_handlers; - new(&c->v8obj.v8obj) v8::Persistent(); + new (&c->v8obj.v8obj) v8::Persistent(); return &c->v8obj.std; } @@ -563,35 +883,39 @@ static zend_object *v8js_v8generator_new(zend_class_entry *ce) /* {{{ */ static void v8js_v8generator_next(v8js_v8generator *g) /* {{{ */ { - if (!g->v8obj.ctx) { + if (!g->v8obj.ctx) + { zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Generator after V8Js instance is destroyed!", 0); + "Can't access V8Generator after V8Js instance is destroyed!", 0); return; } /* std::function relies on its dtor to be executed, otherwise it leaks * some memory on bailout. */ { - std::function< v8::MaybeLocal(v8::Isolate *) > v8_call = [g](v8::Isolate *isolate) { + std::function(v8::Isolate *)> v8_call = [g](v8::Isolate *isolate) + { v8::Local v8_context = isolate->GetEnteredOrMicrotaskContext(); v8::Local method_name = V8JS_SYM("next"); v8::Local v8obj = v8::Local::New(isolate, g->v8obj.v8obj)->ToObject(v8_context).ToLocalChecked(); - v8::Local cb = v8::Local::Cast(v8obj->Get(v8_context, method_name).ToLocalChecked());; + v8::Local cb = v8::Local::Cast(v8obj->Get(v8_context, method_name).ToLocalChecked()); + ; v8::MaybeLocal result = cb->Call(v8_context, v8obj, 0, NULL); - if(result.IsEmpty()) { + if (result.IsEmpty()) + { /* cb->Call probably threw (and already threw a zend exception), just return */ return V8JS_NULL; } - if(!result.ToLocalChecked()->IsObject()) { + if (!result.ToLocalChecked()->IsObject()) + { zend_throw_exception(php_ce_v8js_exception, - "V8Generator returned non-object on next()", 0); + "V8Generator returned non-object on next()", 0); return V8JS_NULL; } - v8::Local resultObj = result.ToLocalChecked()->ToObject(v8_context).ToLocalChecked(); v8::Local val = resultObj->Get(v8_context, V8JS_SYM("value")).ToLocalChecked(); v8::Local done = resultObj->Get(v8_context, V8JS_SYM("done")).ToLocalChecked(); @@ -607,7 +931,8 @@ static void v8js_v8generator_next(v8js_v8generator *g) /* {{{ */ v8js_v8_call(g->v8obj.ctx, NULL, g->v8obj.flags, g->v8obj.ctx->time_limit, g->v8obj.ctx->memory_limit, v8_call); } - if(V8JSG(fatal_error_abort)) { + if (V8JSG(fatal_error_abort)) + { /* Check for fatal error marker possibly set by v8js_error_handler; just * rethrow the error since we're now out of V8. */ zend_bailout(); @@ -619,7 +944,8 @@ static zend_function *v8js_v8generator_get_method(zend_object **object_ptr, zend { zend_function *result = std_object_handlers.get_method(object_ptr, method, key); - if(!result) { + if (!result) + { result = v8js_v8object_get_method(object_ptr, method, key); } @@ -629,10 +955,10 @@ static zend_function *v8js_v8generator_get_method(zend_object **object_ptr, zend /* {{{ proto V8Generator::__construct() */ -PHP_METHOD(V8Generator,__construct) +PHP_METHOD(V8Generator, __construct) { zend_throw_exception(php_ce_v8js_exception, - "Can't directly construct V8 objects!", 0); + "Can't directly construct V8 objects!", 0); RETURN_FALSE; } /* }}} */ @@ -642,7 +968,7 @@ PHP_METHOD(V8Generator,__construct) PHP_METHOD(V8Generator, __sleep) { zend_throw_exception(php_ce_v8js_exception, - "You cannot serialize or unserialize V8Generator instances", 0); + "You cannot serialize or unserialize V8Generator instances", 0); RETURN_FALSE; } /* }}} */ @@ -652,7 +978,7 @@ PHP_METHOD(V8Generator, __sleep) PHP_METHOD(V8Generator, __wakeup) { zend_throw_exception(php_ce_v8js_exception, - "You cannot serialize or unserialize V8Generator instances", 0); + "You cannot serialize or unserialize V8Generator instances", 0); RETURN_FALSE; } /* }}} */ @@ -663,7 +989,8 @@ PHP_METHOD(V8Generator, current) { v8js_v8generator *g = Z_V8JS_V8GENERATOR_OBJ_P(getThis()); - if(!g->primed) { + if (!g->primed) + { v8js_v8generator_next(g); } @@ -694,10 +1021,10 @@ PHP_METHOD(V8Generator, rewind) { v8js_v8generator *g = Z_V8JS_V8GENERATOR_OBJ_P(getThis()); - if(g->primed) { + if (g->primed) + { zend_throw_exception(php_ce_v8js_exception, - "V8Generator::rewind not supported by ES6", 0); - + "V8Generator::rewind not supported by ES6", 0); } RETURN_FALSE; @@ -710,7 +1037,8 @@ PHP_METHOD(V8Generator, valid) { v8js_v8generator *g = Z_V8JS_V8GENERATOR_OBJ_P(getThis()); - if(!g->primed) { + if (!g->primed) + { v8js_v8generator_next(g); } @@ -718,18 +1046,20 @@ PHP_METHOD(V8Generator, valid) } /* }}} */ - void v8js_v8object_create(zval *res, v8::Local value, int flags, v8::Isolate *isolate) /* {{{ */ { - v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0); + v8js_ctx *ctx = (v8js_ctx *)isolate->GetData(0); - if(value->IsGeneratorObject()) { + if (value->IsGeneratorObject()) + { object_init_ex(res, php_ce_v8generator); } - else if(value->IsFunction()) { + else if (value->IsFunction()) + { object_init_ex(res, php_ce_v8function); } - else { + else + { object_init_ex(res, php_ce_v8object); } @@ -743,23 +1073,45 @@ void v8js_v8object_create(zval *res, v8::Local value, int flags, v8:: } /* }}} */ +ZEND_BEGIN_ARG_INFO(arginfo_v8object_construct, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_v8object_sleep, 0) +ZEND_END_ARG_INFO() -static const zend_function_entry v8js_v8object_methods[] = { /* {{{ */ - PHP_ME(V8Object, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - PHP_ME(V8Object, __sleep, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) - PHP_ME(V8Object, __wakeup, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) - {NULL, NULL, NULL} -}; +ZEND_BEGIN_ARG_INFO(arginfo_v8object_wakeup, 0) +ZEND_END_ARG_INFO() + +static const zend_function_entry v8js_v8object_methods[] = {/* {{{ */ + PHP_ME(V8Object, __construct, arginfo_v8object_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + PHP_ME(V8Object, __sleep, arginfo_v8object_sleep, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL) + PHP_ME(V8Object, __wakeup, arginfo_v8object_wakeup, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL){NULL, NULL, NULL}}; /* }}} */ -static const zend_function_entry v8js_v8function_methods[] = { /* {{{ */ - PHP_ME(V8Function, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - PHP_ME(V8Function, __sleep, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) - PHP_ME(V8Function, __wakeup, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) - {NULL, NULL, NULL} -}; +ZEND_BEGIN_ARG_INFO(arginfo_v8function_construct, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_v8function_sleep, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_v8function_wakeup, 0) +ZEND_END_ARG_INFO() + +static const zend_function_entry v8js_v8function_methods[] = {/* {{{ */ + PHP_ME(V8Function, __construct, arginfo_v8function_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + PHP_ME(V8Function, __sleep, arginfo_v8function_sleep, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL) + PHP_ME(V8Function, __wakeup, arginfo_v8function_wakeup, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL){NULL, NULL, NULL}}; /* }}} */ +ZEND_BEGIN_ARG_INFO(arginfo_v8generator_construct, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_v8generator_sleep, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_v8generator_wakeup, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO(arginfo_v8generator_current, 0) ZEND_END_ARG_INFO() @@ -775,22 +1127,20 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_v8generator_valid, 0) ZEND_END_ARG_INFO() -static const zend_function_entry v8js_v8generator_methods[] = { /* {{{ */ - PHP_ME(V8Generator, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR) - PHP_ME(V8Generator, __sleep, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) - PHP_ME(V8Generator, __wakeup, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) +static const zend_function_entry v8js_v8generator_methods[] = {/* {{{ */ + PHP_ME(V8Generator, __construct, arginfo_v8generator_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + PHP_ME(V8Generator, __sleep, arginfo_v8generator_sleep, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL) + PHP_ME(V8Generator, __wakeup, arginfo_v8generator_wakeup, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL) - PHP_ME(V8Generator, current, arginfo_v8generator_current, ZEND_ACC_PUBLIC) - PHP_ME(V8Generator, key, arginfo_v8generator_key, ZEND_ACC_PUBLIC) - PHP_ME(V8Generator, next, arginfo_v8generator_next, ZEND_ACC_PUBLIC) - PHP_ME(V8Generator, rewind, arginfo_v8generator_rewind, ZEND_ACC_PUBLIC) - PHP_ME(V8Generator, valid, arginfo_v8generator_valid, ZEND_ACC_PUBLIC) + PHP_ME(V8Generator, current, arginfo_v8generator_current, ZEND_ACC_PUBLIC) + PHP_ME(V8Generator, key, arginfo_v8generator_key, ZEND_ACC_PUBLIC) + PHP_ME(V8Generator, next, arginfo_v8generator_next, ZEND_ACC_PUBLIC) + PHP_ME(V8Generator, rewind, arginfo_v8generator_rewind, ZEND_ACC_PUBLIC) + PHP_ME(V8Generator, valid, arginfo_v8generator_valid, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; + {NULL, NULL, NULL}}; /* }}} */ - PHP_MINIT_FUNCTION(v8js_v8object_class) /* {{{ */ { zend_class_entry ce; @@ -815,7 +1165,6 @@ PHP_MINIT_FUNCTION(v8js_v8object_class) /* {{{ */ zend_class_implements(php_ce_v8generator, 1, zend_ce_iterator); - /* V8 handlers */ memcpy(&v8js_v8object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); v8js_v8object_handlers.clone_obj = NULL; @@ -827,7 +1176,9 @@ PHP_MINIT_FUNCTION(v8js_v8object_class) /* {{{ */ v8js_v8object_handlers.unset_property = v8js_v8object_unset_property; v8js_v8object_handlers.get_properties = v8js_v8object_get_properties; v8js_v8object_handlers.get_method = v8js_v8object_get_method; +#if PHP_VERSION_ID < 80000 v8js_v8object_handlers.call_method = v8js_v8object_call_method; +#endif v8js_v8object_handlers.get_debug_info = v8js_v8object_get_debug_info; v8js_v8object_handlers.get_closure = v8js_v8object_get_closure; v8js_v8object_handlers.offset = XtOffsetOf(struct v8js_v8object, std); @@ -842,7 +1193,6 @@ PHP_MINIT_FUNCTION(v8js_v8object_class) /* {{{ */ return SUCCESS; } /* }}} */ - /* * Local variables: * tab-width: 4 diff --git a/v8js_v8object_class.h b/v8js_v8object_class.h index b342bd6b..0bb7ed0e 100644 --- a/v8js_v8object_class.h +++ b/v8js_v8object_class.h @@ -35,7 +35,7 @@ static inline v8js_v8object *v8js_v8object_fetch_object(zend_object *obj) { } #define Z_V8JS_V8OBJECT_OBJ_P(zv) v8js_v8object_fetch_object(Z_OBJ_P(zv)); - +#define Z_V8JS_V8OBJECT_OBJ(zv) v8js_v8object_fetch_object(zv); /* {{{ Generator container */ struct v8js_v8generator { From 8b10c810492818a5651a093e27f95af16aeedfaf Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Thu, 5 Aug 2021 11:46:17 +0200 Subject: [PATCH 02/64] demo unification of PHP 8.0 code branch w/ old one --- v8js_class.cc | 33 ++++----------------------------- v8js_v8.h | 6 ++++++ 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/v8js_class.cc b/v8js_class.cc index 95768987..a9ba1f3f 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -1309,9 +1309,11 @@ const zend_function_entry v8js_methods[] = { /* {{{ */ /* V8Js object handlers */ -#if PHP_VERSION_ID >= 80000 -static SINCE74(zval*, void) v8js_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot) /* {{{ */ +static SINCE74(zval*, void) v8js_write_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, zval *value, void **cache_slot) /* {{{ */ { + zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); + zend_string *member = SINCE80(_member, Z_STR_P(_member)); + v8js_ctx *c = Z_V8JS_CTX_OBJ(object); V8JS_CTX_PROLOGUE_EX(c, SINCE74(value,)); @@ -1335,33 +1337,6 @@ static SINCE74(zval*, void) v8js_write_property(zend_object *object, zend_string v8::Local key = V8JS_SYML(ZSTR_VAL(member), static_cast(ZSTR_LEN(member))); jsobj->DefineOwnProperty(v8_context, key, zval_to_v8js(value, isolate), v8::ReadOnly); } -#else -static SINCE74(zval*, void) v8js_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */ -{ - v8js_ctx *c = Z_V8JS_CTX_OBJ_P(object); - V8JS_CTX_PROLOGUE_EX(c, SINCE74(value,)); - - /* Check whether member is public, if so, export to V8. */ - zend_property_info *property_info = zend_get_property_info(c->std.ce, Z_STR_P(member), 1); - - if(!property_info || - (property_info != ZEND_WRONG_PROPERTY_INFO && - (property_info->flags & ZEND_ACC_PUBLIC))) { - /* Global PHP JS object */ - v8::Local object_name_js = v8::Local::New(isolate, c->object_name); - v8::Local jsobj = V8JS_GLOBAL(isolate)->Get(v8_context, object_name_js).ToLocalChecked()->ToObject(v8_context).ToLocalChecked(); - - if (Z_STRLEN_P(member) > std::numeric_limits::max()) { - zend_throw_exception(php_ce_v8js_exception, - "Property name exceeds maximum supported length", 0); - return SINCE74(value,); - } - - /* Write value to PHP JS object */ - v8::Local key = V8JS_SYML(Z_STRVAL_P(member), static_cast(Z_STRLEN_P(member))); - jsobj->DefineOwnProperty(v8_context, key, zval_to_v8js(value, isolate), v8::ReadOnly); - } -#endif /* Write value to PHP object */ SINCE74(return,) std_object_handlers.write_property(object, member, value, NULL); diff --git a/v8js_v8.h b/v8js_v8.h index 67c9d7b4..7adc67d4 100644 --- a/v8js_v8.h +++ b/v8js_v8.h @@ -94,6 +94,12 @@ int v8js_get_properties_hash(v8::Local jsValue, HashTable *retval, in #define SINCE74(x,y) x #endif +#if PHP_VERSION_ID < 80000 +#define SINCE80(x,y) y +#else +#define SINCE80(x,y) x +#endif + #endif /* V8JS_V8_H */ From 3d64f085366b810eb4e1aafc94c6b154a3eeddd9 Mon Sep 17 00:00:00 2001 From: Albert Date: Fri, 20 Aug 2021 20:08:45 +0800 Subject: [PATCH 03/64] optimize redundancy code and fix some unit test --- tests/checkstring.phpt | 4 +- tests/exception_clearing.phpt | 12 +- tests/exception_propagation_2.phpt | 2 +- tests/extensions_basic.phpt | 6 +- tests/extensions_circular_dependency.phpt | 6 +- tests/extensions_error.phpt | 2 +- tests/fatal_error_ignore_non_fatals.phpt | 2 +- tests/fatal_error_v8function.phpt | 2 +- v8js_class.cc | 35 +--- v8js_convert.cc | 6 +- v8js_exceptions.cc | 23 +-- v8js_object_export.cc | 18 +- v8js_v8object_class.cc | 194 ++++------------------ 13 files changed, 64 insertions(+), 248 deletions(-) diff --git a/tests/checkstring.phpt b/tests/checkstring.phpt index 9d6ce0ed..dc2ff5b0 100644 --- a/tests/checkstring.phpt +++ b/tests/checkstring.phpt @@ -16,9 +16,9 @@ try { ?> ===EOF=== --EXPECTF-- -Deprecated: Function V8Js::checkString() is deprecated in %s on line %d +Deprecated: %s V8Js::checkString() is deprecated in %s on line %d bool(true) -Deprecated: Function V8Js::checkString() is deprecated in %s on line %d +Deprecated: %s V8Js::checkString() is deprecated in %s on line %d string(%d) "V8Js::checkString():1: SyntaxError: %s" ===EOF=== diff --git a/tests/exception_clearing.phpt b/tests/exception_clearing.phpt index c48a26c5..3646c5a9 100644 --- a/tests/exception_clearing.phpt +++ b/tests/exception_clearing.phpt @@ -23,15 +23,15 @@ var_dump($v8->getPendingException()); --EXPECTF-- Deprecated: V8Js::__construct(): Disabling exception reporting is deprecated, $report_uncaught_exceptions != true in %s%eexception_clearing.php on line 3 -Deprecated: Function V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 5 +Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 5 NULL -Deprecated: Function V8Js::clearPendingException() is deprecated in %s%eexception_clearing.php on line 7 +Deprecated: %s V8Js::clearPendingException() is deprecated in %s%eexception_clearing.php on line 7 -Deprecated: Function V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 8 +Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 8 NULL -Deprecated: Function V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 11 +Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 11 object(V8JsScriptException)#%d (13) { ["message":protected]=> string(49) "throw_0:1: ReferenceError: fooobar is not defined" @@ -83,8 +83,8 @@ object(V8JsScriptException)#%d (13) { at throw_0:1:1" } -Deprecated: Function V8Js::clearPendingException() is deprecated in %s%eexception_clearing.php on line 13 +Deprecated: %s V8Js::clearPendingException() is deprecated in %s%eexception_clearing.php on line 13 -Deprecated: Function V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 14 +Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 14 NULL ===EOF=== diff --git a/tests/exception_propagation_2.phpt b/tests/exception_propagation_2.phpt index 718856d2..c808e3aa 100644 --- a/tests/exception_propagation_2.phpt +++ b/tests/exception_propagation_2.phpt @@ -40,7 +40,7 @@ try { --EXPECTF-- Deprecated: V8Js::__construct(): Disabling exception reporting is deprecated, $report_uncaught_exceptions != true in %s%eexception_propagation_2.php on line 8 -Deprecated: Function V8Js::getPendingException() is deprecated in %s%eexception_propagation_2.php on line 11 +Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_propagation_2.php on line 11 object(V8JsScriptException)#%d (13) { ["message":protected]=> string(49) "throw_0:1: ReferenceError: fooobar is not defined" diff --git a/tests/extensions_basic.phpt b/tests/extensions_basic.phpt index 9c0db761..308c79cd 100644 --- a/tests/extensions_basic.phpt +++ b/tests/extensions_basic.phpt @@ -14,11 +14,11 @@ $a = new V8Js('myobj', array(), array('a')); ?> ===EOF=== --EXPECTF-- -Deprecated: Function V8Js::registerExtension() is deprecated in %s%eextensions_basic.php on line 3 +Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_basic.php on line 3 -Deprecated: Function V8Js::registerExtension() is deprecated in %s%eextensions_basic.php on line 4 +Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_basic.php on line 4 -Deprecated: Function V8Js::getExtensions() is deprecated in %s%eextensions_basic.php on line 6 +Deprecated: %s V8Js::getExtensions() is deprecated in %s%eextensions_basic.php on line 6 array(2) { ["a"]=> array(2) { diff --git a/tests/extensions_circular_dependency.phpt b/tests/extensions_circular_dependency.phpt index 5c65c4b6..f015293b 100644 --- a/tests/extensions_circular_dependency.phpt +++ b/tests/extensions_circular_dependency.phpt @@ -13,11 +13,11 @@ var_dump(V8JS::getExtensions()); $a = new V8Js('myobj', array(), array('a')); ?> --EXPECTF-- -Deprecated: Function V8Js::registerExtension() is deprecated in %s%eextensions_circular_dependency.php on line 3 +Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_circular_dependency.php on line 3 -Deprecated: Function V8Js::registerExtension() is deprecated in %s%eextensions_circular_dependency.php on line 4 +Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_circular_dependency.php on line 4 -Deprecated: Function V8Js::getExtensions() is deprecated in %s%eextensions_circular_dependency.php on line 6 +Deprecated: %s V8Js::getExtensions() is deprecated in %s%eextensions_circular_dependency.php on line 6 array(2) { ["a"]=> array(2) { diff --git a/tests/extensions_error.phpt b/tests/extensions_error.phpt index b11054a5..d2210ada 100644 --- a/tests/extensions_error.phpt +++ b/tests/extensions_error.phpt @@ -33,7 +33,7 @@ var_dump($v8); --EXPECTF-- -- registerExtension -- -Deprecated: Function V8Js::registerExtension() is deprecated in %s%eextensions_error.php on line 5 +Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_error.php on line 5 -- creating V8Js object -- Error installing extension 'handlebars'. diff --git a/tests/fatal_error_ignore_non_fatals.phpt b/tests/fatal_error_ignore_non_fatals.phpt index 729577d1..1708bbd1 100644 --- a/tests/fatal_error_ignore_non_fatals.phpt +++ b/tests/fatal_error_ignore_non_fatals.phpt @@ -24,7 +24,7 @@ $js->executeString($script); ?> ===EOF=== --EXPECTF-- -Notice: Undefined variable: bar in %s%efatal_error_ignore_non_fatals.php on line 6 +%s: Undefined variable%sbar in %s%efatal_error_ignore_non_fatals.php on line 6 Warning: Foo Bar! in %s%efatal_error_ignore_non_fatals.php on line 7 blar foo diff --git a/tests/fatal_error_v8function.phpt b/tests/fatal_error_v8function.phpt index 3c48f2d5..9df4ceb8 100644 --- a/tests/fatal_error_v8function.phpt +++ b/tests/fatal_error_v8function.phpt @@ -25,7 +25,7 @@ goodbye cruel world! Fatal error: Uncaught Error: Call to undefined method Foo::bar() in %s%efatal_error_v8function.php:6 Stack trace: -#0 [internal function]: Foo->callback() +#0 %s: Foo->callback() #1 %s%efatal_error_v8function.php(14): V8Function->V8Js::V8::Invoke() #2 {main} thrown in %s%efatal_error_v8function.php on line 6 diff --git a/v8js_class.cc b/v8js_class.cc index a9ba1f3f..becac9d8 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -506,11 +506,7 @@ static PHP_METHOD(V8Js, __construct) V8JS_GLOBAL(isolate)->DefineOwnProperty(context, object_name_js, php_obj, v8::ReadOnly); /* Export public property values */ - #if (PHP_MAJOR_VERSION < 8) - HashTable *properties = zend_std_get_properties(getThis()); - #else - HashTable *properties = zend_std_get_properties(Z_OBJ_P(getThis())); - #endif + HashTable *properties = zend_std_get_properties(SINCE80(Z_OBJ_P(getThis()), getThis())); zval *value; zend_string *member; @@ -1339,15 +1335,16 @@ static SINCE74(zval*, void) v8js_write_property(SINCE80(zend_object, zval) *_obj } /* Write value to PHP object */ - SINCE74(return,) std_object_handlers.write_property(object, member, value, NULL); + SINCE74(return,) std_object_handlers.write_property(SINCE80(object, _object), SINCE80(member, _member), value, NULL); } /* }}} */ -#if PHP_VERSION_ID >= 80000 -static void v8js_unset_property(zend_object *object, zend_string *member, void **cache_slot) /* {{{ */ +static void v8js_unset_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, void **cache_slot) /* {{{ */ { - V8JS_BEGIN_CTX_OBJ(c, object) + zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); + zend_string *member = SINCE80(_member, Z_STR_P(_member)); + V8JS_BEGIN_CTX_OBJ(c, object); /* Global PHP JS object */ v8::Local object_name_js = v8::Local::New(isolate, c->object_name); v8::Local jsobj = V8JS_GLOBAL(isolate)->Get(v8_context, object_name_js).ToLocalChecked()->ToObject(v8_context).ToLocalChecked(); @@ -1360,29 +1357,11 @@ static void v8js_unset_property(zend_object *object, zend_string *member, void * /* Delete value from PHP JS object */ v8::Local key = V8JS_SYML(ZSTR_VAL(member), static_cast(ZSTR_LEN(member))); -#else -static void v8js_unset_property(zval *object, zval *member, void **cache_slot) /* {{{ */ -{ - V8JS_BEGIN_CTX(c, object) - - /* Global PHP JS object */ - v8::Local object_name_js = v8::Local::New(isolate, c->object_name); - v8::Local jsobj = V8JS_GLOBAL(isolate)->Get(v8_context, object_name_js).ToLocalChecked()->ToObject(v8_context).ToLocalChecked(); - - if (Z_STRLEN_P(member) > std::numeric_limits::max()) { - zend_throw_exception(php_ce_v8js_exception, - "Property name exceeds maximum supported length", 0); - return; - } - - /* Delete value from PHP JS object */ - v8::Local key = V8JS_SYML(Z_STRVAL_P(member), static_cast(Z_STRLEN_P(member))); -#endif jsobj->Delete(v8_context, key); /* Unset from PHP object */ - std_object_handlers.unset_property(object, member, NULL); + std_object_handlers.unset_property(SINCE80(object, _object), SINCE80(member, _member), NULL); } /* }}} */ diff --git a/v8js_convert.cc b/v8js_convert.cc index b70d20ff..a8ef6dc9 100644 --- a/v8js_convert.cc +++ b/v8js_convert.cc @@ -148,11 +148,7 @@ v8::Local zval_to_v8js(zval *value, v8::Isolate *isolate) /* {{{ */ ce = php_date_get_date_ce(); if (instanceof_function(Z_OBJCE_P(value), ce)) { zval dtval; - #if PHP_VERSION_ID >= 80000 - zend_call_method_with_0_params(Z_OBJ_P(value), NULL, NULL, "getTimestamp", &dtval); - #else - zend_call_method_with_0_params(value, NULL, NULL, "getTimestamp", &dtval); - #endif + zend_call_method_with_0_params(SINCE80(Z_OBJ_P(value), value), NULL, NULL, "getTimestamp", &dtval); v8::Date::New(isolate->GetEnteredOrMicrotaskContext(), ((double)Z_LVAL(dtval) * 1000.0)).ToLocal(&jsValue); zval_dtor(&dtval); } else diff --git a/v8js_exceptions.cc b/v8js_exceptions.cc index 89903d6e..fa1d08f9 100644 --- a/v8js_exceptions.cc +++ b/v8js_exceptions.cc @@ -50,13 +50,8 @@ void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8:: object_init_ex(return_value, php_ce_v8js_script_exception); -#if PHP_VERSION_ID >= 80000 #define PHPV8_EXPROP(type, name, value) \ - zend_update_property##type(php_ce_v8js_script_exception, Z_OBJ_P(return_value), #name, sizeof(#name) - 1, value); -#else -#define PHPV8_EXPROP(type, name, value) \ - zend_update_property##type(php_ce_v8js_script_exception, return_value, #name, sizeof(#name) - 1, value); -#endif + zend_update_property##type(php_ce_v8js_script_exception, SINCE80(Z_OBJ_P(return_value), return_value), #name, sizeof(#name) - 1, value); if (tc_message.IsEmpty()) { @@ -134,7 +129,6 @@ void v8js_throw_script_exception(v8::Isolate *isolate, v8::TryCatch *try_catch) } } /* }}} */ -#if PHP_VERSION_ID >= 80000 #define V8JS_EXCEPTION_METHOD(property) \ static PHP_METHOD(V8JsScriptException, get##property) \ { \ @@ -143,22 +137,9 @@ void v8js_throw_script_exception(v8::Isolate *isolate, v8::TryCatch *try_catch) if (zend_parse_parameters_none() == FAILURE) { \ return; \ } \ - value = zend_read_property(php_ce_v8js_script_exception, Z_OBJ_P(getThis()), #property, sizeof(#property) - 1, 0, &rv); \ + value = zend_read_property(php_ce_v8js_script_exception, SINCE80(Z_OBJ_P(getThis()), getThis()), #property, sizeof(#property) - 1, 0, &rv); \ RETURN_ZVAL(value, 1, 0); \ } -#else -#define V8JS_EXCEPTION_METHOD(property) \ - static PHP_METHOD(V8JsScriptException, get##property) \ - { \ - zval *value, rv; \ - \ - if (zend_parse_parameters_none() == FAILURE) { \ - return; \ - } \ - value = zend_read_property(php_ce_v8js_script_exception, getThis(), #property, sizeof(#property) - 1, 0, &rv); \ - RETURN_ZVAL(value, 1, 0); \ - } -#endif /* {{{ proto string V8JsEScriptxception::getJsFileName() diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 59263aa1..6b3b59ba 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -643,11 +643,11 @@ v8::Local v8js_named_property_callback(v8::Local property_n zval php_value; zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); - #if PHP_VERSION_ID >= 80000 - zend_object &zobject = *object; - #else + #if PHP_VERSION_ID < 80000 zval zobject; ZVAL_OBJ(&zobject, object); + #else + zend_object &zobject = *object; #endif v8js_function_tmpl_t *tmpl_ptr = reinterpret_cast(self->GetAlignedPointerFromInternalField(0)); @@ -803,11 +803,7 @@ v8::Local v8js_named_property_callback(v8::Local property_n const zend_object_handlers *h = object->handlers; if (callback_type == V8JS_PROP_QUERY) { - #if PHP_VERSION_ID >= 80000 - if (h->has_property(&zobject, Z_STR_P(&zname), 0, NULL)) { - #else - if (h->has_property(&zobject, &zname, 0, NULL)) { - #endif + if (h->has_property(&zobject, SINCE80(Z_STR_P(&zname), &zname), 0, NULL)) { ret_value = V8JS_UINT(v8::None); } else { ret_value = v8::Local(); // empty handle @@ -818,11 +814,7 @@ v8::Local v8js_named_property_callback(v8::Local property_n if(!property_info || (property_info != ZEND_WRONG_PROPERTY_INFO && property_info->flags & ZEND_ACC_PUBLIC)) { - #if PHP_VERSION_ID >= 80000 - h->unset_property(&zobject, Z_STR_P(&zname), NULL); - #else - h->unset_property(&zobject, &zname, NULL); - #endif + h->unset_property(&zobject, SINCE80(Z_STR_P(&zname), &zname), NULL); ret_value = V8JS_TRUE(); } else { diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index 2fce6ba4..a4a30971 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -45,46 +45,17 @@ static zend_object_handlers v8js_v8generator_handlers; #define V8JS_V8_INVOKE_FUNC_NAME "V8Js::V8::Invoke" /* V8 Object handlers */ -#if PHP_VERSION_ID >= 80000 -static int v8js_v8object_has_property(zend_object *object, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */ -{ - int retval = false; - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); - - if (!obj->ctx) - { - zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); - return false; - } - - V8JS_CTX_PROLOGUE_EX(obj->ctx, false); - v8::Local v8obj = v8::Local::New(isolate, obj->v8obj); - v8::Local jsObj; - - if (!v8obj->IsObject() || !v8obj->ToObject(v8_context).ToLocal(&jsObj)) - { - return false; - } - - if (ZSTR_LEN(member) > std::numeric_limits::max()) - { - zend_throw_exception(php_ce_v8js_exception, - "Member name length exceeds maximum supported length", 0); - return false; - } - - v8::Local jsKey = V8JS_ZSYM(member); -#else -static int v8js_v8object_has_property(zval *object, zval *member, int has_set_exists, void **cache_slot) /* {{{ */ +static int v8js_v8object_has_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, int has_set_exists, void **cache_slot) /* {{{ */ { + zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); + zend_string *member = SINCE80(_member, Z_STR_P(_member)); /* param has_set_exists: * 0 (has) whether property exists and is not NULL - isset() * 1 (set) whether property exists and is true-ish - empty() * 2 (exists) whether property exists - property_exists() */ int retval = false; - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); if (!obj->ctx) { @@ -97,20 +68,19 @@ static int v8js_v8object_has_property(zval *object, zval *member, int has_set_ex v8::Local v8obj = v8::Local::New(isolate, obj->v8obj); v8::Local jsObj; - if (Z_TYPE_P(member) != IS_STRING || !v8obj->IsObject() || !v8obj->ToObject(v8_context).ToLocal(&jsObj)) + if (!v8obj->IsObject() || !v8obj->ToObject(v8_context).ToLocal(&jsObj)) { return false; } - if (Z_STRLEN_P(member) > std::numeric_limits::max()) + if (ZSTR_LEN(member) > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, "Member name length exceeds maximum supported length", 0); return false; } - v8::Local jsKey = V8JS_ZSYM(Z_STR_P(member)); -#endif + v8::Local jsKey = V8JS_ZSYM(member); /* Skip any prototype properties */ if (!jsObj->HasRealNamedProperty(v8_context, jsKey).FromMaybe(false) && !jsObj->HasRealNamedCallbackProperty(v8_context, jsKey).FromMaybe(false)) { @@ -158,9 +128,11 @@ static int v8js_v8object_has_property(zval *object, zval *member, int has_set_ex } /* }}} */ -#if PHP_VERSION_ID >= 80000 -static zval *v8js_v8object_read_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */ +static zval *v8js_v8object_read_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, int type, void **cache_slot, zval *rv) /* {{{ */ { + zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); + zend_string *member = SINCE80(_member, Z_STR_P(_member)); + zval *retval = rv; v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); @@ -185,34 +157,7 @@ static zval *v8js_v8object_read_property(zend_object *object, zend_string *membe v8::Local jsKey = V8JS_ZSYM(member); v8::Local jsObj = v8obj->ToObject(v8_context).ToLocalChecked(); -#else -static zval *v8js_v8object_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */ -{ - zval *retval = rv; - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); - - if (!obj->ctx) - { - zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); - return SINCE74(object, retval); - } - - V8JS_CTX_PROLOGUE_EX(obj->ctx, retval); - v8::Local v8obj = v8::Local::New(isolate, obj->v8obj); - - if (Z_TYPE_P(member) == IS_STRING && v8obj->IsObject()) - { - if (Z_STRLEN_P(member) > std::numeric_limits::max()) - { - zend_throw_exception(php_ce_v8js_exception, - "Member name length exceeds maximum supported length", 0); - return retval; - } - v8::Local jsKey = V8JS_ZSYM(Z_STR_P(member)); - v8::Local jsObj = v8obj->ToObject(v8_context).ToLocalChecked(); -#endif /* Skip any prototype properties */ if (jsObj->HasRealNamedProperty(v8_context, jsKey).FromMaybe(false) || jsObj->HasRealNamedCallbackProperty(v8_context, jsKey).FromMaybe(false)) { @@ -229,19 +174,17 @@ static zval *v8js_v8object_read_property(zval *object, zval *member, int type, v } /* }}} */ -#if PHP_VERSION_ID >= 80000 -static zval *v8js_v8object_get_property_ptr_ptr(zend_object *object, zend_string *member, int type, void **cache_slot) /* {{{ */ -#else -static zval *v8js_v8object_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot) /* {{{ */ -#endif +static zval *v8js_v8object_get_property_ptr_ptr(SINCE80(zend_object, zval) *object, SINCE80(zend_string, zval) *member, int type, void **cache_slot) /* {{{ */ { return NULL; } /* }}} */ -#if PHP_VERSION_ID >= 80000 -static SINCE74(zval *, void) v8js_v8object_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot) /* {{{ */ +static SINCE74(zval *, void) v8js_v8object_write_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, zval *value, void **cache_slot) /* {{{ */ { + zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); + zend_string *member = SINCE80(_member, Z_STR_P(_member)); + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); if (!obj->ctx) @@ -266,41 +209,16 @@ static SINCE74(zval *, void) v8js_v8object_write_property(zend_object *object, z { v8obj->CreateDataProperty(v8_context, V8JS_ZSYM(member), zval_to_v8js(value, isolate)); } -#else -static SINCE74(zval *, void) v8js_v8object_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */ -{ - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); - if (!obj->ctx) - { - zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); - return SINCE74(value, ); - } - - V8JS_CTX_PROLOGUE_EX(obj->ctx, SINCE74(value, )); - v8::Local v8objHandle = v8::Local::New(isolate, obj->v8obj); - - if (Z_STRLEN_P(member) > std::numeric_limits::max()) - { - zend_throw_exception(php_ce_v8js_exception, - "Member name length exceeds maximum supported length", 0); - return SINCE74(value, ); - } - - v8::Local v8obj; - if (v8objHandle->IsObject() && v8objHandle->ToObject(v8_context).ToLocal(&v8obj)) - { - v8obj->CreateDataProperty(v8_context, V8JS_ZSYM(Z_STR_P(member)), zval_to_v8js(value, isolate)); - } -#endif return SINCE74(value, ); } /* }}} */ -#if PHP_VERSION_ID >= 80000 -static void v8js_v8object_unset_property(zend_object *object, zend_string *member, void **cache_slot) /* {{{ */ +static void v8js_v8object_unset_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, void **cache_slot) /* {{{ */ { + zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); + zend_string *member = SINCE80(_member, Z_STR_P(_member)); + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); if (!obj->ctx) @@ -326,46 +244,12 @@ static void v8js_v8object_unset_property(zend_object *object, zend_string *membe v8obj->Delete(v8_context, V8JS_ZSYM(member)); } } -#else -static void v8js_v8object_unset_property(zval *object, zval *member, void **cache_slot) /* {{{ */ -{ - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); - - if (!obj->ctx) - { - zend_throw_exception(php_ce_v8js_exception, - "Can't access V8Object after V8Js instance is destroyed!", 0); - return; - } - - V8JS_CTX_PROLOGUE(obj->ctx); - v8::Local v8objHandle = v8::Local::New(isolate, obj->v8obj); - - if (Z_STRLEN_P(member) > std::numeric_limits::max()) - { - zend_throw_exception(php_ce_v8js_exception, - "Member name length exceeds maximum supported length", 0); - return; - } - - v8::Local v8obj; - if (v8objHandle->IsObject() && v8objHandle->ToObject(v8_context).ToLocal(&v8obj)) - { - v8obj->Delete(v8_context, V8JS_ZSYM(Z_STR_P(member))); - } -} -#endif /* }}} */ -#if PHP_VERSION_ID >= 80000 -static HashTable *v8js_v8object_get_properties(zend_object *object) /* {{{ */ -{ - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); -#else -static HashTable *v8js_v8object_get_properties(zval *object) /* {{{ */ +static HashTable *v8js_v8object_get_properties(SINCE80(zend_object, zval) *object) /* {{{ */ { - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); -#endif + v8js_v8object *obj = SINCE80(Z_V8JS_V8OBJECT_OBJ, Z_V8JS_V8OBJECT_OBJ_P)(object); + if (obj->properties == NULL) { #if PHP_VERSION_ID < 70300 @@ -411,11 +295,7 @@ static HashTable *v8js_v8object_get_properties(zval *object) /* {{{ */ } /* }}} */ -#if PHP_VERSION_ID >= 80000 -static HashTable *v8js_v8object_get_debug_info(zend_object *object, int *is_temp) /* {{{ */ -#else -static HashTable *v8js_v8object_get_debug_info(zval *object, int *is_temp) /* {{{ */ -#endif +static HashTable *v8js_v8object_get_debug_info(SINCE80(zend_object, zval) *object, int *is_temp) /* {{{ */ { *is_temp = 0; return v8js_v8object_get_properties(object); @@ -544,11 +424,7 @@ static ZEND_FUNCTION(zend_v8object_func) static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_string *method, const zval *key) /* {{{ */ { v8js_v8object *obj = v8js_v8object_fetch_object(*object_ptr); -#if PHP_VERSION_ID < 80000 - zend_function *f; -#else - zend_internal_function *f; -#endif + SINCE80(zend_internal_function, zend_function) *f; if (!obj->ctx) { @@ -708,15 +584,13 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I #if PHP_VERSION_ID >= 80000 static int v8js_v8object_get_closure(zend_object *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr, bool call) /* {{{ */ -{ - zend_internal_function *invoke; - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); #else static int v8js_v8object_get_closure(zval *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr) /* {{{ */ -{ - zend_function *invoke; - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); #endif +{ + SINCE80(zend_internal_function, zend_function) *invoke; + v8js_v8object *obj = SINCE80(Z_V8JS_V8OBJECT_OBJ, Z_V8JS_V8OBJECT_OBJ_P)(object); + if (!obj->ctx) { zend_throw_exception(php_ce_v8js_exception, @@ -747,11 +621,7 @@ static int v8js_v8object_get_closure(zval *object, zend_class_entry **ce_ptr, ze if (zobj_ptr) { -#if PHP_VERSION_ID >= 80000 - *zobj_ptr = object; -#else - *zobj_ptr = Z_OBJ_P(object); -#endif + *zobj_ptr = SINCE80(object, Z_OBJ_P(object)); } *ce_ptr = NULL; @@ -1176,9 +1046,7 @@ PHP_MINIT_FUNCTION(v8js_v8object_class) /* {{{ */ v8js_v8object_handlers.unset_property = v8js_v8object_unset_property; v8js_v8object_handlers.get_properties = v8js_v8object_get_properties; v8js_v8object_handlers.get_method = v8js_v8object_get_method; -#if PHP_VERSION_ID < 80000 - v8js_v8object_handlers.call_method = v8js_v8object_call_method; -#endif + SINCE80(, v8js_v8object_handlers.call_method = v8js_v8object_call_method); v8js_v8object_handlers.get_debug_info = v8js_v8object_get_debug_info; v8js_v8object_handlers.get_closure = v8js_v8object_get_closure; v8js_v8object_handlers.offset = XtOffsetOf(struct v8js_v8object, std); From 1db8f8de5e83f62de6d16986973de252e101170b Mon Sep 17 00:00:00 2001 From: Albert Date: Mon, 23 May 2022 15:41:57 +0800 Subject: [PATCH 04/64] Support PHP8.1+ --- tests/array_access.phpt | 10 ++++---- tests/array_access_001.phpt | 10 ++++---- tests/array_access_002.phpt | 10 ++++---- tests/array_access_003.phpt | 10 ++++---- tests/array_access_004.phpt | 10 ++++---- tests/array_access_005.phpt | 10 ++++---- tests/array_access_006.phpt | 10 ++++---- tests/array_access_007.phpt | 10 ++++---- tests/array_access_008.phpt | 10 ++++---- tests/array_access_basic2.phpt | 10 ++++---- tests/exception_clearing.phpt | 2 +- tests/exception_propagation_2.phpt | 2 +- tests/exception_propagation_3.phpt | 2 +- v8js_object_export.cc | 4 +++ v8js_v8.cc | 4 +++ v8js_v8.h | 39 ++++++++++++++++++++++++++++++ v8js_v8object_class.cc | 20 +++++++-------- 17 files changed, 110 insertions(+), 63 deletions(-) diff --git a/tests/array_access.phpt b/tests/array_access.phpt index 6792c614..9b02dcc2 100644 --- a/tests/array_access.phpt +++ b/tests/array_access.phpt @@ -8,23 +8,23 @@ v8js.use_array_access = 1 = 0 && $offset <= 20; } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { return 19 - $offset; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { throw new Exception('Not implemented'); } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { throw new Exception('Not implemented'); } - public function count() { + public function count(): int { return 20; } } diff --git a/tests/array_access_001.phpt b/tests/array_access_001.phpt index dd92bbd9..49a2d2e6 100644 --- a/tests/array_access_001.phpt +++ b/tests/array_access_001.phpt @@ -10,23 +10,23 @@ v8js.use_array_access = 1 class MyArray implements ArrayAccess, Countable { private $data = Array('one', 'two', 'three'); - public function offsetExists($offset) { + public function offsetExists($offset): bool { return isset($this->data[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { return $this->data[$offset]; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { $this->data[$offset] = $value; } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { throw new Exception('Not implemented'); } - public function count() { + public function count(): int { return count($this->data); } diff --git a/tests/array_access_002.phpt b/tests/array_access_002.phpt index dde425cc..2f3af8ba 100644 --- a/tests/array_access_002.phpt +++ b/tests/array_access_002.phpt @@ -10,24 +10,24 @@ v8js.use_array_access = 1 class MyArray implements ArrayAccess, Countable { private $data = Array('one', 'two', 'three'); - public function offsetExists($offset) { + public function offsetExists($offset): bool { return isset($this->data[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { return $this->data[$offset]; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { echo "set[$offset] = $value\n"; $this->data[$offset] = $value; } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { throw new Exception('Not implemented'); } - public function count() { + public function count(): int { return count($this->data); } } diff --git a/tests/array_access_003.phpt b/tests/array_access_003.phpt index 22c7f091..f894f8b0 100644 --- a/tests/array_access_003.phpt +++ b/tests/array_access_003.phpt @@ -10,24 +10,24 @@ v8js.use_array_access = 1 class MyArray implements ArrayAccess, Countable { private $data = Array('one', 'two', 'three'); - public function offsetExists($offset) { + public function offsetExists($offset): bool { return isset($this->data[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { return $this->data[$offset]; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { echo "set[$offset] = $value\n"; $this->data[$offset] = $value; } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { throw new Exception('Not implemented'); } - public function count() { + public function count(): int { echo 'count() = ', count($this->data), "\n"; return count($this->data); } diff --git a/tests/array_access_004.phpt b/tests/array_access_004.phpt index fa5160a0..89da71a9 100644 --- a/tests/array_access_004.phpt +++ b/tests/array_access_004.phpt @@ -19,24 +19,24 @@ class MyArray implements ArrayAccess, Countable { * accessibly as $length. */ public $length = 42; - public function offsetExists($offset) { + public function offsetExists($offset): bool { return isset($this->data[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { return $this->data[$offset]; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { echo "set[$offset] = $value\n"; $this->data[$offset] = $value; } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { throw new Exception('Not implemented'); } - public function count() { + public function count(): int { return count($this->data); } } diff --git a/tests/array_access_005.phpt b/tests/array_access_005.phpt index afe8492d..7c73a4a0 100644 --- a/tests/array_access_005.phpt +++ b/tests/array_access_005.phpt @@ -10,24 +10,24 @@ v8js.use_array_access = 1 class MyArray implements ArrayAccess, Countable { private $data = Array('one', 'two', 'three'); - public function offsetExists($offset) { + public function offsetExists($offset): bool { return isset($this->data[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { return $this->data[$offset]; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { echo "set[$offset] = $value\n"; $this->data[$offset] = $value; } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { throw new Exception('Not implemented'); } - public function count() { + public function count(): int { return count($this->data); } diff --git a/tests/array_access_006.phpt b/tests/array_access_006.phpt index 95cdf9c1..53fff258 100644 --- a/tests/array_access_006.phpt +++ b/tests/array_access_006.phpt @@ -10,24 +10,24 @@ v8js.use_array_access = 1 class MyArray implements ArrayAccess, Countable { private $data = Array('one', 'two', 'three', null, 'five'); - public function offsetExists($offset) { + public function offsetExists($offset): bool { return isset($this->data[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { return $this->data[$offset]; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { echo "set[$offset] = $value\n"; $this->data[$offset] = $value; } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { throw new Exception('Not implemented'); } - public function count() { + public function count(): int { return count($this->data); } } diff --git a/tests/array_access_007.phpt b/tests/array_access_007.phpt index 724176ec..0f8d59f0 100644 --- a/tests/array_access_007.phpt +++ b/tests/array_access_007.phpt @@ -10,26 +10,26 @@ v8js.use_array_access = 1 class MyArray implements ArrayAccess, Countable { private $data = Array('one', 'two', 'three'); - public function offsetExists($offset) { + public function offsetExists($offset): bool { return isset($this->data[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { if(!$this->offsetExists($offset)) { return null; } return $this->data[$offset]; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { $this->data[$offset] = $value; } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { unset($this->data[$offset]); } - public function count() { + public function count(): int { return max(array_keys($this->data)) + 1; } } diff --git a/tests/array_access_008.phpt b/tests/array_access_008.phpt index 23507eb1..48ee085b 100644 --- a/tests/array_access_008.phpt +++ b/tests/array_access_008.phpt @@ -10,23 +10,23 @@ v8js.use_array_access = 1 class MyArray implements ArrayAccess, Countable { private $data = Array('one', null, 'three'); - public function offsetExists($offset) { + public function offsetExists($offset): bool { return isset($this->data[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { return $this->data[$offset]; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { $this->data[$offset] = $value; } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { unset($this->data[$offset]); } - public function count() { + public function count(): int { return max(array_keys($this->data)) + 1; } } diff --git a/tests/array_access_basic2.phpt b/tests/array_access_basic2.phpt index 925eb2cd..0dcdc440 100644 --- a/tests/array_access_basic2.phpt +++ b/tests/array_access_basic2.phpt @@ -10,23 +10,23 @@ v8js.use_array_access = 1 class MyArray implements ArrayAccess, Countable { private $data = array('one', 'two', 'three'); - public function offsetExists($offset) { + public function offsetExists($offset): bool { return isset($this->data[$offset]); } - public function offsetGet($offset) { + public function offsetGet($offset): mixed { return $this->data[$offset]; } - public function offsetSet($offset, $value) { + public function offsetSet($offset, $value): void { $this->data[$offset] = $value; } - public function offsetUnset($offset) { + public function offsetUnset($offset): void { throw new Exception('Not implemented'); } - public function count() { + public function count(): int { return count($this->data); } } diff --git a/tests/exception_clearing.phpt b/tests/exception_clearing.phpt index 3646c5a9..0d797a6e 100644 --- a/tests/exception_clearing.phpt +++ b/tests/exception_clearing.phpt @@ -5,7 +5,7 @@ Test V8::executeString() : Exception clearing test --FILE-- getPendingException()); diff --git a/tests/exception_propagation_2.phpt b/tests/exception_propagation_2.phpt index c808e3aa..9a879c63 100644 --- a/tests/exception_propagation_2.phpt +++ b/tests/exception_propagation_2.phpt @@ -10,7 +10,7 @@ class Foo { public function __construct() { - $this->v8 = new V8Js(null, array(), array(), false); + $this->v8 = new V8Js('', array(), array(), false); $this->v8->foo = $this; $this->v8->executeString('fooobar', 'throw_0'); var_dump($this->v8->getPendingException()); diff --git a/tests/exception_propagation_3.phpt b/tests/exception_propagation_3.phpt index bc93c1d8..1bdaab3c 100644 --- a/tests/exception_propagation_3.phpt +++ b/tests/exception_propagation_3.phpt @@ -10,7 +10,7 @@ class Foo { public function __construct() { - $this->v8 = new V8Js(null, array(), array(), false); + $this->v8 = new V8Js('', array(), array(), false); $this->v8->foo = $this; $this->v8->executeString('function foobar() { throw new SyntaxError(); }', 'throw_1'); $this->v8->executeString('try { foobar(); } catch (e) { print(e + " caught in JS!\n"); }', 'trycatch1'); diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 6b3b59ba..fa9a9fc7 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -158,6 +158,10 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c fcc.called_scope = object->ce; fcc.object = object; + if (!EG(current_execute_data) || !EG(current_execute_data)->func) { + EG(current_execute_data) = NULL; + } + zend_call_function(&fci, &fcc); } zend_catch { diff --git a/v8js_v8.cc b/v8js_v8.cc index 0b5eab1f..aa0f71de 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -178,6 +178,10 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value, efree(timer_ctx); if(!V8JSG(fatal_error_abort)) { + if (!EG(current_execute_data) || !EG(current_execute_data)->func) { + EG(current_execute_data) = NULL; + } + char exception_string[64]; if (c->time_limit_hit) { diff --git a/v8js_v8.h b/v8js_v8.h index 7adc67d4..59b374d0 100644 --- a/v8js_v8.h +++ b/v8js_v8.h @@ -100,6 +100,45 @@ int v8js_get_properties_hash(v8::Local jsValue, HashTable *retval, in #define SINCE80(x,y) x #endif +#if PHP_VERSION_ID < 70200 +#define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \ + ZEND_BEGIN_ARG_INFO_EX(name, return_reference, required_num_args, allow_null) +#endif + +// polyfill for ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX, which changes between 7.1 and 7.2 +#if PHP_VERSION_ID < 70200 +#define V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, /*class_name*/ 0, allow_null) +#else +#define V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) +#endif + +// In PHP 8.1, mismatched tentative return types emit a deprecation notice. +// https://wiki.php.net/rfc/internal_method_return_types +// +// When compiling for earlier php versions, the return type is dropped. +#if PHP_VERSION_ID < 80100 +#define ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ + ZEND_BEGIN_ARG_INFO_EX(name, return_reference, required_num_args, allow_null) +#endif + +#ifndef IS_VOID +#define IS_VOID 99 +#endif + +#ifndef IS_MIXED +#define IS_MIXED 99 +#endif + +#ifndef _IS_BOOL +#define _IS_BOOL 99 +#endif + +#ifndef IS_LONG +#define IS_LONG 99 +#endif + #endif /* V8JS_V8_H */ diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index a4a30971..a78412dd 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -853,7 +853,7 @@ PHP_METHOD(V8Generator, __wakeup) } /* }}} */ -/* {{{ mixed V8Generator::current() +/* {{{ mixed V8Generator::current(): mixed */ PHP_METHOD(V8Generator, current) { @@ -868,7 +868,7 @@ PHP_METHOD(V8Generator, current) } /* }}} */ -/* {{{ scalar V8Generator::key() +/* {{{ scalar V8Generator::key(): mixed */ PHP_METHOD(V8Generator, key) { @@ -876,7 +876,7 @@ PHP_METHOD(V8Generator, key) } /* }}} */ -/* {{{ void V8Generator::next() +/* {{{ void V8Generator::next(): void */ PHP_METHOD(V8Generator, next) { @@ -885,7 +885,7 @@ PHP_METHOD(V8Generator, next) } /* }}} */ -/* {{{ void V8Generator::rewind() +/* {{{ void V8Generator::rewind(): void */ PHP_METHOD(V8Generator, rewind) { @@ -901,7 +901,7 @@ PHP_METHOD(V8Generator, rewind) } /* }}} */ -/* {{{ boolean V8Generator::valid() +/* {{{ boolean V8Generator::valid(): bool */ PHP_METHOD(V8Generator, valid) { @@ -982,19 +982,19 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_v8generator_wakeup, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_v8generator_current, 0) +V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_current, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_v8generator_key, 0) +V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_key, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_v8generator_next, 0) +V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_next, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_v8generator_rewind, 0) +V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_rewind, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_v8generator_valid, 0) +V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_valid, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() static const zend_function_entry v8js_v8generator_methods[] = {/* {{{ */ From cb7b3dcc296a315c756f3dcde58860737d625438 Mon Sep 17 00:00:00 2001 From: Albert Date: Fri, 27 May 2022 10:47:44 +0800 Subject: [PATCH 05/64] Optimize and fix test reference from @redbullmarky --- tests/array_access.phpt | 54 ++++++++++----- tests/array_access_001.phpt | 66 +++++++++++++----- tests/array_access_002.phpt | 60 ++++++++++++----- tests/array_access_003.phpt | 103 ++++++++++++++++++++--------- tests/array_access_004.phpt | 81 ++++++++++++++++------- tests/array_access_005.phpt | 70 ++++++++++++++------ tests/array_access_006.phpt | 60 ++++++++++++----- tests/array_access_007.phpt | 66 ++++++++++++------ tests/array_access_008.phpt | 57 +++++++++++----- tests/array_access_basic2.phpt | 59 ++++++++++++----- tests/exception_clearing.phpt | 2 +- tests/exception_propagation_2.phpt | 2 +- tests/exception_propagation_3.phpt | 2 +- tests/issue_250_001.phpt | 26 ++------ tests/var_dump.phpt | 4 ++ v8js_class.cc | 4 +- v8js_object_export.cc | 4 -- v8js_v8.cc | 4 -- v8js_v8object_class.cc | 32 ++++++--- 19 files changed, 520 insertions(+), 236 deletions(-) diff --git a/tests/array_access.phpt b/tests/array_access.phpt index 9b02dcc2..31637340 100644 --- a/tests/array_access.phpt +++ b/tests/array_access.phpt @@ -7,25 +7,49 @@ v8js.use_array_access = 1 --FILE-- = 0 && $offset <= 20; - } +if (PHP_VERSION_ID < 80000) { + class MyArray implements ArrayAccess, Countable { + public function offsetExists($offset) { + return $offset >= 0 && $offset <= 20; + } - public function offsetGet($offset): mixed { - return 19 - $offset; - } + public function offsetGet($offset) { + return 19 - $offset; + } - public function offsetSet($offset, $value): void { - throw new Exception('Not implemented'); - } + public function offsetSet($offset, $value) { + throw new Exception('Not implemented'); + } - public function offsetUnset($offset): void { - throw new Exception('Not implemented'); - } + public function offsetUnset($offset) { + throw new Exception('Not implemented'); + } - public function count(): int { - return 20; + public function count() { + return 20; + } + } +} else { + class MyArray implements ArrayAccess, Countable { + public function offsetExists($offset): bool { + return $offset >= 0 && $offset <= 20; + } + + public function offsetGet(mixed $offset): mixed { + return 19 - $offset; + } + + public function offsetSet(mixed $offset, mixed $value): void { + throw new Exception('Not implemented'); + } + + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } + + public function count(): int { + return 20; + } } } diff --git a/tests/array_access_001.phpt b/tests/array_access_001.phpt index 49a2d2e6..92aa2642 100644 --- a/tests/array_access_001.phpt +++ b/tests/array_access_001.phpt @@ -7,31 +7,61 @@ v8js.use_array_access = 1 --FILE-- data[$offset]); - } + public function offsetExists($offset) { + return isset($this->data[$offset]); + } - public function offsetGet($offset): mixed { - return $this->data[$offset]; - } + public function offsetGet($offset) { + return $this->data[$offset]; + } - public function offsetSet($offset, $value): void { - $this->data[$offset] = $value; - } + public function offsetSet($offset, $value) { + $this->data[$offset] = $value; + } - public function offsetUnset($offset): void { - throw new Exception('Not implemented'); - } + public function offsetUnset($offset) { + throw new Exception('Not implemented'); + } + + public function count() { + return count($this->data); + } - public function count(): int { - return count($this->data); + public function push($value) { + $this->data[] = $value; + } } +} else { + class MyArray implements ArrayAccess, Countable { + private $data = Array('one', 'two', 'three'); + + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } + + public function count(): int { + return count($this->data); + } - public function push($value) { - $this->data[] = $value; + public function push($value) { + $this->data[] = $value; + } } } diff --git a/tests/array_access_002.phpt b/tests/array_access_002.phpt index 2f3af8ba..f7db125a 100644 --- a/tests/array_access_002.phpt +++ b/tests/array_access_002.phpt @@ -6,29 +6,55 @@ Test V8::executeString() : Use ArrayAccess with JavaScript native push method v8js.use_array_access = 1 --FILE-- data[$offset]); + } - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } + public function offsetGet($offset) { + return $this->data[$offset]; + } - public function offsetGet($offset): mixed { - return $this->data[$offset]; - } + public function offsetSet($offset, $value) { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } - public function offsetSet($offset, $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } + public function offsetUnset($offset) { + throw new Exception('Not implemented'); + } - public function offsetUnset($offset): void { - throw new Exception('Not implemented'); + public function count() { + return count($this->data); + } } - - public function count(): int { - return count($this->data); +} else { + class MyArray implements ArrayAccess, Countable { + private $data = Array('one', 'two', 'three'); + + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } + + public function count(): int { + return count($this->data); + } } } diff --git a/tests/array_access_003.phpt b/tests/array_access_003.phpt index f894f8b0..f4882727 100644 --- a/tests/array_access_003.phpt +++ b/tests/array_access_003.phpt @@ -6,40 +6,77 @@ Test V8::executeString() : Export PHP methods on ArrayAccess objects v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset): mixed { - return $this->data[$offset]; +if (PHP_VERSION_ID < 80000) { + class MyArray implements ArrayAccess, Countable { + private $data = Array('one', 'two', 'three'); + + public function offsetExists($offset) { + return isset($this->data[$offset]); + } + + public function offsetGet($offset) { + return $this->data[$offset]; + } + + public function offsetSet($offset, $value) { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } + + public function offsetUnset($offset) { + throw new Exception('Not implemented'); + } + + public function count() { + echo 'count() = ', count($this->data), "\n"; + return count($this->data); + } + + public function phpSidePush($value) { + echo "push << $value\n"; + $this->data[] = $value; + } + + public function push($value) { + echo "php-side-push << $value\n"; + $this->data[] = $value; + } } - - public function offsetSet($offset, $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } - - public function offsetUnset($offset): void { - throw new Exception('Not implemented'); - } - - public function count(): int { - echo 'count() = ', count($this->data), "\n"; - return count($this->data); - } - - public function phpSidePush($value) { - echo "push << $value\n"; - $this->data[] = $value; - } - - public function push($value) { - echo "php-side-push << $value\n"; - $this->data[] = $value; +} else { + class MyArray implements ArrayAccess, Countable { + private $data = Array('one', 'two', 'three'); + + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } + + public function count(): int { + echo 'count() = ', count($this->data), "\n"; + return count($this->data); + } + + public function phpSidePush($value) { + echo "push << $value\n"; + $this->data[] = $value; + } + + public function push($value) { + echo "php-side-push << $value\n"; + $this->data[] = $value; + } } } diff --git a/tests/array_access_004.phpt b/tests/array_access_004.phpt index 89da71a9..c5c664b0 100644 --- a/tests/array_access_004.phpt +++ b/tests/array_access_004.phpt @@ -6,38 +6,73 @@ Test V8::executeString() : Export PHP properties on ArrayAccess objects v8js.use_array_access = 1 --FILE-- data[$offset]); + } - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } + public function offsetGet($offset) { + return $this->data[$offset]; + } - public function offsetGet($offset): mixed { - return $this->data[$offset]; - } + public function offsetSet($offset, $value) { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } - public function offsetSet($offset, $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } + public function offsetUnset($offset) { + throw new Exception('Not implemented'); + } - public function offsetUnset($offset): void { - throw new Exception('Not implemented'); + public function count() { + return count($this->data); + } } +} else { + class MyArray implements ArrayAccess, Countable { + private $data = Array('one', 'two', 'three'); + + private $privFoo = 23; + protected $protFoo = 23; + public $pubFoo = 42; + + /* We can have a length property on the PHP object, but the length property + * of the JS object will still call count() method. Anyways it should be + * accessibly as $length. */ + public $length = 42; + + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } - public function count(): int { - return count($this->data); + public function count(): int { + return count($this->data); + } } } diff --git a/tests/array_access_005.phpt b/tests/array_access_005.phpt index 7c73a4a0..ba6bc732 100644 --- a/tests/array_access_005.phpt +++ b/tests/array_access_005.phpt @@ -6,33 +6,63 @@ Test V8::executeString() : Export __invoke method on ArrayAccess objects v8js.use_array_access = 1 --FILE-- data[$offset]); + } - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } + public function offsetGet($offset) { + return $this->data[$offset]; + } - public function offsetGet($offset): mixed { - return $this->data[$offset]; - } + public function offsetSet($offset, $value) { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } - public function offsetSet($offset, $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } + public function offsetUnset($offset) { + throw new Exception('Not implemented'); + } - public function offsetUnset($offset): void { - throw new Exception('Not implemented'); - } + public function count() { + return count($this->data); + } - public function count(): int { - return count($this->data); + public function __invoke() { + echo "__invoke called!\n"; + } } - - public function __invoke() { - echo "__invoke called!\n"; +} else { + class MyArray implements ArrayAccess, Countable { + private $data = Array('one', 'two', 'three'); + + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } + + public function count(): int { + return count($this->data); + } + + public function __invoke() { + echo "__invoke called!\n"; + } } } diff --git a/tests/array_access_006.phpt b/tests/array_access_006.phpt index 53fff258..96af8e3a 100644 --- a/tests/array_access_006.phpt +++ b/tests/array_access_006.phpt @@ -6,29 +6,55 @@ Test V8::executeString() : Enumerate ArrayAccess keys v8js.use_array_access = 1 --FILE-- data[$offset]); + } - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } + public function offsetGet($offset) { + return $this->data[$offset]; + } - public function offsetGet($offset): mixed { - return $this->data[$offset]; - } + public function offsetSet($offset, $value) { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } - public function offsetSet($offset, $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } + public function offsetUnset($offset) { + throw new Exception('Not implemented'); + } - public function offsetUnset($offset): void { - throw new Exception('Not implemented'); + public function count() { + return count($this->data); + } } - - public function count(): int { - return count($this->data); +} else { + class MyArray implements ArrayAccess, Countable { + private $data = Array('one', 'two', 'three', null, 'five'); + + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } + + public function count(): int { + return count($this->data); + } } } diff --git a/tests/array_access_007.phpt b/tests/array_access_007.phpt index 0f8d59f0..1210c12e 100644 --- a/tests/array_access_007.phpt +++ b/tests/array_access_007.phpt @@ -6,31 +6,59 @@ Test V8::executeString() : Delete (unset) ArrayAccess keys v8js.use_array_access = 1 --FILE-- data[$offset]); + } - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } + public function offsetGet($offset) { + if(!$this->offsetExists($offset)) { + return null; + } + return $this->data[$offset]; + } - public function offsetGet($offset): mixed { - if(!$this->offsetExists($offset)) { - return null; - } - return $this->data[$offset]; - } + public function offsetSet($offset, $value) { + $this->data[$offset] = $value; + } - public function offsetSet($offset, $value): void { - $this->data[$offset] = $value; - } + public function offsetUnset($offset) { + unset($this->data[$offset]); + } - public function offsetUnset($offset): void { - unset($this->data[$offset]); + public function count() { + return max(array_keys($this->data)) + 1; + } } - - public function count(): int { - return max(array_keys($this->data)) + 1; +} else { + class MyArray implements ArrayAccess, Countable { + private $data = Array('one', 'two', 'three'); + + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed { + if(!$this->offsetExists($offset)) { + return null; + } + return $this->data[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + unset($this->data[$offset]); + } + + public function count(): int { + return max(array_keys($this->data)) + 1; + } } } diff --git a/tests/array_access_008.phpt b/tests/array_access_008.phpt index 48ee085b..f49942d6 100644 --- a/tests/array_access_008.phpt +++ b/tests/array_access_008.phpt @@ -6,28 +6,53 @@ Test V8::executeString() : in array (isset) behaviour of ArrayAccess v8js.use_array_access = 1 --FILE-- data[$offset]); + } - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } + public function offsetGet($offset) { + return $this->data[$offset]; + } - public function offsetGet($offset): mixed { - return $this->data[$offset]; - } + public function offsetSet($offset, $value) { + $this->data[$offset] = $value; + } - public function offsetSet($offset, $value): void { - $this->data[$offset] = $value; - } + public function offsetUnset($offset) { + unset($this->data[$offset]); + } - public function offsetUnset($offset): void { - unset($this->data[$offset]); + public function count() { + return max(array_keys($this->data)) + 1; + } } - - public function count(): int { - return max(array_keys($this->data)) + 1; +} else { + class MyArray implements ArrayAccess, Countable { + private $data = Array('one', null, 'three'); + + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + unset($this->data[$offset]); + } + + public function count(): int { + return max(array_keys($this->data)) + 1; + } } } diff --git a/tests/array_access_basic2.phpt b/tests/array_access_basic2.phpt index 0dcdc440..0cbf403c 100644 --- a/tests/array_access_basic2.phpt +++ b/tests/array_access_basic2.phpt @@ -6,28 +6,53 @@ Test V8::executeString() : Check array access setter behaviour v8js.use_array_access = 1 --FILE-- data[$offset]); +if (PHP_VERSION_ID < 80000) { + class MyArray implements ArrayAccess, Countable { + private $data = array('one', 'two', 'three'); + + public function offsetExists($offset) { + return isset($this->data[$offset]); + } + + public function offsetGet($offset) { + return $this->data[$offset]; + } + + public function offsetSet($offset, $value) { + $this->data[$offset] = $value; + } + + public function offsetUnset($offset) { + throw new Exception('Not implemented'); + } + + public function count() { + return count($this->data); + } } +} else { + class MyArray implements ArrayAccess, Countable { + private $data = array('one', 'two', 'three'); - public function offsetGet($offset): mixed { - return $this->data[$offset]; - } + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } - public function offsetSet($offset, $value): void { - $this->data[$offset] = $value; - } + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } - public function offsetUnset($offset): void { - throw new Exception('Not implemented'); - } + public function offsetSet(mixed $offset, mixed $value): void { + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } - public function count(): int { - return count($this->data); + public function count(): int { + return count($this->data); + } } } diff --git a/tests/exception_clearing.phpt b/tests/exception_clearing.phpt index 0d797a6e..3646c5a9 100644 --- a/tests/exception_clearing.phpt +++ b/tests/exception_clearing.phpt @@ -5,7 +5,7 @@ Test V8::executeString() : Exception clearing test --FILE-- getPendingException()); diff --git a/tests/exception_propagation_2.phpt b/tests/exception_propagation_2.phpt index 9a879c63..c808e3aa 100644 --- a/tests/exception_propagation_2.phpt +++ b/tests/exception_propagation_2.phpt @@ -10,7 +10,7 @@ class Foo { public function __construct() { - $this->v8 = new V8Js('', array(), array(), false); + $this->v8 = new V8Js(null, array(), array(), false); $this->v8->foo = $this; $this->v8->executeString('fooobar', 'throw_0'); var_dump($this->v8->getPendingException()); diff --git a/tests/exception_propagation_3.phpt b/tests/exception_propagation_3.phpt index 1bdaab3c..bc93c1d8 100644 --- a/tests/exception_propagation_3.phpt +++ b/tests/exception_propagation_3.phpt @@ -10,7 +10,7 @@ class Foo { public function __construct() { - $this->v8 = new V8Js('', array(), array(), false); + $this->v8 = new V8Js(null, array(), array(), false); $this->v8->foo = $this; $this->v8->executeString('function foobar() { throw new SyntaxError(); }', 'throw_1'); $this->v8->executeString('try { foobar(); } catch (e) { print(e + " caught in JS!\n"); }', 'trycatch1'); diff --git a/tests/issue_250_001.phpt b/tests/issue_250_001.phpt index dff94279..48bd5e4e 100644 --- a/tests/issue_250_001.phpt +++ b/tests/issue_250_001.phpt @@ -54,22 +54,10 @@ try { ?> ===EOF=== ---EXPECTREGEX-- -(?:Warning\: Creating default object from empty value in [^\r\n]+\/issue_250_001\.php on line 9\s*)+ -object\(TestObject\)\#\d+ \(3\) \{ - \["data"\:"TestObject"\:private\]\=\> - object\(V8Object\)\#\d+ \(0\) \{ - \} - \["meta"\:"TestObject"\:private\]\=\> - array\(0\) \{ - \} - \["a"\]\=\> - object\(stdClass\)\#\d+ \(1\) \{ - \["b"\]\=\> - object\(stdClass\)\#\d+ \(1\) \{ - \["title"\]\=\> - string\(4\) "ouch" - \} - \} -\} -\=\=\=EOF\=\=\= +--EXPECTF-- +Fatal error: Uncaught Error: Attempt to modify property "b" on null in %s%eissue_250_001.php:9 +Stack trace: +#0 [internal function]: TestObject->setTitle('ouch') +#1 %s%eissue_250_001.php(44): V8Js->executeString(' var v1 = se...') +#2 {main} + thrown in %s%eissue_250_001.php on line 9 diff --git a/tests/var_dump.phpt b/tests/var_dump.phpt index e1d232be..cc0654cb 100644 --- a/tests/var_dump.phpt +++ b/tests/var_dump.phpt @@ -139,6 +139,10 @@ array \(11\) \{ \["date"\] \=\> object\(DateTime\)\#\d+ \(\d+\) \{(?: \["createFromImmutable"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \})?(?: + \["createFromInterface"\] \=\> object\(Closure\)\#\d+ \{ function \(\) \{ \[native code\] \} \})? diff --git a/v8js_class.cc b/v8js_class.cc index becac9d8..49acc114 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -346,7 +346,7 @@ static PHP_METHOD(V8Js, __construct) return; } - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Saabz", &object_name, &vars_arr, &exts_arr, &report_uncaught, &snapshot_blob) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!aabz", &object_name, &vars_arr, &exts_arr, &report_uncaught, &snapshot_blob) == FAILURE) { return; } @@ -705,7 +705,7 @@ static PHP_METHOD(V8Js, executeString) long flags = V8JS_FLAG_NONE, time_limit = 0, memory_limit = 0; v8js_script *res = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|Slll", &str, &identifier, &flags, &time_limit, &memory_limit) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|S!lll", &str, &identifier, &flags, &time_limit, &memory_limit) == FAILURE) { return; } diff --git a/v8js_object_export.cc b/v8js_object_export.cc index fa9a9fc7..6b3b59ba 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -158,10 +158,6 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c fcc.called_scope = object->ce; fcc.object = object; - if (!EG(current_execute_data) || !EG(current_execute_data)->func) { - EG(current_execute_data) = NULL; - } - zend_call_function(&fci, &fcc); } zend_catch { diff --git a/v8js_v8.cc b/v8js_v8.cc index aa0f71de..0b5eab1f 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -178,10 +178,6 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value, efree(timer_ctx); if(!V8JSG(fatal_error_abort)) { - if (!EG(current_execute_data) || !EG(current_execute_data)->func) { - EG(current_execute_data) = NULL; - } - char exception_string[64]; if (c->time_limit_hit) { diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index a78412dd..b13554b8 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -140,7 +140,7 @@ static zval *v8js_v8object_read_property(SINCE80(zend_object, zval) *_object, SI { zend_throw_exception(php_ce_v8js_exception, "Can't access V8Object after V8Js instance is destroyed!", 0); - return retval; + return SINCE80(&EG(uninitialized_zval), retval); } V8JS_CTX_PROLOGUE_EX(obj->ctx, retval); @@ -152,7 +152,7 @@ static zval *v8js_v8object_read_property(SINCE80(zend_object, zval) *_object, SI { zend_throw_exception(php_ce_v8js_exception, "Member name length exceeds maximum supported length", 0); - return retval; + return SINCE80(&EG(uninitialized_zval), retval); } v8::Local jsKey = V8JS_ZSYM(member); @@ -313,9 +313,8 @@ static ZEND_FUNCTION(zend_v8object_func) /* Cleanup trampoline */ ZEND_ASSERT(EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE); - zend_string_release(EX(func)->common.function_name); - zend_free_trampoline(EX(func)); - EX(func) = NULL; + + bool bail = false; v8js_v8object *obj = v8js_v8object_fetch_object(object); @@ -323,18 +322,25 @@ static ZEND_FUNCTION(zend_v8object_func) { zend_throw_exception(php_ce_v8js_exception, "Can't access V8Object after V8Js instance is destroyed!", 0); - return; + bail = true; } if (obj->v8obj.IsEmpty()) { - return; + bail = true; } if (ZSTR_LEN(method) > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, "Method name length exceeds maximum supported length", 0); + bail = true; + } + + if (bail) { + zend_string_release(EX(func)->common.function_name); + zend_free_trampoline(EX(func)); + EX(func) = NULL; return; } @@ -413,6 +419,10 @@ static ZEND_FUNCTION(zend_v8object_func) efree(argv); } + zend_string_release(EX(func)->common.function_name); + zend_free_trampoline(EX(func)); + EX(func) = NULL; + if (V8JSG(fatal_error_abort)) { /* Check for fatal error marker possibly set by v8js_error_handler; just @@ -458,7 +468,9 @@ static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_st return f; #else f = (zend_internal_function *)ecalloc(1, sizeof(*f)); - f->type = ZEND_ACC_CALL_VIA_HANDLER; + f->type = ZEND_INTERNAL_FUNCTION; + f->scope = (*object_ptr)->ce; + f->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; f->handler = ZEND_FN(zend_v8object_func); f->function_name = zend_string_copy(method); return (zend_function *)f; @@ -613,7 +625,9 @@ static int v8js_v8object_get_closure(zval *object, zend_class_entry **ce_ptr, ze *fptr_ptr = invoke; #else invoke = (zend_internal_function *)ecalloc(1, sizeof(*invoke)); - invoke->type = ZEND_ACC_CALL_VIA_HANDLER; + invoke->type = ZEND_INTERNAL_FUNCTION; + invoke->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; + invoke->scope = object->ce; invoke->handler = ZEND_FN(zend_v8object_func); invoke->function_name = zend_string_init(V8JS_V8_INVOKE_FUNC_NAME, sizeof(V8JS_V8_INVOKE_FUNC_NAME) - 1, 0); *fptr_ptr = (zend_function *)invoke; From 82ba4abfe4065da18ac671ede97d8f915391a898 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Mon, 30 May 2022 14:02:34 +0200 Subject: [PATCH 06/64] Update README that PHP 8 is requred + mention php7 branch --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 377ee3ee..5af3aa97 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Minimum requirements for the version line shipped with the Chrome browser (stable channel) and newer (only). For a version overview see https://omahaproxy.appspot.com/. -- PHP 7.0.0+ +- PHP 8.0.0+ This embedded implementation of the V8 engine uses thread locking so it works with ZTS enabled. @@ -37,6 +37,8 @@ maintain support for it myself, and don't really have Windows boxes to try thing It would be great if someone could step up and fix things on Windows, provide pre-build V8 binaries, etc. +There is a branch named `php7` which targets PHP 7.0.0+ + Pre-built binaries ------------------ From 1455451e6f6136560120fbfb8bd37a6edac46a6f Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Mon, 30 May 2022 14:03:12 +0200 Subject: [PATCH 07/64] ignore .dep files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6e46a23b..38419c7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.lo *.o +*.dep .deps .libs Dockerfile.tmp From 10cd73a03d6c87ddf5143654caf4c70e1a61be51 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Mon, 30 May 2022 14:11:28 +0200 Subject: [PATCH 08/64] eliminate PHP_VERSION_ID checks for < 80000 etc --- tests/array_access.phpt | 54 +++++------------ tests/array_access_001.phpt | 66 ++++++--------------- tests/array_access_002.phpt | 61 ++++++-------------- tests/array_access_003.phpt | 102 +++++++++++---------------------- tests/array_access_004.phpt | 82 ++++++++------------------ tests/array_access_005.phpt | 71 +++++++---------------- tests/array_access_006.phpt | 61 ++++++-------------- tests/array_access_007.phpt | 65 ++++++--------------- tests/array_access_008.phpt | 58 ++++++------------- tests/array_access_basic2.phpt | 58 ++++++------------- v8js_class.h | 2 - v8js_convert.cc | 21 +------ v8js_object_export.cc | 20 ------- v8js_v8.h | 19 ------ v8js_v8object_class.cc | 26 --------- 15 files changed, 195 insertions(+), 571 deletions(-) diff --git a/tests/array_access.phpt b/tests/array_access.phpt index 31637340..80f8387b 100644 --- a/tests/array_access.phpt +++ b/tests/array_access.phpt @@ -7,49 +7,25 @@ v8js.use_array_access = 1 --FILE-- = 0 && $offset <= 20; - } - - public function offsetGet($offset) { - return 19 - $offset; - } +class MyArray implements ArrayAccess, Countable { + public function offsetExists($offset): bool { + return $offset >= 0 && $offset <= 20; + } - public function offsetSet($offset, $value) { - throw new Exception('Not implemented'); - } + public function offsetGet(mixed $offset): mixed { + return 19 - $offset; + } - public function offsetUnset($offset) { - throw new Exception('Not implemented'); - } + public function offsetSet(mixed $offset, mixed $value): void { + throw new Exception('Not implemented'); + } - public function count() { - return 20; - } + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); } -} else { - class MyArray implements ArrayAccess, Countable { - public function offsetExists($offset): bool { - return $offset >= 0 && $offset <= 20; - } - - public function offsetGet(mixed $offset): mixed { - return 19 - $offset; - } - - public function offsetSet(mixed $offset, mixed $value): void { - throw new Exception('Not implemented'); - } - - public function offsetUnset(mixed $offset): void { - throw new Exception('Not implemented'); - } - - public function count(): int { - return 20; - } + + public function count(): int { + return 20; } } diff --git a/tests/array_access_001.phpt b/tests/array_access_001.phpt index 92aa2642..83cbd8dc 100644 --- a/tests/array_access_001.phpt +++ b/tests/array_access_001.phpt @@ -7,61 +7,31 @@ v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset) { - return $this->data[$offset]; - } - - public function offsetSet($offset, $value) { - $this->data[$offset] = $value; - } - - public function offsetUnset($offset) { - throw new Exception('Not implemented'); - } - - public function count() { - return count($this->data); - } - - public function push($value) { - $this->data[] = $value; - } + public function offsetExists($offset): bool { + return isset($this->data[$offset]); } -} else { - class MyArray implements ArrayAccess, Countable { - private $data = Array('one', 'two', 'three'); - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } - - public function offsetGet(mixed $offset): mixed { - return $this->data[$offset]; - } + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } - public function offsetSet(mixed $offset, mixed $value): void { - $this->data[$offset] = $value; - } + public function offsetSet(mixed $offset, mixed $value): void { + $this->data[$offset] = $value; + } - public function offsetUnset(mixed $offset): void { - throw new Exception('Not implemented'); - } + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } - public function count(): int { - return count($this->data); - } + public function count(): int { + return count($this->data); + } - public function push($value) { - $this->data[] = $value; - } + public function push($value) { + $this->data[] = $value; } } diff --git a/tests/array_access_002.phpt b/tests/array_access_002.phpt index f7db125a..f8c6e886 100644 --- a/tests/array_access_002.phpt +++ b/tests/array_access_002.phpt @@ -6,55 +6,28 @@ Test V8::executeString() : Use ArrayAccess with JavaScript native push method v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset) { - return $this->data[$offset]; - } + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } - public function offsetSet($offset, $value) { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } - public function offsetUnset($offset) { - throw new Exception('Not implemented'); - } + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } - public function count() { - return count($this->data); - } + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); } -} else { - class MyArray implements ArrayAccess, Countable { - private $data = Array('one', 'two', 'three'); - - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } - - public function offsetGet(mixed $offset): mixed { - return $this->data[$offset]; - } - - public function offsetSet(mixed $offset, mixed $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } - - public function offsetUnset(mixed $offset): void { - throw new Exception('Not implemented'); - } - - public function count(): int { - return count($this->data); - } + + public function count(): int { + return count($this->data); } } diff --git a/tests/array_access_003.phpt b/tests/array_access_003.phpt index f4882727..5adc5fad 100644 --- a/tests/array_access_003.phpt +++ b/tests/array_access_003.phpt @@ -6,77 +6,39 @@ Test V8::executeString() : Export PHP methods on ArrayAccess objects v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset) { - return $this->data[$offset]; - } - - public function offsetSet($offset, $value) { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } - - public function offsetUnset($offset) { - throw new Exception('Not implemented'); - } - - public function count() { - echo 'count() = ', count($this->data), "\n"; - return count($this->data); - } - - public function phpSidePush($value) { - echo "push << $value\n"; - $this->data[] = $value; - } - - public function push($value) { - echo "php-side-push << $value\n"; - $this->data[] = $value; - } +class MyArray implements ArrayAccess, Countable { + private $data = Array('one', 'two', 'three'); + + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } + + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } + + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } + + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } + + public function count(): int { + echo 'count() = ', count($this->data), "\n"; + return count($this->data); } -} else { - class MyArray implements ArrayAccess, Countable { - private $data = Array('one', 'two', 'three'); - - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } - - public function offsetGet(mixed $offset): mixed { - return $this->data[$offset]; - } - - public function offsetSet(mixed $offset, mixed $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } - - public function offsetUnset(mixed $offset): void { - throw new Exception('Not implemented'); - } - - public function count(): int { - echo 'count() = ', count($this->data), "\n"; - return count($this->data); - } - - public function phpSidePush($value) { - echo "push << $value\n"; - $this->data[] = $value; - } - - public function push($value) { - echo "php-side-push << $value\n"; - $this->data[] = $value; - } + + public function phpSidePush($value) { + echo "push << $value\n"; + $this->data[] = $value; + } + + public function push($value) { + echo "php-side-push << $value\n"; + $this->data[] = $value; } } diff --git a/tests/array_access_004.phpt b/tests/array_access_004.phpt index c5c664b0..dce9ad53 100644 --- a/tests/array_access_004.phpt +++ b/tests/array_access_004.phpt @@ -6,73 +6,37 @@ Test V8::executeString() : Export PHP properties on ArrayAccess objects v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset) { - return $this->data[$offset]; - } - - public function offsetSet($offset, $value) { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } - - public function offsetUnset($offset) { - throw new Exception('Not implemented'); - } - - public function count() { - return count($this->data); - } + public function offsetExists($offset): bool { + return isset($this->data[$offset]); } -} else { - class MyArray implements ArrayAccess, Countable { - private $data = Array('one', 'two', 'three'); - - private $privFoo = 23; - protected $protFoo = 23; - public $pubFoo = 42; - /* We can have a length property on the PHP object, but the length property - * of the JS object will still call count() method. Anyways it should be - * accessibly as $length. */ - public $length = 42; - - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } - - public function offsetGet(mixed $offset): mixed { - return $this->data[$offset]; - } + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } - public function offsetSet(mixed $offset, mixed $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } - public function offsetUnset(mixed $offset): void { - throw new Exception('Not implemented'); - } + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } - public function count(): int { - return count($this->data); - } + public function count(): int { + return count($this->data); } } diff --git a/tests/array_access_005.phpt b/tests/array_access_005.phpt index ba6bc732..603e7705 100644 --- a/tests/array_access_005.phpt +++ b/tests/array_access_005.phpt @@ -6,63 +6,32 @@ Test V8::executeString() : Export __invoke method on ArrayAccess objects v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset) { - return $this->data[$offset]; - } + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } - public function offsetSet($offset, $value) { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } - public function offsetUnset($offset) { - throw new Exception('Not implemented'); - } + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } - public function count() { - return count($this->data); - } + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } - public function __invoke() { - echo "__invoke called!\n"; - } + public function count(): int { + return count($this->data); } -} else { - class MyArray implements ArrayAccess, Countable { - private $data = Array('one', 'two', 'three'); - - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } - - public function offsetGet(mixed $offset): mixed { - return $this->data[$offset]; - } - - public function offsetSet(mixed $offset, mixed $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } - - public function offsetUnset(mixed $offset): void { - throw new Exception('Not implemented'); - } - - public function count(): int { - return count($this->data); - } - - public function __invoke() { - echo "__invoke called!\n"; - } + + public function __invoke() { + echo "__invoke called!\n"; } } diff --git a/tests/array_access_006.phpt b/tests/array_access_006.phpt index 96af8e3a..05260b05 100644 --- a/tests/array_access_006.phpt +++ b/tests/array_access_006.phpt @@ -6,55 +6,28 @@ Test V8::executeString() : Enumerate ArrayAccess keys v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset) { - return $this->data[$offset]; - } + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } - public function offsetSet($offset, $value) { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } - public function offsetUnset($offset) { - throw new Exception('Not implemented'); - } + public function offsetSet(mixed $offset, mixed $value): void { + echo "set[$offset] = $value\n"; + $this->data[$offset] = $value; + } - public function count() { - return count($this->data); - } + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); } -} else { - class MyArray implements ArrayAccess, Countable { - private $data = Array('one', 'two', 'three', null, 'five'); - - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } - - public function offsetGet(mixed $offset): mixed { - return $this->data[$offset]; - } - - public function offsetSet(mixed $offset, mixed $value): void { - echo "set[$offset] = $value\n"; - $this->data[$offset] = $value; - } - - public function offsetUnset(mixed $offset): void { - throw new Exception('Not implemented'); - } - - public function count(): int { - return count($this->data); - } + + public function count(): int { + return count($this->data); } } diff --git a/tests/array_access_007.phpt b/tests/array_access_007.phpt index 1210c12e..ce528668 100644 --- a/tests/array_access_007.phpt +++ b/tests/array_access_007.phpt @@ -6,59 +6,30 @@ Test V8::executeString() : Delete (unset) ArrayAccess keys v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset) { - if(!$this->offsetExists($offset)) { - return null; - } - return $this->data[$offset]; - } + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } - public function offsetSet($offset, $value) { - $this->data[$offset] = $value; + public function offsetGet(mixed $offset): mixed { + if(!$this->offsetExists($offset)) { + return null; } + return $this->data[$offset]; + } - public function offsetUnset($offset) { - unset($this->data[$offset]); - } + public function offsetSet(mixed $offset, mixed $value): void { + $this->data[$offset] = $value; + } - public function count() { - return max(array_keys($this->data)) + 1; - } + public function offsetUnset(mixed $offset): void { + unset($this->data[$offset]); } -} else { - class MyArray implements ArrayAccess, Countable { - private $data = Array('one', 'two', 'three'); - - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } - - public function offsetGet(mixed $offset): mixed { - if(!$this->offsetExists($offset)) { - return null; - } - return $this->data[$offset]; - } - - public function offsetSet(mixed $offset, mixed $value): void { - $this->data[$offset] = $value; - } - - public function offsetUnset(mixed $offset): void { - unset($this->data[$offset]); - } - - public function count(): int { - return max(array_keys($this->data)) + 1; - } + + public function count(): int { + return max(array_keys($this->data)) + 1; } } diff --git a/tests/array_access_008.phpt b/tests/array_access_008.phpt index f49942d6..67fae5ed 100644 --- a/tests/array_access_008.phpt +++ b/tests/array_access_008.phpt @@ -6,53 +6,27 @@ Test V8::executeString() : in array (isset) behaviour of ArrayAccess v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset) { - return $this->data[$offset]; - } + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } - public function offsetSet($offset, $value) { - $this->data[$offset] = $value; - } + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } - public function offsetUnset($offset) { - unset($this->data[$offset]); - } + public function offsetSet(mixed $offset, mixed $value): void { + $this->data[$offset] = $value; + } - public function count() { - return max(array_keys($this->data)) + 1; - } + public function offsetUnset(mixed $offset): void { + unset($this->data[$offset]); } -} else { - class MyArray implements ArrayAccess, Countable { - private $data = Array('one', null, 'three'); - - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } - - public function offsetGet(mixed $offset): mixed { - return $this->data[$offset]; - } - - public function offsetSet(mixed $offset, mixed $value): void { - $this->data[$offset] = $value; - } - - public function offsetUnset(mixed $offset): void { - unset($this->data[$offset]); - } - - public function count(): int { - return max(array_keys($this->data)) + 1; - } + + public function count(): int { + return max(array_keys($this->data)) + 1; } } diff --git a/tests/array_access_basic2.phpt b/tests/array_access_basic2.phpt index 0cbf403c..a658a39d 100644 --- a/tests/array_access_basic2.phpt +++ b/tests/array_access_basic2.phpt @@ -6,53 +6,27 @@ Test V8::executeString() : Check array access setter behaviour v8js.use_array_access = 1 --FILE-- data[$offset]); - } - - public function offsetGet($offset) { - return $this->data[$offset]; - } - - public function offsetSet($offset, $value) { - $this->data[$offset] = $value; - } - - public function offsetUnset($offset) { - throw new Exception('Not implemented'); - } - - public function count() { - return count($this->data); - } - } -} else { - class MyArray implements ArrayAccess, Countable { - private $data = array('one', 'two', 'three'); +class MyArray implements ArrayAccess, Countable { + private $data = array('one', 'two', 'three'); - public function offsetExists($offset): bool { - return isset($this->data[$offset]); - } + public function offsetExists($offset): bool { + return isset($this->data[$offset]); + } - public function offsetGet(mixed $offset): mixed { - return $this->data[$offset]; - } + public function offsetGet(mixed $offset): mixed { + return $this->data[$offset]; + } - public function offsetSet(mixed $offset, mixed $value): void { - $this->data[$offset] = $value; - } + public function offsetSet(mixed $offset, mixed $value): void { + $this->data[$offset] = $value; + } - public function offsetUnset(mixed $offset): void { - throw new Exception('Not implemented'); - } + public function offsetUnset(mixed $offset): void { + throw new Exception('Not implemented'); + } - public function count(): int { - return count($this->data); - } + public function count(): int { + return count($this->data); } } diff --git a/v8js_class.h b/v8js_class.h index cabdee83..38efc839 100644 --- a/v8js_class.h +++ b/v8js_class.h @@ -87,9 +87,7 @@ static inline struct v8js_ctx *v8js_ctx_fetch_object(zend_object *obj) { #define Z_V8JS_CTX_OBJ(zv) v8js_ctx_fetch_object(zv); -#if PHP_VERSION_ID >= 80000 #define ZEND_ACC_DTOR 0 -#endif PHP_MINIT_FUNCTION(v8js_class); diff --git a/v8js_convert.cc b/v8js_convert.cc index a8ef6dc9..67aa4cee 100644 --- a/v8js_convert.cc +++ b/v8js_convert.cc @@ -70,12 +70,7 @@ static v8::Local v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate v8::Local newarr; /* Prevent recursion */ -#if PHP_VERSION_ID >= 70300 - if (myht && GC_IS_RECURSIVE(myht)) -#else - if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 0) -#endif - { + if (myht && GC_IS_RECURSIVE(myht)) { return V8JS_NULL; } @@ -87,12 +82,7 @@ static v8::Local v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate zval *data; zend_ulong index = 0; -#if PHP_VERSION_ID >= 70300 - if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) -#else - if (myht) -#endif - { + if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { GC_PROTECT_RECURSION(myht); } @@ -100,12 +90,7 @@ static v8::Local v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate newarr->Set(v8_context, index++, zval_to_v8js(data, isolate)); } ZEND_HASH_FOREACH_END(); -#if PHP_VERSION_ID >= 70300 - if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) -#else - if (myht) -#endif - { + if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { GC_UNPROTECT_RECURSION(myht); } } diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 6b3b59ba..72fcb58e 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -150,9 +150,6 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c zend_try { /* zend_fcall_info_cache */ -#if PHP_VERSION_ID < 70300 - fcc.initialized = 1; -#endif fcc.function_handler = method_ptr; fcc.calling_scope = object->ce; fcc.called_scope = object->ce; @@ -643,12 +640,7 @@ v8::Local v8js_named_property_callback(v8::Local property_n zval php_value; zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); - #if PHP_VERSION_ID < 80000 - zval zobject; - ZVAL_OBJ(&zobject, object); - #else zend_object &zobject = *object; - #endif v8js_function_tmpl_t *tmpl_ptr = reinterpret_cast(self->GetAlignedPointerFromInternalField(0)); v8::Local tmpl = v8::Local::New(isolate, *tmpl_ptr); @@ -1031,11 +1023,7 @@ static v8::Local v8js_wrap_array_to_object(v8::Isolate *isolate, zva { zval *data; -#if PHP_VERSION_ID >= 70300 if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { -#else - if (myht) { -#endif GC_PROTECT_RECURSION(myht); } @@ -1067,11 +1055,7 @@ static v8::Local v8js_wrap_array_to_object(v8::Isolate *isolate, zva } ZEND_HASH_FOREACH_END(); -#if PHP_VERSION_ID >= 70300 if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { -#else - if (myht) { -#endif GC_UNPROTECT_RECURSION(myht); } @@ -1095,11 +1079,7 @@ v8::Local v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate) /* {{ } /* Prevent recursion */ -#if PHP_VERSION_ID >= 70300 if (myht && GC_IS_RECURSIVE(myht)) { -#else - if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) { -#endif return V8JS_NULL; } diff --git a/v8js_v8.h b/v8js_v8.h index 59b374d0..421cfdef 100644 --- a/v8js_v8.h +++ b/v8js_v8.h @@ -88,31 +88,12 @@ int v8js_get_properties_hash(v8::Local jsValue, HashTable *retval, in V8JS_CTX_PROLOGUE(ctx); -#if PHP_VERSION_ID < 70400 -#define SINCE74(x,y) y -#else #define SINCE74(x,y) x -#endif - -#if PHP_VERSION_ID < 80000 -#define SINCE80(x,y) y -#else #define SINCE80(x,y) x -#endif - -#if PHP_VERSION_ID < 70200 -#define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \ - ZEND_BEGIN_ARG_INFO_EX(name, return_reference, required_num_args, allow_null) -#endif // polyfill for ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX, which changes between 7.1 and 7.2 -#if PHP_VERSION_ID < 70200 -#define V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ - ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, /*class_name*/ 0, allow_null) -#else #define V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) -#endif // In PHP 8.1, mismatched tentative return types emit a deprecation notice. // https://wiki.php.net/rfc/internal_method_return_types diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index b13554b8..c59e633e 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -252,14 +252,6 @@ static HashTable *v8js_v8object_get_properties(SINCE80(zend_object, zval) *objec if (obj->properties == NULL) { -#if PHP_VERSION_ID < 70300 - if (GC_G(gc_active)) - { - /* the garbage collector is running, don't create more zvals */ - return NULL; - } -#endif - ALLOC_HASHTABLE(obj->properties); zend_hash_init(obj->properties, 0, NULL, ZVAL_PTR_DTOR, 0); @@ -461,12 +453,6 @@ static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_st if (v8obj->ToObject(v8_context).ToLocal(&jsObj) && jsObj->Has(v8_context, jsKey).FromMaybe(false) && jsObj->Get(v8_context, jsKey).ToLocal(&jsObjSlot) && jsObjSlot->IsFunction()) { -#if PHP_VERSION_ID < 80000 - f = (zend_function *)ecalloc(1, sizeof(*f)); - f->type = ZEND_OVERLOADED_FUNCTION_TEMPORARY; - f->common.function_name = zend_string_copy(method); - return f; -#else f = (zend_internal_function *)ecalloc(1, sizeof(*f)); f->type = ZEND_INTERNAL_FUNCTION; f->scope = (*object_ptr)->ce; @@ -474,7 +460,6 @@ static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_st f->handler = ZEND_FN(zend_v8object_func); f->function_name = zend_string_copy(method); return (zend_function *)f; -#endif } } @@ -594,11 +579,7 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I } /* }}} */ -#if PHP_VERSION_ID >= 80000 static int v8js_v8object_get_closure(zend_object *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr, bool call) /* {{{ */ -#else -static int v8js_v8object_get_closure(zval *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr) /* {{{ */ -#endif { SINCE80(zend_internal_function, zend_function) *invoke; v8js_v8object *obj = SINCE80(Z_V8JS_V8OBJECT_OBJ, Z_V8JS_V8OBJECT_OBJ_P)(object); @@ -618,12 +599,6 @@ static int v8js_v8object_get_closure(zval *object, zend_class_entry **ce_ptr, ze return FAILURE; } -#if PHP_VERSION_ID < 80000 - invoke = (zend_function *)ecalloc(1, sizeof(*invoke)); - invoke->type = ZEND_OVERLOADED_FUNCTION_TEMPORARY; - invoke->common.function_name = zend_string_init(V8JS_V8_INVOKE_FUNC_NAME, sizeof(V8JS_V8_INVOKE_FUNC_NAME) - 1, 0); - *fptr_ptr = invoke; -#else invoke = (zend_internal_function *)ecalloc(1, sizeof(*invoke)); invoke->type = ZEND_INTERNAL_FUNCTION; invoke->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; @@ -631,7 +606,6 @@ static int v8js_v8object_get_closure(zval *object, zend_class_entry **ce_ptr, ze invoke->handler = ZEND_FN(zend_v8object_func); invoke->function_name = zend_string_init(V8JS_V8_INVOKE_FUNC_NAME, sizeof(V8JS_V8_INVOKE_FUNC_NAME) - 1, 0); *fptr_ptr = (zend_function *)invoke; -#endif if (zobj_ptr) { From 6be2206aab6a0ffe6ea2eefcfaacd4f37f0459b4 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Mon, 30 May 2022 14:15:00 +0200 Subject: [PATCH 09/64] eliminate PHP_MAJOR_VERSION checks --- v8js_array_access.cc | 8 -------- v8js_methods.cc | 9 --------- v8js_object_export.cc | 8 -------- 3 files changed, 25 deletions(-) diff --git a/v8js_array_access.cc b/v8js_array_access.cc index 3151781c..c9ca933f 100644 --- a/v8js_array_access.cc +++ b/v8js_array_access.cc @@ -35,10 +35,6 @@ static zval v8js_array_access_dispatch(zend_object *object, const char *method_n zval php_value; fci.size = sizeof(fci); -#if (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) - fci.function_table = &object->ce->function_table; - fci.symbol_table = NULL; -#endif ZVAL_STRING(&fci.function_name, method_name); fci.retval = &php_value; @@ -50,11 +46,7 @@ static zval v8js_array_access_dispatch(zend_object *object, const char *method_n fci.params = params; fci.object = object; -#if (PHP_MAJOR_VERSION < 8) - fci.no_separation = 0; -#else fci.named_params = NULL; -#endif zend_call_function(&fci, NULL); zval_dtor(&fci.function_name); diff --git a/v8js_methods.cc b/v8js_methods.cc index 519748b0..614c064c 100644 --- a/v8js_methods.cc +++ b/v8js_methods.cc @@ -311,13 +311,8 @@ V8JS_METHOD(require) ZVAL_STRING(¶ms[0], module_base_cstr); ZVAL_STRING(¶ms[1], module_id); - #if (PHP_MAJOR_VERSION < 8) - call_result = call_user_function_ex(EG(function_table), NULL, &c->module_normaliser, - &normaliser_result, 2, params, 0, NULL); - #else call_result = call_user_function(EG(function_table), NULL, &c->module_normaliser, &normaliser_result, 2, params); - #endif } isolate->Enter(); @@ -440,11 +435,7 @@ V8JS_METHOD(require) zend_try { ZVAL_STRING(¶ms[0], normalised_module_id); - #if (PHP_MAJOR_VERSION < 8) - call_result = call_user_function_ex(EG(function_table), NULL, &c->module_loader, &module_code, 1, params, 0, NULL); - #else call_result = call_user_function(EG(function_table), NULL, &c->module_loader, &module_code, 1, params); - #endif } zend_catch { v8js_terminate_execution(isolate); diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 72fcb58e..042a82a8 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -59,10 +59,6 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c /* zend_fcall_info */ fci.size = sizeof(fci); -#if (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) - fci.function_table = &object->ce->function_table; - fci.symbol_table = NULL; -#endif fci.function_name = fname; fci.object = object; fci.retval = &retval; @@ -137,11 +133,7 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c } else { fci.params = NULL; } -#if (PHP_MAJOR_VERSION < 8) - fci.no_separation = 1; -#else fci.named_params = NULL; -#endif info.GetReturnValue().Set(V8JS_NULL); { From 9b3d1d1c8fc36284eef8158ea31c64055d9a665b Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Mon, 30 May 2022 14:25:37 +0200 Subject: [PATCH 10/64] remove SINCE74(...) and SINCE80(...) macro fluff --- v8js_class.cc | 20 ++++++------------ v8js_convert.cc | 2 +- v8js_exceptions.cc | 4 ++-- v8js_object_export.cc | 4 ++-- v8js_v8.h | 3 --- v8js_v8object_class.cc | 48 ++++++++++++++++-------------------------- 6 files changed, 30 insertions(+), 51 deletions(-) diff --git a/v8js_class.cc b/v8js_class.cc index 49acc114..0f49c832 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -506,7 +506,7 @@ static PHP_METHOD(V8Js, __construct) V8JS_GLOBAL(isolate)->DefineOwnProperty(context, object_name_js, php_obj, v8::ReadOnly); /* Export public property values */ - HashTable *properties = zend_std_get_properties(SINCE80(Z_OBJ_P(getThis()), getThis())); + HashTable *properties = zend_std_get_properties(Z_OBJ_P(getThis())); zval *value; zend_string *member; @@ -1305,13 +1305,10 @@ const zend_function_entry v8js_methods[] = { /* {{{ */ /* V8Js object handlers */ -static SINCE74(zval*, void) v8js_write_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, zval *value, void **cache_slot) /* {{{ */ +static zval* v8js_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot) /* {{{ */ { - zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); - zend_string *member = SINCE80(_member, Z_STR_P(_member)); - v8js_ctx *c = Z_V8JS_CTX_OBJ(object); - V8JS_CTX_PROLOGUE_EX(c, SINCE74(value,)); + V8JS_CTX_PROLOGUE_EX(c, value); /* Check whether member is public, if so, export to V8. */ zend_property_info *property_info = zend_get_property_info(c->std.ce, member, 1); @@ -1326,7 +1323,7 @@ static SINCE74(zval*, void) v8js_write_property(SINCE80(zend_object, zval) *_obj if (ZSTR_LEN(member) > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, "Property name exceeds maximum supported length", 0); - return SINCE74(value,); + return value; } /* Write value to PHP JS object */ @@ -1335,15 +1332,12 @@ static SINCE74(zval*, void) v8js_write_property(SINCE80(zend_object, zval) *_obj } /* Write value to PHP object */ - SINCE74(return,) std_object_handlers.write_property(SINCE80(object, _object), SINCE80(member, _member), value, NULL); + return std_object_handlers.write_property(object, member, value, NULL); } /* }}} */ -static void v8js_unset_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, void **cache_slot) /* {{{ */ +static void v8js_unset_property(zend_object *object, zend_string *member, void **cache_slot) /* {{{ */ { - zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); - zend_string *member = SINCE80(_member, Z_STR_P(_member)); - V8JS_BEGIN_CTX_OBJ(c, object); /* Global PHP JS object */ v8::Local object_name_js = v8::Local::New(isolate, c->object_name); @@ -1361,7 +1355,7 @@ static void v8js_unset_property(SINCE80(zend_object, zval) *_object, SINCE80(zen jsobj->Delete(v8_context, key); /* Unset from PHP object */ - std_object_handlers.unset_property(SINCE80(object, _object), SINCE80(member, _member), NULL); + std_object_handlers.unset_property(object, member, NULL); } /* }}} */ diff --git a/v8js_convert.cc b/v8js_convert.cc index 67aa4cee..d6fe832d 100644 --- a/v8js_convert.cc +++ b/v8js_convert.cc @@ -133,7 +133,7 @@ v8::Local zval_to_v8js(zval *value, v8::Isolate *isolate) /* {{{ */ ce = php_date_get_date_ce(); if (instanceof_function(Z_OBJCE_P(value), ce)) { zval dtval; - zend_call_method_with_0_params(SINCE80(Z_OBJ_P(value), value), NULL, NULL, "getTimestamp", &dtval); + zend_call_method_with_0_params(Z_OBJ_P(value), NULL, NULL, "getTimestamp", &dtval); v8::Date::New(isolate->GetEnteredOrMicrotaskContext(), ((double)Z_LVAL(dtval) * 1000.0)).ToLocal(&jsValue); zval_dtor(&dtval); } else diff --git a/v8js_exceptions.cc b/v8js_exceptions.cc index fa1d08f9..81c04237 100644 --- a/v8js_exceptions.cc +++ b/v8js_exceptions.cc @@ -51,7 +51,7 @@ void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8:: object_init_ex(return_value, php_ce_v8js_script_exception); #define PHPV8_EXPROP(type, name, value) \ - zend_update_property##type(php_ce_v8js_script_exception, SINCE80(Z_OBJ_P(return_value), return_value), #name, sizeof(#name) - 1, value); + zend_update_property##type(php_ce_v8js_script_exception, Z_OBJ_P(return_value), #name, sizeof(#name) - 1, value); if (tc_message.IsEmpty()) { @@ -137,7 +137,7 @@ void v8js_throw_script_exception(v8::Isolate *isolate, v8::TryCatch *try_catch) if (zend_parse_parameters_none() == FAILURE) { \ return; \ } \ - value = zend_read_property(php_ce_v8js_script_exception, SINCE80(Z_OBJ_P(getThis()), getThis()), #property, sizeof(#property) - 1, 0, &rv); \ + value = zend_read_property(php_ce_v8js_script_exception, Z_OBJ_P(getThis()), #property, sizeof(#property) - 1, 0, &rv); \ RETURN_ZVAL(value, 1, 0); \ } diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 042a82a8..78597d07 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -787,7 +787,7 @@ v8::Local v8js_named_property_callback(v8::Local property_n const zend_object_handlers *h = object->handlers; if (callback_type == V8JS_PROP_QUERY) { - if (h->has_property(&zobject, SINCE80(Z_STR_P(&zname), &zname), 0, NULL)) { + if (h->has_property(&zobject, Z_STR_P(&zname), 0, NULL)) { ret_value = V8JS_UINT(v8::None); } else { ret_value = v8::Local(); // empty handle @@ -798,7 +798,7 @@ v8::Local v8js_named_property_callback(v8::Local property_n if(!property_info || (property_info != ZEND_WRONG_PROPERTY_INFO && property_info->flags & ZEND_ACC_PUBLIC)) { - h->unset_property(&zobject, SINCE80(Z_STR_P(&zname), &zname), NULL); + h->unset_property(&zobject, Z_STR_P(&zname), NULL); ret_value = V8JS_TRUE(); } else { diff --git a/v8js_v8.h b/v8js_v8.h index 421cfdef..5c13f00f 100644 --- a/v8js_v8.h +++ b/v8js_v8.h @@ -88,9 +88,6 @@ int v8js_get_properties_hash(v8::Local jsValue, HashTable *retval, in V8JS_CTX_PROLOGUE(ctx); -#define SINCE74(x,y) x -#define SINCE80(x,y) x - // polyfill for ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX, which changes between 7.1 and 7.2 #define V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index c59e633e..4399e54f 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -45,10 +45,8 @@ static zend_object_handlers v8js_v8generator_handlers; #define V8JS_V8_INVOKE_FUNC_NAME "V8Js::V8::Invoke" /* V8 Object handlers */ -static int v8js_v8object_has_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, int has_set_exists, void **cache_slot) /* {{{ */ +static int v8js_v8object_has_property(zend_object *object, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */ { - zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); - zend_string *member = SINCE80(_member, Z_STR_P(_member)); /* param has_set_exists: * 0 (has) whether property exists and is not NULL - isset() * 1 (set) whether property exists and is true-ish - empty() @@ -128,11 +126,8 @@ static int v8js_v8object_has_property(SINCE80(zend_object, zval) *_object, SINCE } /* }}} */ -static zval *v8js_v8object_read_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, int type, void **cache_slot, zval *rv) /* {{{ */ +static zval *v8js_v8object_read_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */ { - zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); - zend_string *member = SINCE80(_member, Z_STR_P(_member)); - zval *retval = rv; v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); @@ -140,7 +135,7 @@ static zval *v8js_v8object_read_property(SINCE80(zend_object, zval) *_object, SI { zend_throw_exception(php_ce_v8js_exception, "Can't access V8Object after V8Js instance is destroyed!", 0); - return SINCE80(&EG(uninitialized_zval), retval); + return &EG(uninitialized_zval); } V8JS_CTX_PROLOGUE_EX(obj->ctx, retval); @@ -152,7 +147,7 @@ static zval *v8js_v8object_read_property(SINCE80(zend_object, zval) *_object, SI { zend_throw_exception(php_ce_v8js_exception, "Member name length exceeds maximum supported length", 0); - return SINCE80(&EG(uninitialized_zval), retval); + return &EG(uninitialized_zval); } v8::Local jsKey = V8JS_ZSYM(member); @@ -174,34 +169,31 @@ static zval *v8js_v8object_read_property(SINCE80(zend_object, zval) *_object, SI } /* }}} */ -static zval *v8js_v8object_get_property_ptr_ptr(SINCE80(zend_object, zval) *object, SINCE80(zend_string, zval) *member, int type, void **cache_slot) /* {{{ */ +static zval *v8js_v8object_get_property_ptr_ptr(zend_object *object, zend_string *member, int type, void **cache_slot) /* {{{ */ { return NULL; } /* }}} */ -static SINCE74(zval *, void) v8js_v8object_write_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, zval *value, void **cache_slot) /* {{{ */ +static zval *v8js_v8object_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot) /* {{{ */ { - zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); - zend_string *member = SINCE80(_member, Z_STR_P(_member)); - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); if (!obj->ctx) { zend_throw_exception(php_ce_v8js_exception, "Can't access V8Object after V8Js instance is destroyed!", 0); - return SINCE74(value, ); + return value; } - V8JS_CTX_PROLOGUE_EX(obj->ctx, SINCE74(value, )); + V8JS_CTX_PROLOGUE_EX(obj->ctx, value); v8::Local v8objHandle = v8::Local::New(isolate, obj->v8obj); if (ZSTR_LEN(member) > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, "Member name length exceeds maximum supported length", 0); - return SINCE74(value, ); + return value; } v8::Local v8obj; @@ -210,15 +202,12 @@ static SINCE74(zval *, void) v8js_v8object_write_property(SINCE80(zend_object, z v8obj->CreateDataProperty(v8_context, V8JS_ZSYM(member), zval_to_v8js(value, isolate)); } - return SINCE74(value, ); + return value; } /* }}} */ -static void v8js_v8object_unset_property(SINCE80(zend_object, zval) *_object, SINCE80(zend_string, zval) *_member, void **cache_slot) /* {{{ */ +static void v8js_v8object_unset_property(zend_object *object, zend_string *member, void **cache_slot) /* {{{ */ { - zend_object *object = SINCE80(_object, Z_OBJ_P(_object)); - zend_string *member = SINCE80(_member, Z_STR_P(_member)); - v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); if (!obj->ctx) @@ -246,9 +235,9 @@ static void v8js_v8object_unset_property(SINCE80(zend_object, zval) *_object, SI } /* }}} */ -static HashTable *v8js_v8object_get_properties(SINCE80(zend_object, zval) *object) /* {{{ */ +static HashTable *v8js_v8object_get_properties(zend_object *object) /* {{{ */ { - v8js_v8object *obj = SINCE80(Z_V8JS_V8OBJECT_OBJ, Z_V8JS_V8OBJECT_OBJ_P)(object); + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); if (obj->properties == NULL) { @@ -287,7 +276,7 @@ static HashTable *v8js_v8object_get_properties(SINCE80(zend_object, zval) *objec } /* }}} */ -static HashTable *v8js_v8object_get_debug_info(SINCE80(zend_object, zval) *object, int *is_temp) /* {{{ */ +static HashTable *v8js_v8object_get_debug_info(zend_object *object, int *is_temp) /* {{{ */ { *is_temp = 0; return v8js_v8object_get_properties(object); @@ -426,7 +415,7 @@ static ZEND_FUNCTION(zend_v8object_func) static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_string *method, const zval *key) /* {{{ */ { v8js_v8object *obj = v8js_v8object_fetch_object(*object_ptr); - SINCE80(zend_internal_function, zend_function) *f; + zend_internal_function *f; if (!obj->ctx) { @@ -581,8 +570,8 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I static int v8js_v8object_get_closure(zend_object *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr, bool call) /* {{{ */ { - SINCE80(zend_internal_function, zend_function) *invoke; - v8js_v8object *obj = SINCE80(Z_V8JS_V8OBJECT_OBJ, Z_V8JS_V8OBJECT_OBJ_P)(object); + zend_internal_function *invoke; + v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); if (!obj->ctx) { @@ -609,7 +598,7 @@ static int v8js_v8object_get_closure(zend_object *object, zend_class_entry **ce_ if (zobj_ptr) { - *zobj_ptr = SINCE80(object, Z_OBJ_P(object)); + *zobj_ptr = object; } *ce_ptr = NULL; @@ -1034,7 +1023,6 @@ PHP_MINIT_FUNCTION(v8js_v8object_class) /* {{{ */ v8js_v8object_handlers.unset_property = v8js_v8object_unset_property; v8js_v8object_handlers.get_properties = v8js_v8object_get_properties; v8js_v8object_handlers.get_method = v8js_v8object_get_method; - SINCE80(, v8js_v8object_handlers.call_method = v8js_v8object_call_method); v8js_v8object_handlers.get_debug_info = v8js_v8object_get_debug_info; v8js_v8object_handlers.get_closure = v8js_v8object_get_closure; v8js_v8object_handlers.offset = XtOffsetOf(struct v8js_v8object, std); From d44530f717c3cb92b2141992a0938bc547d28435 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Mon, 30 May 2022 14:27:01 +0200 Subject: [PATCH 11/64] remove V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX polyfill --- v8js_v8.h | 4 ---- v8js_v8object_class.cc | 10 +++++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/v8js_v8.h b/v8js_v8.h index 5c13f00f..46e28a9c 100644 --- a/v8js_v8.h +++ b/v8js_v8.h @@ -88,10 +88,6 @@ int v8js_get_properties_hash(v8::Local jsValue, HashTable *retval, in V8JS_CTX_PROLOGUE(ctx); -// polyfill for ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX, which changes between 7.1 and 7.2 -#define V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \ - ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) - // In PHP 8.1, mismatched tentative return types emit a deprecation notice. // https://wiki.php.net/rfc/internal_method_return_types // diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index 4399e54f..c2d2697e 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -959,19 +959,19 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_v8generator_wakeup, 0) ZEND_END_ARG_INFO() -V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_current, 0, 0, IS_MIXED, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_current, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() -V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_key, 0, 0, IS_MIXED, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_key, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() -V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_next, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_next, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() -V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_rewind, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_rewind, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() -V8_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_valid, 0, 0, _IS_BOOL, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8generator_valid, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() static const zend_function_entry v8js_v8generator_methods[] = {/* {{{ */ From fa4babb30743dd19b4b24160bcc7acd5743801cc Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Tue, 31 May 2022 09:35:09 +0200 Subject: [PATCH 12/64] Remove support for V8 extensions --- README.md | 34 +-- php_v8js_macros.h | 3 - tests/create_snapshot_basic.phpt | 2 +- tests/exception_clearing.phpt | 2 +- tests/exception_propagation_2.phpt | 2 +- tests/exception_propagation_3.phpt | 2 +- tests/extensions_basic.phpt | 42 ---- tests/extensions_circular_dependency.phpt | 52 ----- tests/extensions_error.phpt | 44 ---- tests/unicode.phpt | 2 +- v8js_class.cc | 260 +--------------------- v8js_main.cc | 6 - 12 files changed, 11 insertions(+), 440 deletions(-) delete mode 100644 tests/extensions_basic.phpt delete mode 100644 tests/extensions_circular_dependency.phpt delete mode 100644 tests/extensions_error.phpt diff --git a/README.md b/README.md index 59066510..21fb08c6 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,10 @@ class V8Js * Initializes and starts V8 engine and returns new V8Js object with it's own V8 context. * @param string $object_name * @param array $variables - * @param array $extensions * @param bool $report_uncaught_exceptions * @param string $snapshot_blob */ - public function __construct($object_name = "PHP", array $variables = [], array $extensions = [], $report_uncaught_exceptions = TRUE, $snapshot_blob = NULL) + public function __construct($object_name = "PHP", array $variables = [], $report_uncaught_exceptions = TRUE, $snapshot_blob = NULL) {} /** @@ -177,30 +176,8 @@ class V8Js /** Static methods **/ - /** - * Registers persistent context independent global Javascript extension. - * NOTE! These extensions exist until PHP is shutdown and they need to be registered before V8 is initialized. - * For best performance V8 is initialized only once per process thus this call has to be done before any V8Js objects are created! - * @param string $extension_name - * @param string $code - * @param array $dependencies - * @param bool $auto_enable - * @return bool - */ - public static function registerExtension($extension_name, $code, array $dependencies, $auto_enable = FALSE) - {} - - /** - * Returns extensions successfully registered with V8Js::registerExtension(). - * @return array|string[] - */ - public static function getExtensions() - {} - /** * Creates a custom V8 heap snapshot with the provided JavaScript source embedded. - * Snapshots are supported by V8 4.3.7 and higher. For older versions of V8 this - * extension doesn't provide this method. * @param string $embed_source * @return string|false */ @@ -353,15 +330,6 @@ This behaviour can be changed by enabling the php.ini flag `v8js.use_array_acces Snapshots ========= -First of all snapshots are incompatible with extensions. So when you see - - # - # Fatal error in ../src/snapshot/startup-serializer.cc, line 122 - # Check failed: !isolate->has_installed_extensions(). - # - -you need to remove all extension registrations. - First of all [custom startup snapshots](https://v8project.blogspot.de/2015/09/custom-startup-snapshots.html) is a feature provided by V8 itself, built on top of it's general heap snapshots feature. The idea is that, since it is quite common to load some JavaScript library prior to any actual work to be done, that this library code diff --git a/php_v8js_macros.h b/php_v8js_macros.h index eb6d8118..606fa4d2 100644 --- a/php_v8js_macros.h +++ b/php_v8js_macros.h @@ -138,7 +138,6 @@ ZEND_EXTERN_MODULE_GLOBALS(v8js) * * - whether V8 has been initialized at all * - the V8 backend platform - * - loaded extensions * - V8 "command line" flags * * In a ZTS-enabled environment access to all of these variables must happen @@ -150,8 +149,6 @@ struct _v8js_process_globals { std::mutex lock; #endif - HashTable *extensions; - /* V8 command line flags */ char *v8_flags; diff --git a/tests/create_snapshot_basic.phpt b/tests/create_snapshot_basic.phpt index 731426de..56444493 100644 --- a/tests/create_snapshot_basic.phpt +++ b/tests/create_snapshot_basic.phpt @@ -22,7 +22,7 @@ if (strlen($snap) > 0) { var_dump("snapshot successfully created"); } -$v8 = new V8Js('PHP', array(), array(), true, $snap); +$v8 = new V8Js('PHP', array(), true, $snap); $v8->executeString('var_dump(doublify(23));'); ?> ===EOF=== diff --git a/tests/exception_clearing.phpt b/tests/exception_clearing.phpt index 3646c5a9..c02d465f 100644 --- a/tests/exception_clearing.phpt +++ b/tests/exception_clearing.phpt @@ -5,7 +5,7 @@ Test V8::executeString() : Exception clearing test --FILE-- getPendingException()); diff --git a/tests/exception_propagation_2.phpt b/tests/exception_propagation_2.phpt index c808e3aa..ce88e6a9 100644 --- a/tests/exception_propagation_2.phpt +++ b/tests/exception_propagation_2.phpt @@ -10,7 +10,7 @@ class Foo { public function __construct() { - $this->v8 = new V8Js(null, array(), array(), false); + $this->v8 = new V8Js(null, array(), false); $this->v8->foo = $this; $this->v8->executeString('fooobar', 'throw_0'); var_dump($this->v8->getPendingException()); diff --git a/tests/exception_propagation_3.phpt b/tests/exception_propagation_3.phpt index bc93c1d8..af7de8ce 100644 --- a/tests/exception_propagation_3.phpt +++ b/tests/exception_propagation_3.phpt @@ -10,7 +10,7 @@ class Foo { public function __construct() { - $this->v8 = new V8Js(null, array(), array(), false); + $this->v8 = new V8Js(null, array(), false); $this->v8->foo = $this; $this->v8->executeString('function foobar() { throw new SyntaxError(); }', 'throw_1'); $this->v8->executeString('try { foobar(); } catch (e) { print(e + " caught in JS!\n"); }', 'trycatch1'); diff --git a/tests/extensions_basic.phpt b/tests/extensions_basic.phpt deleted file mode 100644 index 308c79cd..00000000 --- a/tests/extensions_basic.phpt +++ /dev/null @@ -1,42 +0,0 @@ ---TEST-- -Test V8::registerExtension() : Basic extension registering ---SKIPIF-- - ---FILE-- - -===EOF=== ---EXPECTF-- -Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_basic.php on line 3 - -Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_basic.php on line 4 - -Deprecated: %s V8Js::getExtensions() is deprecated in %s%eextensions_basic.php on line 6 -array(2) { - ["a"]=> - array(2) { - ["auto_enable"]=> - bool(false) - ["deps"]=> - array(1) { - [0]=> - string(1) "b" - } - } - ["b"]=> - array(1) { - ["auto_enable"]=> - bool(false) - } -} - -Deprecated: V8Js::__construct(): Use of extensions is deprecated, $extensions array passed in %s%eextensions_basic.php on line 8 -Hello world! -===EOF=== diff --git a/tests/extensions_circular_dependency.phpt b/tests/extensions_circular_dependency.phpt deleted file mode 100644 index f015293b..00000000 --- a/tests/extensions_circular_dependency.phpt +++ /dev/null @@ -1,52 +0,0 @@ ---TEST-- -Test V8::registerExtension() : Circular dependencies ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_circular_dependency.php on line 3 - -Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_circular_dependency.php on line 4 - -Deprecated: %s V8Js::getExtensions() is deprecated in %s%eextensions_circular_dependency.php on line 6 -array(2) { - ["a"]=> - array(2) { - ["auto_enable"]=> - bool(false) - ["deps"]=> - array(1) { - [0]=> - string(1) "b" - } - } - ["b"]=> - array(2) { - ["auto_enable"]=> - bool(false) - ["deps"]=> - array(1) { - [0]=> - string(1) "a" - } - } -} - -Deprecated: V8Js::__construct(): Use of extensions is deprecated, $extensions array passed in %s%eextensions_circular_dependency.php on line 8 - -Warning: Fatal V8 error in v8::Context::New(): Circular extension dependency in %s on line 8 - -Fatal error: Uncaught V8JsException: Failed to create V8 context. Check that registered extensions do not have errors. in %s:8 -Stack trace: -#0 %s(8): V8Js->__construct('myobj', Array, Array) -#1 {main} - thrown in %s on line 8 diff --git a/tests/extensions_error.phpt b/tests/extensions_error.phpt deleted file mode 100644 index d2210ada..00000000 --- a/tests/extensions_error.phpt +++ /dev/null @@ -1,44 +0,0 @@ ---TEST-- -Test V8::registerExtension() : Register extension with errors ---SKIPIF-- - (.*)/", $minfo, $matches)) { - $version = explode('.', $matches[1]); - if($version[0] < 5 || ($version[0] == 5 && $version[1] < 7)) { - // old v8 version, has shorter error message and hence doesn't - // fit our EXCEPTF below - echo "SKIP too old V8 version"; - } -} - -?> ---FILE-- - -===EOF=== ---EXPECTF-- --- registerExtension -- - -Deprecated: %s V8Js::registerExtension() is deprecated in %s%eextensions_error.php on line 5 --- creating V8Js object -- -Error installing extension 'handlebars'. - -Fatal error: Uncaught V8JsException: Failed to create V8 context. Check that registered extensions do not have errors. in %s%eextensions_error.php:7 -Stack trace: -#0 %s%eextensions_error.php(7): V8Js->__construct() -#1 {main} - thrown in %s%eextensions_error.php on line 7 diff --git a/tests/unicode.phpt b/tests/unicode.phpt index 58fd2f59..0bbfa704 100644 --- a/tests/unicode.phpt +++ b/tests/unicode.phpt @@ -12,7 +12,7 @@ $unicode = 'äöüßÜÄÖÜ߀áàâÁÀµ²³▁▂▃▄▅▆▇█ $snapshot = V8Js::createSnapshot("var snapshot = {unicode: '" . $unicode . "'}"); # start V8Js -$jscript = new V8Js('php', array(), array(), true, $snapshot); +$jscript = new V8Js('php', array(), true, $snapshot); # insert unicode via php var $jscript->unicode = $unicode; diff --git a/v8js_class.cc b/v8js_class.cc index 0f49c832..0ca181ce 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -59,17 +59,6 @@ static void v8js_script_free(v8js_script *res); int le_v8js_script; -/* {{{ Extension container */ -struct v8js_jsext { - zend_bool auto_enable; - HashTable *deps_ht; - const char **deps; - int deps_count; - zend_string *name; - zend_string *source; -}; -/* }}} */ - #ifdef USE_INTERNAL_ALLOCATOR class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: @@ -247,73 +236,6 @@ static zend_object* v8js_new(zend_class_entry *ce) /* {{{ */ } /* }}} */ -static void v8js_free_ext_strarr(const char **arr, int count) /* {{{ */ -{ - int i; - - if (arr) { - for (i = 0; i < count; i++) { - if (arr[i]) { - free((void *) arr[i]); - } - } - free(arr); - } -} -/* }}} */ - -static void v8js_jsext_free_storage(v8js_jsext *jsext) /* {{{ */ -{ - if (jsext->deps_ht) { - zend_hash_destroy(jsext->deps_ht); - free(jsext->deps_ht); - } - if (jsext->deps) { - v8js_free_ext_strarr(jsext->deps, jsext->deps_count); - } - - // Free the persisted non-interned strings we allocated. - if (jsext->name) { - zend_string_release(jsext->name); - } - if (jsext->source) { - zend_string_release(jsext->source); - } - - free(jsext); -} -/* }}} */ - -static void v8js_jsext_dtor(zval *zv) /* {{{ */ -{ - v8js_jsext_free_storage(reinterpret_cast(Z_PTR_P(zv))); -} -/* }}} */ - -static int v8js_create_ext_strarr(const char ***retval, int count, HashTable *ht) /* {{{ */ -{ - const char **exts = NULL; - HashPosition pos; - zval *tmp; - int i = 0; - - exts = (const char **) calloc(1, count * sizeof(char *)); - zend_hash_internal_pointer_reset_ex(ht, &pos); - while ((tmp = zend_hash_get_current_data_ex(ht, &pos))) { - if (Z_TYPE_P(tmp) == IS_STRING) { - exts[i++] = zend_strndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); - } else { - v8js_free_ext_strarr(exts, i); - return FAILURE; - } - zend_hash_move_forward_ex(ht, &pos); - } - *retval = exts; - - return SUCCESS; -} -/* }}} */ - static void v8js_fatal_error_handler(const char *location, const char *message) /* {{{ */ { if (location) { @@ -328,15 +250,13 @@ static void v8js_fatal_error_handler(const char *location, const char *message) ((ZSTR_LEN(key) == sizeof(mname) - 1) && \ !strncasecmp(ZSTR_VAL(key), mname, ZSTR_LEN(key))) -/* {{{ proto void V8Js::__construct([string object_name [, array variables [, array extensions [, bool report_uncaught_exceptions [, string snapshot_blob]]]]]) +/* {{{ proto void V8Js::__construct([string object_name [, array variables [, bool report_uncaught_exceptions [, string snapshot_blob]]]]) __construct for V8Js */ static PHP_METHOD(V8Js, __construct) { zend_string *object_name = NULL; zend_bool report_uncaught = 1; - zval *vars_arr = NULL, *exts_arr = NULL; - const char **exts = NULL; - int exts_count = 0; + zval *vars_arr = NULL; zval *snapshot_blob = NULL; v8js_ctx *c = Z_V8JS_CTX_OBJ_P(getThis()) @@ -346,7 +266,7 @@ static PHP_METHOD(V8Js, __construct) return; } - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!aabz", &object_name, &vars_arr, &exts_arr, &report_uncaught, &snapshot_blob) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!abz", &object_name, &vars_arr, &report_uncaught, &snapshot_blob) == FAILURE) { return; } @@ -401,26 +321,6 @@ static PHP_METHOD(V8Js, __construct) ZVAL_NULL(&c->module_normaliser); ZVAL_NULL(&c->module_loader); - /* Include extensions used by this context */ - /* Note: Extensions registered with auto_enable do not need to be added separately like this. */ - if (exts_arr) - { - exts_count = zend_hash_num_elements(Z_ARRVAL_P(exts_arr)); - - if (exts_count != 0) { - php_error_docref(NULL, E_DEPRECATED, "Use of extensions is deprecated, $extensions array passed"); - } - - if (v8js_create_ext_strarr(&exts, exts_count, Z_ARRVAL_P(exts_arr)) == FAILURE) { - zend_throw_exception(php_ce_v8js_exception, - "Invalid extensions array passed", 0); - return; - } - } - - /* Declare configuration for extensions */ - v8::ExtensionConfiguration extension_conf(exts_count, exts); - // Isolate execution v8::Isolate *isolate = c->isolate; v8::Locker locker(isolate); @@ -442,17 +342,10 @@ static PHP_METHOD(V8Js, __construct) v8js_register_methods(global_template, c); /* Create context */ - v8::Local context = v8::Context::New(isolate, &extension_conf, global_template); - - if (exts) { - v8js_free_ext_strarr(exts, exts_count); - } + v8::Local context = v8::Context::New(isolate, nullptr, global_template); - /* If extensions have errors, context will be empty. (NOTE: This is V8 stuff, they expect the passed sources to compile :) */ if (context.IsEmpty()) { - zend_throw_exception(php_ce_v8js_exception, - "Failed to create V8 context. " - "Check that registered extensions do not have errors.", 0); + zend_throw_exception(php_ce_v8js_exception, "Failed to create V8 context.", 0); return; } @@ -1006,140 +899,10 @@ static void v8js_script_dtor(zend_resource *rsrc) /* {{{ */ } /* }}} */ -static int v8js_register_extension(zend_string *name, zend_string *source, zval *deps_arr, zend_bool auto_enable) /* {{{ */ -{ - v8js_jsext *jsext = NULL; - -#ifdef ZTS - v8js_process_globals.lock.lock(); -#endif - - if (!v8js_process_globals.extensions) { - v8js_process_globals.extensions = (HashTable *) malloc(sizeof(HashTable)); - zend_hash_init(v8js_process_globals.extensions, 1, NULL, v8js_jsext_dtor, 1); - } else if (zend_hash_exists(v8js_process_globals.extensions, name)) { -#ifdef ZTS - v8js_process_globals.lock.unlock(); -#endif - return FAILURE; - } - - jsext = (v8js_jsext *) calloc(1, sizeof(v8js_jsext)); - - if (deps_arr) { - jsext->deps_count = zend_hash_num_elements(Z_ARRVAL_P(deps_arr)); - - if (v8js_create_ext_strarr(&jsext->deps, jsext->deps_count, Z_ARRVAL_P(deps_arr)) == FAILURE) { - php_error_docref(NULL, E_WARNING, "Invalid dependency array passed"); - v8js_jsext_free_storage(jsext); -#ifdef ZTS - v8js_process_globals.lock.unlock(); -#endif - return FAILURE; - } - } - - jsext->auto_enable = auto_enable; - // Allocate a persistent string which will survive until module shutdown on both ZTS(Persistent) and NTS(Not interned, those would be cleaned up) - // (zend_string_dup would return the original interned string, if interned, so we don't use that) - jsext->name = zend_string_init(ZSTR_VAL(name), ZSTR_LEN(name), 1); - jsext->source = zend_string_init(ZSTR_VAL(source), ZSTR_LEN(source), 1); - - if (jsext->deps) { - jsext->deps_ht = (HashTable *) malloc(sizeof(HashTable)); - zend_hash_init(jsext->deps_ht, jsext->deps_count, NULL, v8js_persistent_zval_dtor, 1); - zend_hash_copy(jsext->deps_ht, Z_ARRVAL_P(deps_arr), v8js_persistent_zval_ctor); - } - - v8::Extension *extension = new v8::Extension(ZSTR_VAL(jsext->name), ZSTR_VAL(jsext->source), jsext->deps_count, jsext->deps); - - if (!zend_hash_add_ptr(v8js_process_globals.extensions, jsext->name, jsext)) { - v8js_jsext_free_storage(jsext); -#ifdef ZTS - v8js_process_globals.lock.unlock(); -#endif - return FAILURE; - } - -#ifdef ZTS - v8js_process_globals.lock.unlock(); -#endif - - extension->set_auto_enable(auto_enable ? true : false); - v8::RegisterExtension(std::unique_ptr(extension)); - - return SUCCESS; -} -/* }}} */ - /* ## Static methods ## */ -/* {{{ proto bool V8Js::registerExtension(string ext_name, string script [, array deps [, bool auto_enable]]) - */ -static PHP_METHOD(V8Js, registerExtension) -{ - zend_string *ext_name, *script; - zval *deps_arr = NULL; - zend_bool auto_enable = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|ab", &ext_name, &script, &deps_arr, &auto_enable) == FAILURE) { - return; - } - - if (!ZSTR_LEN(ext_name)) { - php_error_docref(NULL, E_WARNING, "Extension name cannot be empty"); - } else if (!ZSTR_LEN(script)) { - php_error_docref(NULL, E_WARNING, "Script cannot be empty"); - } else if (v8js_register_extension(ext_name, script, deps_arr, auto_enable) == SUCCESS) { - RETURN_TRUE; - } - RETURN_FALSE; -} -/* }}} */ - -/* {{{ proto array V8Js::getExtensions() - */ -static PHP_METHOD(V8Js, getExtensions) -{ - v8js_jsext *jsext; - zend_string *key; - zval *val, ext; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - array_init(return_value); - -#ifdef ZTS - v8js_process_globals.lock.lock(); -#endif - - if (v8js_process_globals.extensions) { - ZEND_HASH_FOREACH_STR_KEY_VAL(v8js_process_globals.extensions, key, val) { - if (key) { - jsext = (v8js_jsext *) Z_PTR_P(val); - array_init(&ext); - add_assoc_bool_ex(&ext, ZEND_STRL("auto_enable"), jsext->auto_enable); - if (jsext->deps_ht) { - zval deps_arr; - array_init(&deps_arr); - zend_hash_copy(Z_ARRVAL_P(&deps_arr), jsext->deps_ht, (copy_ctor_func_t) zval_add_ref); - add_assoc_zval_ex(&ext, ZEND_STRL("deps"), &deps_arr); - } - add_assoc_zval_ex(return_value, ZSTR_VAL(key), ZSTR_LEN(key), &ext); - } - } ZEND_HASH_FOREACH_END(); - } - -#ifdef ZTS - v8js_process_globals.lock.unlock(); -#endif -} -/* }}} */ - static v8::StartupData createSnapshotDataBlob(v8::SnapshotCreator *snapshot_creator, zend_string *str) /* {{{ */ { v8::Isolate *isolate = snapshot_creator->GetIsolate(); @@ -1203,7 +966,6 @@ static PHP_METHOD(V8Js, createSnapshot) ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_construct, 0, 0, 0) ZEND_ARG_INFO(0, object_name) ZEND_ARG_INFO(0, variables) - ZEND_ARG_INFO(0, extensions) ZEND_ARG_INFO(0, report_uncaught_exceptions) ZEND_ARG_INFO(0, snapshot_blob) ZEND_END_ARG_INFO() @@ -1257,16 +1019,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_setaverageobjectsize, 0, 0, 1) ZEND_ARG_INFO(0, average_object_size) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_registerextension, 0, 0, 2) - ZEND_ARG_INFO(0, extension_name) - ZEND_ARG_INFO(0, script) - ZEND_ARG_INFO(0, dependencies) - ZEND_ARG_INFO(0, auto_enable) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_v8js_getextensions, 0) -ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_createsnapshot, 0, 0, 1) ZEND_ARG_INFO(0, script) ZEND_END_ARG_INFO() @@ -1295,8 +1047,6 @@ const zend_function_entry v8js_methods[] = { /* {{{ */ PHP_ME(V8Js, setTimeLimit, arginfo_v8js_settimelimit, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setMemoryLimit, arginfo_v8js_setmemorylimit, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setAverageObjectSize, arginfo_v8js_setaverageobjectsize, ZEND_ACC_PUBLIC) - PHP_ME(V8Js, registerExtension, arginfo_v8js_registerextension, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_DEPRECATED) - PHP_ME(V8Js, getExtensions, arginfo_v8js_getextensions, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_DEPRECATED) PHP_ME(V8Js, createSnapshot, arginfo_v8js_createsnapshot, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) {NULL, NULL, NULL} }; diff --git a/v8js_main.cc b/v8js_main.cc index 66b58ef1..43453404 100644 --- a/v8js_main.cc +++ b/v8js_main.cc @@ -172,12 +172,6 @@ static PHP_MSHUTDOWN_FUNCTION(v8js) v8js_process_globals.v8_flags = NULL; } - if (v8js_process_globals.extensions) { - zend_hash_destroy(v8js_process_globals.extensions); - free(v8js_process_globals.extensions); - v8js_process_globals.extensions = NULL; - } - return SUCCESS; } /* }}} */ From f6a93c3cd6942beb243a87053b40b9d6f1aa3aeb Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Tue, 31 May 2022 09:53:09 +0200 Subject: [PATCH 13/64] Remove support for uncaught exceptions. Use try/catch. --- README.md | 6 +- tests/create_snapshot_basic.phpt | 2 +- tests/exception_clearing.phpt | 90 ----------------------- tests/exception_propagation_1.phpt | 37 ---------- tests/exception_propagation_2.phpt | 112 ----------------------------- tests/exception_propagation_3.phpt | 39 ---------- tests/issue_183_003.phpt | 2 - tests/unicode.phpt | 2 +- v8js_class.cc | 58 +-------------- v8js_class.h | 2 - v8js_v8.cc | 23 +----- 11 files changed, 9 insertions(+), 364 deletions(-) delete mode 100644 tests/exception_clearing.phpt delete mode 100644 tests/exception_propagation_1.phpt delete mode 100644 tests/exception_propagation_2.phpt delete mode 100644 tests/exception_propagation_3.phpt diff --git a/README.md b/README.md index 21fb08c6..fa30f9ab 100644 --- a/README.md +++ b/README.md @@ -78,10 +78,9 @@ class V8Js * Initializes and starts V8 engine and returns new V8Js object with it's own V8 context. * @param string $object_name * @param array $variables - * @param bool $report_uncaught_exceptions * @param string $snapshot_blob */ - public function __construct($object_name = "PHP", array $variables = [], $report_uncaught_exceptions = TRUE, $snapshot_blob = NULL) + public function __construct($object_name = "PHP", array $variables = [], $snapshot_blob = NULL) {} /** @@ -358,8 +357,7 @@ Exceptions ========== If the JavaScript code throws (without catching), causes errors or doesn't -compile, `V8JsScriptException` exceptions are thrown unless the `V8Js` object -is constructed with `report_uncaught_exceptions` set `FALSE`. +compile, `V8JsScriptException` exceptions are thrown. PHP exceptions that occur due to calls from JavaScript code by default are *not* re-thrown into JavaScript context but cause the JavaScript execution to diff --git a/tests/create_snapshot_basic.phpt b/tests/create_snapshot_basic.phpt index 56444493..0f75296a 100644 --- a/tests/create_snapshot_basic.phpt +++ b/tests/create_snapshot_basic.phpt @@ -22,7 +22,7 @@ if (strlen($snap) > 0) { var_dump("snapshot successfully created"); } -$v8 = new V8Js('PHP', array(), true, $snap); +$v8 = new V8Js('PHP', array(), $snap); $v8->executeString('var_dump(doublify(23));'); ?> ===EOF=== diff --git a/tests/exception_clearing.phpt b/tests/exception_clearing.phpt deleted file mode 100644 index c02d465f..00000000 --- a/tests/exception_clearing.phpt +++ /dev/null @@ -1,90 +0,0 @@ ---TEST-- -Test V8::executeString() : Exception clearing test ---SKIPIF-- - ---FILE-- -getPendingException()); - -$v8->clearPendingException(); -var_dump($v8->getPendingException()); - -$v8->executeString('fooobar', 'throw_0'); -var_dump($v8->getPendingException()); - -$v8->clearPendingException(); -var_dump($v8->getPendingException()); - -?> -===EOF=== ---EXPECTF-- -Deprecated: V8Js::__construct(): Disabling exception reporting is deprecated, $report_uncaught_exceptions != true in %s%eexception_clearing.php on line 3 - -Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 5 -NULL - -Deprecated: %s V8Js::clearPendingException() is deprecated in %s%eexception_clearing.php on line 7 - -Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 8 -NULL - -Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 11 -object(V8JsScriptException)#%d (13) { - ["message":protected]=> - string(49) "throw_0:1: ReferenceError: fooobar is not defined" - ["string":"Exception":private]=> - string(0) "" - ["code":protected]=> - int(0) - ["file":protected]=> - string(%d) "%s" - ["line":protected]=> - int(10) - ["trace":"Exception":private]=> - array(1) { - [0]=> - array(6) { - ["file"]=> - string(%d) "%s" - ["line"]=> - int(10) - ["function"]=> - string(13) "executeString" - ["class"]=> - string(4) "V8Js" - ["type"]=> - string(2) "->" - ["args"]=> - array(2) { - [0]=> - string(7) "fooobar" - [1]=> - string(7) "throw_0" - } - } - } - ["previous":"Exception":private]=> - NULL - ["JsFileName":protected]=> - string(7) "throw_0" - ["JsLineNumber":protected]=> - int(1) - ["JsStartColumn":protected]=> - int(0) - ["JsEndColumn":protected]=> - int(1) - ["JsSourceLine":protected]=> - string(7) "fooobar" - ["JsTrace":protected]=> - string(57) "ReferenceError: fooobar is not defined - at throw_0:1:1" -} - -Deprecated: %s V8Js::clearPendingException() is deprecated in %s%eexception_clearing.php on line 13 - -Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_clearing.php on line 14 -NULL -===EOF=== diff --git a/tests/exception_propagation_1.phpt b/tests/exception_propagation_1.phpt deleted file mode 100644 index cdc7f5f1..00000000 --- a/tests/exception_propagation_1.phpt +++ /dev/null @@ -1,37 +0,0 @@ ---TEST-- -Test V8::executeString() : Exception propagation test 1 ---SKIPIF-- - ---FILE-- -v8 = new V8Js(); - $this->v8->foo = $this; - $this->v8->executeString('fooobar', 'throw_0'); - var_dump($this->v8->getPendingException()); - $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " caught!\n"); }', 'trycatch1'); - $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " caught!\n"); }', 'trycatch2'); - } - - public function bar() - { - echo "To Bar!\n"; - $this->v8->executeString('throw new Error();', 'throw_1'); - } -} - -try { - $foo = new Foo(); -} catch (V8JsScriptException $e) { - echo "PHP Exception: ", $e->getMessage(), "\n"; //var_dump($e); -} -?> -===EOF=== ---EXPECTF-- -PHP Exception: throw_0:1: ReferenceError: fooobar is not defined -===EOF=== diff --git a/tests/exception_propagation_2.phpt b/tests/exception_propagation_2.phpt deleted file mode 100644 index ce88e6a9..00000000 --- a/tests/exception_propagation_2.phpt +++ /dev/null @@ -1,112 +0,0 @@ ---TEST-- -Test V8::executeString() : Exception propagation test 2 ---SKIPIF-- - ---FILE-- -v8 = new V8Js(null, array(), false); - $this->v8->foo = $this; - $this->v8->executeString('fooobar', 'throw_0'); - var_dump($this->v8->getPendingException()); - // the exception is not cleared before the next executeString call, - // hence the next *exiting* executeString will throw. - // In this case this is the executeString call in bar() function. - $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " caught!\n"); }', 'trycatch1'); - $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " caught!\n"); }', 'trycatch2'); - } - - public function bar() - { - echo "To Bar!\n"; - // This executeString call throws a PHP exception, not propagated - // to JS, hence immediately triggering the top-level catch handler. - $this->v8->executeString('throw new Error();', 'throw_1'); - } -} - -try { - $foo = new Foo(); -} catch (V8JsScriptException $e) { - echo "PHP Exception: ", $e->getMessage(), "\n"; //var_dump($e); -} -?> -===EOF=== ---EXPECTF-- -Deprecated: V8Js::__construct(): Disabling exception reporting is deprecated, $report_uncaught_exceptions != true in %s%eexception_propagation_2.php on line 8 - -Deprecated: %s V8Js::getPendingException() is deprecated in %s%eexception_propagation_2.php on line 11 -object(V8JsScriptException)#%d (13) { - ["message":protected]=> - string(49) "throw_0:1: ReferenceError: fooobar is not defined" - ["string":"Exception":private]=> - string(0) "" - ["code":protected]=> - int(0) - ["file":protected]=> - string(%d) "%s" - ["line":protected]=> - int(10) - ["trace":"Exception":private]=> - array(2) { - [0]=> - array(6) { - ["file"]=> - string(%d) "%s" - ["line"]=> - int(10) - ["function"]=> - string(13) "executeString" - ["class"]=> - string(4) "V8Js" - ["type"]=> - string(2) "->" - ["args"]=> - array(2) { - [0]=> - string(7) "fooobar" - [1]=> - string(7) "throw_0" - } - } - [1]=> - array(6) { - ["file"]=> - string(%d) "%s" - ["line"]=> - int(29) - ["function"]=> - string(11) "__construct" - ["class"]=> - string(3) "Foo" - ["type"]=> - string(2) "->" - ["args"]=> - array(0) { - } - } - } - ["previous":"Exception":private]=> - NULL - ["JsFileName":protected]=> - string(7) "throw_0" - ["JsLineNumber":protected]=> - int(1) - ["JsStartColumn":protected]=> - int(0) - ["JsEndColumn":protected]=> - int(1) - ["JsSourceLine":protected]=> - string(7) "fooobar" - ["JsTrace":protected]=> - string(57) "ReferenceError: fooobar is not defined - at throw_0:1:1" -} -To Bar! -PHP Exception: throw_0:1: ReferenceError: fooobar is not defined -===EOF=== diff --git a/tests/exception_propagation_3.phpt b/tests/exception_propagation_3.phpt deleted file mode 100644 index af7de8ce..00000000 --- a/tests/exception_propagation_3.phpt +++ /dev/null @@ -1,39 +0,0 @@ ---TEST-- -Test V8::executeString() : Exception propagation test 3 ---SKIPIF-- - ---FILE-- -v8 = new V8Js(null, array(), false); - $this->v8->foo = $this; - $this->v8->executeString('function foobar() { throw new SyntaxError(); }', 'throw_1'); - $this->v8->executeString('try { foobar(); } catch (e) { print(e + " caught in JS!\n"); }', 'trycatch1'); - $this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " caught via PHP callback!\n"); }', 'trycatch2'); - } - - public function bar() - { - echo "To Bar!\n"; - $this->v8->executeString('throw new Error();', 'throw_2'); - } -} - -try { - $foo = new Foo(); -} catch (V8JsScriptException $e) { - echo "PHP Exception: ", $e->getMessage(), "\n"; -} -?> -===EOF=== ---EXPECTF-- -Deprecated: V8Js::__construct(): Disabling exception reporting is deprecated, $report_uncaught_exceptions != true in %s%eexception_propagation_3.php on line 8 -SyntaxError caught in JS! -To Bar! -Error caught via PHP callback! -===EOF=== diff --git a/tests/issue_183_003.phpt b/tests/issue_183_003.phpt index 1a96c3f3..3b92b423 100644 --- a/tests/issue_183_003.phpt +++ b/tests/issue_183_003.phpt @@ -19,7 +19,6 @@ var_dump(typeof PHP.executeString); var_dump(typeof PHP.compileString); var_dump(typeof PHP.executeScript); var_dump(typeof PHP.checkString); -var_dump(typeof PHP.getPendingException); var_dump(typeof PHP.setModuleNormaliser); var_dump(typeof PHP.setModuleLoader); var_dump(typeof PHP.registerExtension); @@ -52,6 +51,5 @@ string(9) "undefined" string(9) "undefined" string(9) "undefined" string(9) "undefined" -string(9) "undefined" string(6) "caught" ===EOF=== diff --git a/tests/unicode.phpt b/tests/unicode.phpt index 0bbfa704..648ed041 100644 --- a/tests/unicode.phpt +++ b/tests/unicode.phpt @@ -12,7 +12,7 @@ $unicode = 'äöüßÜÄÖÜ߀áàâÁÀµ²³▁▂▃▄▅▆▇█ $snapshot = V8Js::createSnapshot("var snapshot = {unicode: '" . $unicode . "'}"); # start V8Js -$jscript = new V8Js('php', array(), true, $snapshot); +$jscript = new V8Js('php', array(), $snapshot); # insert unicode via php var $jscript->unicode = $unicode; diff --git a/v8js_class.cc b/v8js_class.cc index 0ca181ce..badbe117 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -78,7 +78,6 @@ static void v8js_free_storage(zend_object *object) /* {{{ */ zend_object_std_dtor(&c->std); - zval_ptr_dtor(&c->pending_exception); zval_ptr_dtor(&c->module_normaliser); zval_ptr_dtor(&c->module_loader); @@ -250,12 +249,11 @@ static void v8js_fatal_error_handler(const char *location, const char *message) ((ZSTR_LEN(key) == sizeof(mname) - 1) && \ !strncasecmp(ZSTR_VAL(key), mname, ZSTR_LEN(key))) -/* {{{ proto void V8Js::__construct([string object_name [, array variables [, bool report_uncaught_exceptions [, string snapshot_blob]]]]) +/* {{{ proto void V8Js::__construct([string object_name [, array variables [, string snapshot_blob]]]) __construct for V8Js */ static PHP_METHOD(V8Js, __construct) { zend_string *object_name = NULL; - zend_bool report_uncaught = 1; zval *vars_arr = NULL; zval *snapshot_blob = NULL; @@ -266,7 +264,7 @@ static PHP_METHOD(V8Js, __construct) return; } - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!abz", &object_name, &vars_arr, &report_uncaught, &snapshot_blob) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!az", &object_name, &vars_arr, &snapshot_blob) == FAILURE) { return; } @@ -274,14 +272,8 @@ static PHP_METHOD(V8Js, __construct) v8js_v8_init(); /* Throw PHP exception if uncaught exceptions exist */ - c->report_uncaught = report_uncaught; - ZVAL_NULL(&c->pending_exception); c->in_execution = 0; - if (report_uncaught != 1) { - php_error_docref(NULL, E_DEPRECATED, "Disabling exception reporting is deprecated, $report_uncaught_exceptions != true"); - } - new (&c->create_params) v8::Isolate::CreateParams(); #ifdef USE_INTERNAL_ALLOCATOR @@ -703,43 +695,6 @@ static PHP_METHOD(V8Js, checkString) } /* }}} */ -/* {{{ proto mixed V8Js::getPendingException() - */ -static PHP_METHOD(V8Js, getPendingException) -{ - v8js_ctx *c; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - c = Z_V8JS_CTX_OBJ_P(getThis()); - - if (Z_TYPE(c->pending_exception) == IS_OBJECT) { - RETURN_ZVAL(&c->pending_exception, 1, 0); - } -} -/* }}} */ - -/* {{{ proto void V8Js::clearPendingException() - */ -static PHP_METHOD(V8Js, clearPendingException) -{ - v8js_ctx *c; - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - c = Z_V8JS_CTX_OBJ_P(getThis()); - - if (Z_TYPE(c->pending_exception) == IS_OBJECT) { - zval_ptr_dtor(&c->pending_exception); - ZVAL_NULL(&c->pending_exception); - } -} -/* }}} */ - /* {{{ proto void V8Js::setModuleNormaliser(string base, string module_id) */ static PHP_METHOD(V8Js, setModuleNormaliser) @@ -966,7 +921,6 @@ static PHP_METHOD(V8Js, createSnapshot) ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_construct, 0, 0, 0) ZEND_ARG_INFO(0, object_name) ZEND_ARG_INFO(0, variables) - ZEND_ARG_INFO(0, report_uncaught_exceptions) ZEND_ARG_INFO(0, snapshot_blob) ZEND_END_ARG_INFO() @@ -1000,12 +954,6 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_checkstring, 0, 0, 1) ZEND_ARG_INFO(0, script) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO(arginfo_v8js_getpendingexception, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_v8js_clearpendingexception, 0) -ZEND_END_ARG_INFO() - ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_setmodulenormaliser, 0, 0, 2) ZEND_ARG_INFO(0, base) ZEND_ARG_INFO(0, module_id) @@ -1040,8 +988,6 @@ const zend_function_entry v8js_methods[] = { /* {{{ */ PHP_ME(V8Js, compileString, arginfo_v8js_compilestring, ZEND_ACC_PUBLIC) PHP_ME(V8Js, executeScript, arginfo_v8js_executescript, ZEND_ACC_PUBLIC) PHP_ME(V8Js, checkString, arginfo_v8js_checkstring, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) - PHP_ME(V8Js, getPendingException, arginfo_v8js_getpendingexception, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) - PHP_ME(V8Js, clearPendingException, arginfo_v8js_clearpendingexception, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) PHP_ME(V8Js, setModuleNormaliser, arginfo_v8js_setmodulenormaliser, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setModuleLoader, arginfo_v8js_setmoduleloader, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setTimeLimit, arginfo_v8js_settimelimit, ZEND_ACC_PUBLIC) diff --git a/v8js_class.h b/v8js_class.h index 3277573f..e5caeb1c 100644 --- a/v8js_class.h +++ b/v8js_class.h @@ -37,8 +37,6 @@ struct cmp_str { struct v8js_ctx { v8::Persistent object_name; v8::Persistent context; - zend_bool report_uncaught; - zval pending_exception; int in_execution; v8::Isolate *isolate; diff --git a/v8js_v8.cc b/v8js_v8.cc index 8d8f99a6..32444002 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -224,31 +224,14 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value, return; } - /* There was pending exception left from earlier executions -> throw to PHP */ - if (Z_TYPE(c->pending_exception) == IS_OBJECT) { - zend_throw_exception_object(&c->pending_exception); - ZVAL_NULL(&c->pending_exception); - } - /* Handle runtime JS exceptions */ if (try_catch.HasCaught()) { /* Pending exceptions are set only in outer caller, inner caller exceptions are always rethrown */ if (c->in_execution < 1) { - - /* Report immediately if report_uncaught is true */ - if (c->report_uncaught) { - v8js_throw_script_exception(c->isolate, &try_catch); - zval_ptr_dtor(&zv_v8inst); - return; - } - - /* Exception thrown from JS, preserve it for future execution */ - if (result.IsEmpty()) { - v8js_create_script_exception(&c->pending_exception, c->isolate, &try_catch); - zval_ptr_dtor(&zv_v8inst); - return; - } + v8js_throw_script_exception(c->isolate, &try_catch); + zval_ptr_dtor(&zv_v8inst); + return; } /* Rethrow back to JS */ From bfd2bfc2df167dcf2f2e1b94a0add57766441dda Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Tue, 31 May 2022 09:57:52 +0200 Subject: [PATCH 14/64] remove deprected V8Js::checkString function --- tests/checkstring.phpt | 24 ------------------------ v8js_class.cc | 27 --------------------------- 2 files changed, 51 deletions(-) delete mode 100644 tests/checkstring.phpt diff --git a/tests/checkstring.phpt b/tests/checkstring.phpt deleted file mode 100644 index dc2ff5b0..00000000 --- a/tests/checkstring.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -Test V8::executeString() : Script validator test ---SKIPIF-- - ---FILE-- -checkString('print("Hello World!");')); - -try { - var_dump($v8->checkString('print("Hello World!);')); -} catch (V8JsScriptException $e) { - var_dump($e->getMessage()); -} -?> -===EOF=== ---EXPECTF-- -Deprecated: %s V8Js::checkString() is deprecated in %s on line %d -bool(true) - -Deprecated: %s V8Js::checkString() is deprecated in %s on line %d -string(%d) "V8Js::checkString():1: SyntaxError: %s" -===EOF=== diff --git a/v8js_class.cc b/v8js_class.cc index badbe117..6fdfa07c 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -669,32 +669,6 @@ static PHP_METHOD(V8Js, executeScript) } /* }}} */ -/* {{{ proto mixed V8Js::checkString(string script) - */ -static PHP_METHOD(V8Js, checkString) -{ - zend_string *str = NULL; - zend_string *identifier = zend_string_init("V8Js::checkString()", 19, 0); - - v8js_script *res = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) { - return; - } - - v8js_compile_script(getThis(), str, identifier, &res); - zend_string_release(identifier); - - if (!res) { - RETURN_FALSE; - } - - v8js_script_free(res); - efree(res); - RETURN_TRUE; -} -/* }}} */ - /* {{{ proto void V8Js::setModuleNormaliser(string base, string module_id) */ static PHP_METHOD(V8Js, setModuleNormaliser) @@ -987,7 +961,6 @@ const zend_function_entry v8js_methods[] = { /* {{{ */ PHP_ME(V8Js, executeString, arginfo_v8js_executestring, ZEND_ACC_PUBLIC) PHP_ME(V8Js, compileString, arginfo_v8js_compilestring, ZEND_ACC_PUBLIC) PHP_ME(V8Js, executeScript, arginfo_v8js_executescript, ZEND_ACC_PUBLIC) - PHP_ME(V8Js, checkString, arginfo_v8js_checkstring, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) PHP_ME(V8Js, setModuleNormaliser, arginfo_v8js_setmodulenormaliser, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setModuleLoader, arginfo_v8js_setmoduleloader, ZEND_ACC_PUBLIC) PHP_ME(V8Js, setTimeLimit, arginfo_v8js_settimelimit, ZEND_ACC_PUBLIC) From 4327b4a3f91c72b8a537faf7c60e5850485a9695 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Tue, 31 May 2022 10:56:47 +0200 Subject: [PATCH 15/64] Update MacOS instructions --- README.MacOS.md | 75 ++++--------------------------------------------- 1 file changed, 5 insertions(+), 70 deletions(-) diff --git a/README.MacOS.md b/README.MacOS.md index 4ded358c..9a11c82a 100644 --- a/README.MacOS.md +++ b/README.MacOS.md @@ -2,87 +2,22 @@ V8Js on MacOS ============= Installation of V8Js on MacOS is pretty much straight forward. +The ARM-based M1 chips also work just fine. -If you have [brew](https://brew.sh) around, just `brew install -php70-v8js` (or `php71-v8js` / `php72-v8js` depending on your PHP -version) and you should be done. This will install a recent version -of V8 along with this extension. - -Otherwise you need to compile latest v8 manually. - -Compile latest v8 ------------------ - -``` -cd /tmp - -# Install depot_tools first (needed for source checkout) -git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git -export PATH=`pwd`/depot_tools:"$PATH" - -# Download v8 -fetch v8 -cd v8 - -# (optional) If you'd like to build a certain version: -git checkout 3.32.6 -gclient sync - -# Compile V8 (using up to 8 CPU cores, requires a lot of RAM, adapt as needed) -make native library=shared -j8 - -# Install to /usr -mkdir -p /usr/local/lib /usr/local/include -cp out/native/lib*.dylib /usr/local/lib/ -cp out/native/libv8_*.a /usr/local/lib/ -cp -R include/* /usr/local/include -``` - -You cannot install the libraries to any location you want since they -have a install name that is baked into the library. You can check -the install name with `otool -D out/native/libv8.dylib`. - -During the build snapshot generation may fail like so: - -``` -ACTION tools_gyp_v8_gyp_v8_snapshot_target_run_mksnapshot /Users/vagrant/v8/out/native/obj.target/v8_snapshot/geni/snapshot.cc -dyld: Library not loaded: /usr/local/lib/libicui18n.dylib - Referenced from: /Users/vagrant/v8/out/native/mksnapshot - Reason: image not found -/bin/sh: line 1: 18964 Trace/BPT trap: 5 "/Users/vagrant/v8/out/native/mksnapshot" --log-snapshot-positions --logfile "/Users/vagrant/v8/out/native/obj.target/v8_snapshot/geni/snapshot.log" --random-seed 314159265 "/Users/vagrant/v8/out/native/obj.target/v8_snapshot/geni/snapshot.cc" -make[1]: *** [/Users/vagrant/v8/out/native/obj.target/v8_snapshot/geni/snapshot.cc] Error 133 -make: *** [native] Error 2 -``` - -... if that happens, just copy libicu*.dylib to /usr/local/lib already -and start make again (then simply continue with installation): - -``` -cp out/native/libicu*.dylib /usr/local/lib/ -make native library=shared -j8 -``` +You can use [brew](https://brew.sh) to install `v8`. This provides +both the library as well as necessary include files in `/opt/homebrew`. Compile php-v8js itself ----------------------- -If you're using Apple LLVM compiler (instead of gcc) you need to pass the `-Wno-c++11-narrowing` -flag. Otherwise compilation fails due to narrowing errors in PHP itself, which LLVM is much pickier -with (compared to gcc). - ``` cd /tmp git clone https://github.com/phpv8/v8js.git cd v8js phpize -./configure CXXFLAGS="-Wno-c++11-narrowing" -make +./configure --with-v8js=/opt/homebrew CPPFLAGS="-DV8_COMPRESS_POINTERS" +make -j4 make test make install ``` - -V8Js' build system assumes that the `icudtl.dat` file is located next to the `libv8.dylib` -library file and compiles the path into the library itself. If for whatever reason the -`icudtl.dat` file is stored at a different place during runtime, you need to set the -php.ini variable `v8js.icudtl_dat_path` to point to the file. Otherwise locale-aware -features of V8 will not work as expected. From 15ed4943ada5cfbed0a43185f8139bb059d3e061 Mon Sep 17 00:00:00 2001 From: rbro Date: Sat, 17 Dec 2022 17:03:01 -0500 Subject: [PATCH 16/64] php 8.2 compatibility --- v8js_v8object_class.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index 7b80a35e..d6edf904 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -464,7 +464,7 @@ static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_st } /* }}} */ -static int v8js_v8object_get_closure(zend_object *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr, bool call) /* {{{ */ +static zend_result v8js_v8object_get_closure(zend_object *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr, bool call) /* {{{ */ { zend_internal_function *invoke; v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); From 5a10dec6985c2d40a9953a3a727d0a9333ec72bf Mon Sep 17 00:00:00 2001 From: Christiano Becker Date: Mon, 16 Jan 2023 17:35:07 -0300 Subject: [PATCH 17/64] When FLAG_PROPAGATE_PHP_EXCEPTIONS is set, check for unwind or graceful exit before propagate --- tests/issue_497_001.phpt | 37 +++++++++++++++++++++++++++++++++++++ v8js_object_export.cc | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/issue_497_001.phpt diff --git a/tests/issue_497_001.phpt b/tests/issue_497_001.phpt new file mode 100644 index 00000000..deb3daf4 --- /dev/null +++ b/tests/issue_497_001.phpt @@ -0,0 +1,37 @@ +--TEST-- +Test V8::executeString() : Issue #497 (segmentation fault calling PHP exit inside object function) +--SKIPIF-- + +--FILE-- +foo = new Foo(); + +$JS = <<< EOT +PHP.foo.somecall(); +PHP.foo.bar(); +EOT; + +$v8->executeString($JS, '', \V8JS::FLAG_PROPAGATE_PHP_EXCEPTIONS); +echo 'Not here!!'; +?> +--EXPECTF-- +string(12) "Foo somecall" +string(7) "Foo bar" +string(14) "Foo __destruct" diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 78597d07..ebbabde8 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -167,7 +167,7 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c } if(EG(exception)) { - if(ctx->flags & V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS) { + if((ctx->flags & V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS) && !zend_is_graceful_exit(EG(exception)) && !zend_is_unwind_exit(EG(exception))) { zval tmp_zv; ZVAL_OBJ(&tmp_zv, EG(exception)); return_value = isolate->ThrowException(zval_to_v8js(&tmp_zv, isolate)); From 37cdb6f9cf79b0880842ec82514f9b0ed7edb3ea Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 3 Feb 2023 19:38:20 +0100 Subject: [PATCH 18/64] fix build with php <8.2, refs #493 --- v8js_v8object_class.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index d6edf904..ff1495c5 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -464,7 +464,12 @@ static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_st } /* }}} */ -static zend_result v8js_v8object_get_closure(zend_object *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr, bool call) /* {{{ */ +#if PHP_VERSION_ID < 80200 +static int v8js_v8object_get_closure +#else +static zend_result v8js_v8object_get_closure +#endif +(zend_object *object, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **zobj_ptr, bool call) /* {{{ */ { zend_internal_function *invoke; v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ(object); From e06b382bd0d2224dc21ebbb6f5a779e11e468f51 Mon Sep 17 00:00:00 2001 From: Marek Skopal Date: Wed, 8 Feb 2023 14:04:03 +0100 Subject: [PATCH 19/64] Fixed build on PHP 8.0.x --- v8js_object_export.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 967f6acc..2154d278 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -38,7 +38,11 @@ v8::Local v8js_propagate_exception(v8js_ctx *ctx) /* {{{ */ { v8::Local return_value = v8::Null(ctx->isolate); +#if PHP_VERSION_ID < 80100 + if (!(ctx->flags & V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS) || zend_is_unwind_exit(EG(exception))) { +#else if (!(ctx->flags & V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS) || zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception))) { +#endif v8js_terminate_execution(ctx->isolate); return return_value; } From 83431fbd52fc9cb578bcbcfc0bebc23c4f05e1bb Mon Sep 17 00:00:00 2001 From: Christiano Becker Date: Sat, 18 Feb 2023 10:18:36 -0300 Subject: [PATCH 20/64] * Added AllowDynamicPropertis on V8Js, V8Object and V8Function * Added #[AllowDynamicProperties] on test classes that uses Dynamic Properties --- tests/has_property_after_dispose.phpt | 1 + tests/issue_250_001.phpt | 7 ++++--- tests/property_visibility-has-property.phpt | 1 + tests/property_visibility-set.phpt | 1 + tests/use_after_dispose.phpt | 1 + v8js_class.cc | 9 +++++++++ v8js_v8object_class.cc | 17 +++++++++++++++++ 7 files changed, 34 insertions(+), 3 deletions(-) diff --git a/tests/has_property_after_dispose.phpt b/tests/has_property_after_dispose.phpt index 02ee6230..4f847256 100644 --- a/tests/has_property_after_dispose.phpt +++ b/tests/has_property_after_dispose.phpt @@ -5,6 +5,7 @@ Test V8::executeString() : has_property after dispose --FILE-- ===EOF=== --EXPECTF-- -Fatal error: Uncaught Error: Attempt to modify property "b" on null in %s%eissue_250_001.php:9 +Fatal error: Uncaught Error: Attempt to modify property "b" on null in %s%eissue_250_001.php:10 Stack trace: #0 [internal function]: TestObject->setTitle('ouch') -#1 %s%eissue_250_001.php(44): V8Js->executeString(' var v1 = se...') +#1 %s%eissue_250_001.php(45): V8Js->executeString(' var v1 = se...') #2 {main} - thrown in %s%eissue_250_001.php on line 9 + thrown in %s%eissue_250_001.php on line 10 diff --git a/tests/property_visibility-has-property.phpt b/tests/property_visibility-has-property.phpt index 1fdb5dfd..06b7f115 100644 --- a/tests/property_visibility-has-property.phpt +++ b/tests/property_visibility-has-property.phpt @@ -5,6 +5,7 @@ Test V8::executeString() : Property visibility - has property --FILE-- create_object = v8js_new; +#if PHP_VERSION_ID >= 80200 + php_ce_v8js->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES; + + zend_string *attribute_name_AllowDynamicProperties_class_V8Js = zend_string_init_interned("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1); + zend_add_class_attribute(php_ce_v8js, attribute_name_AllowDynamicProperties_class_V8Js, 0); + zend_string_release(attribute_name_AllowDynamicProperties_class_V8Js); +#endif + /* V8Js handlers */ memcpy(&v8js_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); v8js_object_handlers.clone_obj = NULL; diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index ff1495c5..7bc4b4fb 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -29,6 +29,7 @@ extern "C" #include "zend_closures.h" #include "ext/spl/spl_exceptions.h" #include "zend_exceptions.h" +#include "zend_attributes.h" } /* {{{ Class Entries */ @@ -899,11 +900,27 @@ PHP_MINIT_FUNCTION(v8js_v8object_class) /* {{{ */ php_ce_v8object->ce_flags |= ZEND_ACC_FINAL; php_ce_v8object->create_object = v8js_v8object_new; +#if PHP_VERSION_ID >= 80200 + php_ce_v8object->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES; + + zend_string *attribute_name_AllowDynamicProperties_class_v8object = zend_string_init_interned("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1); + zend_add_class_attribute(php_ce_v8object, attribute_name_AllowDynamicProperties_class_v8object, 0); + zend_string_release(attribute_name_AllowDynamicProperties_class_v8object); +#endif + /* V8Function Class */ INIT_CLASS_ENTRY(ce, "V8Function", v8js_v8function_methods); php_ce_v8function = zend_register_internal_class(&ce); php_ce_v8function->ce_flags |= ZEND_ACC_FINAL; php_ce_v8function->create_object = v8js_v8object_new; + +#if PHP_VERSION_ID >= 80200 + php_ce_v8function->ce_flags |= ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES; + + zend_string *attribute_name_AllowDynamicProperties_class_v8function = zend_string_init_interned("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1); + zend_add_class_attribute(php_ce_v8function, attribute_name_AllowDynamicProperties_class_v8function, 0); + zend_string_release(attribute_name_AllowDynamicProperties_class_v8function); +#endif /* V8Generator Class */ INIT_CLASS_ENTRY(ce, "V8Generator", v8js_v8generator_methods); From 1e25cc8788393a18a1cf43626e43238eed6ec5b0 Mon Sep 17 00:00:00 2001 From: Mark Grainger Date: Sat, 18 Feb 2023 14:58:43 +0000 Subject: [PATCH 21/64] segfault fix when checking with empty --- v8js_v8object_class.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index ff1495c5..332b9a26 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -916,7 +916,6 @@ PHP_MINIT_FUNCTION(v8js_v8object_class) /* {{{ */ /* V8 handlers */ memcpy(&v8js_v8object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); v8js_v8object_handlers.clone_obj = NULL; - v8js_v8object_handlers.cast_object = NULL; v8js_v8object_handlers.get_property_ptr_ptr = v8js_v8object_get_property_ptr_ptr; v8js_v8object_handlers.has_property = v8js_v8object_has_property; v8js_v8object_handlers.read_property = v8js_v8object_read_property; From 79a46804dc850268833d39ebf4f1e3efdaca8b80 Mon Sep 17 00:00:00 2001 From: Mark Grainger Date: Sat, 18 Feb 2023 15:12:29 +0000 Subject: [PATCH 22/64] empty() test --- tests/issue_504_001.phpt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/issue_504_001.phpt diff --git a/tests/issue_504_001.phpt b/tests/issue_504_001.phpt new file mode 100644 index 00000000..79d96583 --- /dev/null +++ b/tests/issue_504_001.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test empty() : Segmentation fault caused by 'empty' check on a V8Function object +--SKIPIF-- + +--FILE-- +executeString(' + a = { + main: function() {} + }; +', null, V8Js::FLAG_FORCE_ARRAY | V8Js::FLAG_PROPAGATE_PHP_EXCEPTIONS); + +if (!empty($r['main'])) { + echo 'Ok' . PHP_EOL; +} +?> +--EXPECTF-- +Ok + From f24a8af0f5e69106fc46ea3b5b40fbece179f1f4 Mon Sep 17 00:00:00 2001 From: Christiano Becker Date: Mon, 20 Feb 2023 07:13:41 -0300 Subject: [PATCH 23/64] * tests/timezones.phpt - added LC_ALL=C to prevent test failing when another locale is set as default --- tests/timezones.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/timezones.phpt b/tests/timezones.phpt index 73c7c81c..358021a3 100644 --- a/tests/timezones.phpt +++ b/tests/timezones.phpt @@ -9,6 +9,7 @@ require_once(dirname(__FILE__) . '/skipif.inc'); ?> --FILE-- Date: Mon, 20 Feb 2023 08:09:13 -0300 Subject: [PATCH 24/64] PHP 8.2 compatibility * tests/array_access_002.phpt - added #[AllowDynamicProperties] to the class MyArray * tests/js-construct-protected-ctor.phpt - some change on how pph8.2 Exepctions references the line that caused the exception, when some call have multiple lines (eg: the executeString in this test), now references the line where the command started (first line) instead of the last line. * V8Js Object Export: added to not enumerate magic methods __serialize and __unserialize - this two methods was added to DateTime objects and was causing tests/var_dump.phpt failing. --- tests/array_access_002.phpt | 1 + tests/js-construct-protected-ctor.phpt | 4 ++-- v8js_object_export.cc | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/array_access_002.phpt b/tests/array_access_002.phpt index f8c6e886..641cb519 100644 --- a/tests/array_access_002.phpt +++ b/tests/array_access_002.phpt @@ -6,6 +6,7 @@ Test V8::executeString() : Use ArrayAccess with JavaScript native push method v8js.use_array_access = 1 --FILE-- string(%d) "%s" ["line":protected]=> - int(29) + int(%d) ["trace":"Exception":private]=> array(1) { [0]=> @@ -60,7 +60,7 @@ object(V8JsScriptException)#%d (13) { ["file"]=> string(%d) "%s" ["line"]=> - int(29) + int(%d) ["function"]=> string(13) "executeString" ["class"]=> diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 2154d278..ea1a0f25 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -395,7 +395,9 @@ static void v8js_named_property_enumerator(const v8::PropertyCallbackInfo Date: Mon, 20 Feb 2023 12:47:20 -0300 Subject: [PATCH 25/64] * Propagate exception when zend_read_property reads __get and throws an exception --- v8js_object_export.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/v8js_object_export.cc b/v8js_object_export.cc index ea1a0f25..7b287a1f 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -765,10 +765,12 @@ v8::Local v8js_named_property_callback(v8::Local property_n (property_info != ZEND_WRONG_PROPERTY_INFO && property_info->flags & ZEND_ACC_PUBLIC)) { zval *property_val = zend_read_property(NULL, &zobject, name, name_len, true, &php_value); - // special case uninitialized_zval_ptr and return an empty value - // (indicating that we don't intercept this property) if the - // property doesn't exist. - if (property_val == &EG(uninitialized_zval)) { + if(EG(exception)) { + ret_value = v8js_propagate_exception(ctx); + } else if (property_val == &EG(uninitialized_zval)) { + // special case uninitialized_zval_ptr and return an empty value + // (indicating that we don't intercept this property) if the + // property doesn't exist. ret_value = v8::Local(); } else { // wrap it From 35b5bff97702ba2aca44b0c9541c15e2eefabd1e Mon Sep 17 00:00:00 2001 From: Christiano Becker Date: Mon, 20 Feb 2023 14:59:41 -0300 Subject: [PATCH 26/64] * Added test tests/php_exceptions_007.phpt --- tests/php_exceptions_007.phpt | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/php_exceptions_007.phpt diff --git a/tests/php_exceptions_007.phpt b/tests/php_exceptions_007.phpt new file mode 100644 index 00000000..a02c69ec --- /dev/null +++ b/tests/php_exceptions_007.phpt @@ -0,0 +1,54 @@ +--TEST-- +Test V8::executeString() : PHP Exception handling (throwed inside magic method) +--SKIPIF-- + +--FILE-- +triggerException(); + } +} + +function execute($code, $flags = V8Js::FLAG_NONE) { + $js = new V8Js(); + $js->output = new stdClass(); + $js->SomeClassInstance = new SomeClass(); + try { + $js->executeString(" + try { + $code + } catch(e) { + PHP.output.result = 'Caught exception at javascript level : ' + e.getMessage(); + } + ", '', $flags); + print($js->output->result.PHP_EOL); + } catch (Exception $e) { + print( "Caught exception at php level : ".$e->getMessage().PHP_EOL); + } +} + +execute("PHP.SomeClassInstance.triggerException();"); +execute("PHP.SomeClassInstance.someMethod(PHP.SomeClassInstance.TriggerMagicMethod);"); +execute("PHP.SomeClassInstance.TriggerMagicMethod;"); +execute("PHP.SomeClassInstance.triggerException();", V8Js::FLAG_PROPAGATE_PHP_EXCEPTIONS); +execute("PHP.SomeClassInstance.someMethod(PHP.SomeClassInstance.TriggerMagicMethod);", V8Js::FLAG_PROPAGATE_PHP_EXCEPTIONS); +execute("PHP.SomeClassInstance.TriggerMagicMethod;", V8Js::FLAG_PROPAGATE_PHP_EXCEPTIONS); +?> +===EOF=== +--EXPECTF-- +Caught exception at php level : Some exception +Caught exception at php level : Some exception +Caught exception at php level : Some exception +Caught exception at javascript level : Some exception +Caught exception at javascript level : Some exception +Caught exception at javascript level : Some exception +===EOF=== From c59982f129e601112ba371516e841159e1728f96 Mon Sep 17 00:00:00 2001 From: Christiano Becker Date: Tue, 21 Feb 2023 08:55:15 -0300 Subject: [PATCH 27/64] Added toJSON Symbol that calls jsonSerialize if the php class exported implements JsonSerializable interface --- v8js_object_export.cc | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 7b287a1f..2c67f4cb 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -1007,6 +1007,34 @@ static v8::MaybeLocal v8js_wrap_object(v8::Isolate *isolate, zend_cl v8::MaybeLocal newobj = constr->NewInstance(v8_context, 1, &external); + bool has_json_serializable = false; + for (unsigned int i = 0; i < ce->num_interfaces; i ++) { + if (strcmp (ZSTR_VAL(ce->interfaces[i]->name), "JsonSerializable") == 0) { + has_json_serializable = true; + break; + } + } + + if (has_json_serializable) { + void *ptr; + zend_string *key; + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, key, ptr) { + zend_function *method_ptr = reinterpret_cast(ptr); + if (strcmp(ZSTR_VAL(method_ptr->common.function_name), "jsonSerialize") == 0) { + v8::Local method_name = V8JS_SYM("toJSON"); + v8::Local ft; + + ft = v8::FunctionTemplate::New(isolate, v8js_php_callback, + v8::External::New((isolate), method_ptr)); + + v8js_function_tmpl_t *persistent_ft = &ctx->method_tmpls[std::make_pair(ce, method_ptr)]; + persistent_ft->Reset(isolate, ft); + + newobj.ToLocalChecked()->CreateDataProperty(v8_context, method_name, ft->GetFunction(v8_context).ToLocalChecked()); + } + } ZEND_HASH_FOREACH_END(); + } + if (ce == zend_ce_closure && !newobj.IsEmpty()) { // free uncached function template when object is freed ctx->weak_closures[persist_tpl_].Reset(isolate, newobj.ToLocalChecked()); From 9cb0400f90974fdc0e19d0059b251d9c9a5a4c40 Mon Sep 17 00:00:00 2001 From: Christiano Becker Date: Tue, 21 Feb 2023 09:00:32 -0300 Subject: [PATCH 28/64] Added tests/tojson_001.phpt --- tests/tojson_001.phpt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/tojson_001.phpt diff --git a/tests/tojson_001.phpt b/tests/tojson_001.phpt new file mode 100644 index 00000000..f87474e7 --- /dev/null +++ b/tests/tojson_001.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test V8::executeString() : redirects toJSON() to jsonSerialize +--SKIPIF-- + +--FILE-- +foo = new Foo; +$v8->executeString('var_dump(JSON.stringify(PHP.foo));'); +?> +===EOF=== +--EXPECTF-- +string(13) "["foo","bar"]" +===EOF=== \ No newline at end of file From 34d944a9f5866925574fdcaef576e0bef35cecce Mon Sep 17 00:00:00 2001 From: Christiano Becker Date: Wed, 22 Feb 2023 16:13:13 -0300 Subject: [PATCH 29/64] toJSON: use zend_hash_find_ptr_lc instead of ZEND_HASH_FOREACH_STR_KEY_PTR --- v8js_object_export.cc | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 2c67f4cb..7a40800f 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -1016,23 +1016,23 @@ static v8::MaybeLocal v8js_wrap_object(v8::Isolate *isolate, zend_cl } if (has_json_serializable) { - void *ptr; - zend_string *key; - ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, key, ptr) { - zend_function *method_ptr = reinterpret_cast(ptr); - if (strcmp(ZSTR_VAL(method_ptr->common.function_name), "jsonSerialize") == 0) { - v8::Local method_name = V8JS_SYM("toJSON"); - v8::Local ft; - - ft = v8::FunctionTemplate::New(isolate, v8js_php_callback, - v8::External::New((isolate), method_ptr)); - - v8js_function_tmpl_t *persistent_ft = &ctx->method_tmpls[std::make_pair(ce, method_ptr)]; - persistent_ft->Reset(isolate, ft); - - newobj.ToLocalChecked()->CreateDataProperty(v8_context, method_name, ft->GetFunction(v8_context).ToLocalChecked()); - } - } ZEND_HASH_FOREACH_END(); + zend_string *jsonserialize_str = zend_string_init + ("jsonSerialize", sizeof("jsonSerialize") - 1, 0); + zend_function *jsonserialize_method_ptr = reinterpret_cast + (zend_hash_find_ptr_lc(&ce->function_table, jsonserialize_str)); + if (jsonserialize_method_ptr && + jsonserialize_method_ptr->common.fn_flags & ZEND_ACC_PUBLIC) { + v8::Local method_name = V8JS_SYM("toJSON"); + v8::Local ft; + + ft = v8::FunctionTemplate::New(isolate, v8js_php_callback, + v8::External::New((isolate), jsonserialize_method_ptr)); + + v8js_function_tmpl_t *persistent_ft = &ctx->method_tmpls[std::make_pair(ce, jsonserialize_method_ptr)]; + persistent_ft->Reset(isolate, ft); + + newobj.ToLocalChecked()->CreateDataProperty(v8_context, method_name, ft->GetFunction(v8_context).ToLocalChecked()); + } } if (ce == zend_ce_closure && !newobj.IsEmpty()) { From f696867dc2e0e8d745a72019e49b0f0e7ac666c7 Mon Sep 17 00:00:00 2001 From: Christiano Becker Date: Wed, 22 Feb 2023 16:16:22 -0300 Subject: [PATCH 30/64] Fixed tab-based indentation --- v8js_object_export.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 7a40800f..44ff0c52 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -1008,14 +1008,14 @@ static v8::MaybeLocal v8js_wrap_object(v8::Isolate *isolate, zend_cl v8::MaybeLocal newobj = constr->NewInstance(v8_context, 1, &external); bool has_json_serializable = false; - for (unsigned int i = 0; i < ce->num_interfaces; i ++) { - if (strcmp (ZSTR_VAL(ce->interfaces[i]->name), "JsonSerializable") == 0) { - has_json_serializable = true; - break; - } - } - - if (has_json_serializable) { + for (unsigned int i = 0; i < ce->num_interfaces; i ++) { + if (strcmp (ZSTR_VAL(ce->interfaces[i]->name), "JsonSerializable") == 0) { + has_json_serializable = true; + break; + } + } + + if (has_json_serializable) { zend_string *jsonserialize_str = zend_string_init ("jsonSerialize", sizeof("jsonSerialize") - 1, 0); zend_function *jsonserialize_method_ptr = reinterpret_cast @@ -1033,7 +1033,7 @@ static v8::MaybeLocal v8js_wrap_object(v8::Isolate *isolate, zend_cl newobj.ToLocalChecked()->CreateDataProperty(v8_context, method_name, ft->GetFunction(v8_context).ToLocalChecked()); } - } + } if (ce == zend_ce_closure && !newobj.IsEmpty()) { // free uncached function template when object is freed From 752cbdb8ac6ab44235a27473eb68973d9d9a168d Mon Sep 17 00:00:00 2001 From: Christiano Becker Date: Mon, 27 Feb 2023 08:03:22 -0300 Subject: [PATCH 31/64] Since ArrayBuffer has InternalFieldCount set to 2 by default, added !isArrayBuffer() and !isArrayBufferView() to ensure that is PHP object --- v8js_convert.cc | 2 +- v8js_object_export.cc | 3 ++- v8js_v8.cc | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/v8js_convert.cc b/v8js_convert.cc index d6fe832d..1c5b149f 100644 --- a/v8js_convert.cc +++ b/v8js_convert.cc @@ -260,7 +260,7 @@ int v8js_to_zval(v8::Local jsValue, zval *return_value, int flags, v8 } // if this is a wrapped PHP object, then just unwrap it. - if (self->InternalFieldCount() == 2) { + if ((self->InternalFieldCount() == 2) && !jsValue->IsArrayBufferView() && !jsValue->IsArrayBuffer()) { zend_object *object = reinterpret_cast(self->GetAlignedPointerFromInternalField(1)); zval zval_object; ZVAL_OBJ(&zval_object, object); diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 7b287a1f..298ff65b 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -141,7 +141,8 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, c { v8::Local param_object; - if (info[i]->IsObject() && info[i]->ToObject(v8_context).ToLocal(¶m_object) && param_object->InternalFieldCount() == 2) + if (info[i]->IsObject() && info[i]->ToObject(v8_context).ToLocal(¶m_object) && param_object->InternalFieldCount() == 2 + && !param_object->IsArrayBufferView() && !param_object->IsArrayBuffer()) { /* This is a PHP object, passed to JS and back. */ zend_object *object = reinterpret_cast(param_object->GetAlignedPointerFromInternalField(1)); diff --git a/v8js_v8.cc b/v8js_v8.cc index 58562122..467f201b 100644 --- a/v8js_v8.cc +++ b/v8js_v8.cc @@ -325,7 +325,8 @@ int v8js_get_properties_hash(v8::Local jsValue, HashTable *retval, in ZVAL_UNDEF(&value); v8::Local jsValObject; - if (jsVal->IsObject() && jsVal->ToObject(v8_context).ToLocal(&jsValObject) && jsValObject->InternalFieldCount() == 2) { + if (jsVal->IsObject() && !jsVal->IsArrayBufferView() && !jsVal->IsArrayBuffer() + && jsVal->ToObject(v8_context).ToLocal(&jsValObject) && (jsValObject->InternalFieldCount() == 2)) { /* This is a PHP object, passed to JS and back. */ zend_object *object = reinterpret_cast(jsValObject->GetAlignedPointerFromInternalField(1)); ZVAL_OBJ(&value, object); From 7dcff4f3c92a4e7298bd5d6bba5a5891f27ad9c8 Mon Sep 17 00:00:00 2001 From: Mark Grainger Date: Thu, 15 Feb 2024 08:50:27 +0000 Subject: [PATCH 32/64] Fixed compile issue against V8 12 --- v8js_variables.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v8js_variables.cc b/v8js_variables.cc index f546f797..2cb91624 100644 --- a/v8js_variables.cc +++ b/v8js_variables.cc @@ -80,7 +80,7 @@ void v8js_register_accessors(std::vector *accessor_list, v8: ctx->isolate = isolate; /* Set the variable fetch callback for given symbol on named property */ - php_obj->SetAccessor(V8JS_STRL(ZSTR_VAL(property_name), static_cast(ZSTR_LEN(property_name))), v8js_fetch_php_variable, NULL, v8::External::New(isolate, ctx), v8::PROHIBITS_OVERWRITING, v8::ReadOnly); + php_obj->SetAccessor(V8JS_STRL(ZSTR_VAL(property_name), static_cast(ZSTR_LEN(property_name))), v8js_fetch_php_variable, NULL, v8::External::New(isolate, ctx), v8::DEFAULT, v8::ReadOnly); /* record the context so we can free it later */ accessor_list->push_back(ctx); From 7aa2ffb9796b2f2fc6e6238beca9b75443f1fbca Mon Sep 17 00:00:00 2001 From: Julian Krzefski Date: Fri, 23 Aug 2024 17:21:43 +0200 Subject: [PATCH 33/64] Update link to V8 version overview in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 03f1bf4f..20fcaba1 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Minimum requirements V8 releases are published rather quickly and the V8 team usually provides security support for the version line shipped with the Chrome browser (stable channel) and newer (only). - For a version overview see https://omahaproxy.appspot.com/. + For a version overview see https://chromiumdash.appspot.com/branches. - PHP 8.0.0+ From c01f24f5e45a9a14c0a668fd79dc48136e3c65d9 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 7 Sep 2024 16:05:07 +0200 Subject: [PATCH 34/64] Split include and lib directory variables Solves #522 Solves #529 --- config.m4 | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/config.m4 b/config.m4 index 9cb3b16c..b42a0ea4 100644 --- a/config.m4 +++ b/config.m4 @@ -3,8 +3,8 @@ PHP_ARG_WITH(v8js, for V8 Javascript Engine, if test "$PHP_V8JS" != "no"; then SEARCH_PATH="/usr/local /usr" - SEARCH_FOR="$PHP_LIBDIR/libv8.$SHLIB_SUFFIX_NAME" - + SEARCH_FOR="libv8.$SHLIB_SUFFIX_NAME" + if test -r $PHP_V8JS/$SEARCH_FOR; then case $host_os in darwin* ) @@ -14,26 +14,28 @@ if test "$PHP_V8JS" != "no"; then LDFLAGS="$LDFLAGS -Wl,--rpath=$PHP_V8JS/$PHP_LIBDIR" ;; esac - V8_DIR=$PHP_V8JS + V8_INCLUDE_DIR=$PHP_V8JS/include/v8 + V8_LIBRARY_DIR=$PHP_V8JS/$PHP_LIBDIR else AC_MSG_CHECKING([for V8 files in default path]) for i in $SEARCH_PATH ; do - if test -r $i/$SEARCH_FOR; then - V8_DIR=$i + if test -r $i/$PHP_LIBDIR/$SEARCH_FOR; then + V8_INCLUDE_DIR=$i/include/v8 + V8_LIBRARY_DIR=$i/$PHP_LIBDIR AC_MSG_RESULT(found in $i) fi done fi - AC_DEFINE_UNQUOTED([PHP_V8_EXEC_PATH], "$V8_DIR/$SEARCH_FOR", [Full path to libv8 library file]) + AC_DEFINE_UNQUOTED([PHP_V8_EXEC_PATH], "$V8_LIBRARY_DIR/$SEARCH_FOR", [Full path to libv8 library file]) - if test -z "$V8_DIR"; then + if test -z "$V8_INCLUDE_DIR" || test -z "$V8_LIBRARY_DIR"; then AC_MSG_RESULT([not found]) AC_MSG_ERROR([Please reinstall the v8 distribution]) fi - PHP_ADD_INCLUDE($V8_DIR/include) - PHP_ADD_LIBRARY_WITH_PATH(v8, $V8_DIR/$PHP_LIBDIR, V8JS_SHARED_LIBADD) + PHP_ADD_INCLUDE($V8_INCLUDE_DIR) + PHP_ADD_LIBRARY_WITH_PATH(v8, $V8_LIBRARY_DIR, V8JS_SHARED_LIBADD) PHP_SUBST(V8JS_SHARED_LIBADD) PHP_REQUIRE_CXX() @@ -89,8 +91,8 @@ if test "$PHP_V8JS" != "no"; then AC_LANG_PUSH([C++]) - CPPFLAGS="$CPPFLAGS -I$V8_DIR/include -std=$ac_cv_v8_cstd" - LDFLAGS="$LDFLAGS -L$V8_DIR/$PHP_LIBDIR" + CPPFLAGS="$CPPFLAGS -I$V8_INCLUDE_DIR -std=$ac_cv_v8_cstd" + LDFLAGS="$LDFLAGS -L$V8_LIBRARY_DIR" AC_MSG_CHECKING([for libv8_libplatform]) AC_DEFUN([V8_CHECK_LINK], [ @@ -161,7 +163,7 @@ int main () AC_MSG_CHECKING([for $1]) blob_found=0 - for i in "$V8_DIR/$PHP_LIBDIR" "$V8_DIR/share/v8"; do + for i in "$V8_LIBRARY_DIR" "$V8_INCLUDE_DIR/../share/v8"; do if test -r "$i/$1"; then AC_MSG_RESULT([found ($i/$1)]) AC_DEFINE_UNQUOTED([$2], "$i/$1", [Full path to $1 file]) @@ -219,7 +221,7 @@ int main () AC_DEFINE([V8_DEPRECATION_WARNINGS], [1], [Enable compiler warnings when using V8_DEPRECATED apis.]) - PHP_ADD_INCLUDE($V8_DIR) + PHP_ADD_INCLUDE($V8_INCLUDE_DIR) PHP_NEW_EXTENSION(v8js, [ \ v8js_array_access.cc \ v8js_class.cc \ From be6e1a809af25f9cc1fb8741878606852d4e58dd Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 7 Sep 2024 16:08:04 +0200 Subject: [PATCH 35/64] Add opinionated checks for installations on debian 12 and different architectures --- config.m4 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config.m4 b/config.m4 index b42a0ea4..3cad7b02 100644 --- a/config.m4 +++ b/config.m4 @@ -18,12 +18,20 @@ if test "$PHP_V8JS" != "no"; then V8_LIBRARY_DIR=$PHP_V8JS/$PHP_LIBDIR else AC_MSG_CHECKING([for V8 files in default path]) + ARCH=$(uname -m) + for i in $SEARCH_PATH ; do if test -r $i/$PHP_LIBDIR/$SEARCH_FOR; then V8_INCLUDE_DIR=$i/include/v8 V8_LIBRARY_DIR=$i/$PHP_LIBDIR AC_MSG_RESULT(found in $i) fi + + if test -r $i/$PHP_LIBDIR/$ARCH-linux-gnu/$SEARCH_FOR; then + V8_INCLUDE_DIR=$i/include/v8 + V8_LIBRARY_DIR=$i/$PHP_LIBDIR/$ARCH-linux-gnu + AC_MSG_RESULT(found in $i) + fi done fi From 66d155679bb314e8e123353a7f692192840f8d8e Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 7 Sep 2024 23:43:20 +0200 Subject: [PATCH 36/64] Restructure code so an always false condition is moved to skimming loop --- config.m4 | 56 +++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/config.m4 b/config.m4 index 3cad7b02..21a9b32f 100644 --- a/config.m4 +++ b/config.m4 @@ -5,36 +5,36 @@ if test "$PHP_V8JS" != "no"; then SEARCH_PATH="/usr/local /usr" SEARCH_FOR="libv8.$SHLIB_SUFFIX_NAME" - if test -r $PHP_V8JS/$SEARCH_FOR; then - case $host_os in - darwin* ) - # MacOS does not support --rpath - ;; - * ) - LDFLAGS="$LDFLAGS -Wl,--rpath=$PHP_V8JS/$PHP_LIBDIR" - ;; - esac - V8_INCLUDE_DIR=$PHP_V8JS/include/v8 - V8_LIBRARY_DIR=$PHP_V8JS/$PHP_LIBDIR - else - AC_MSG_CHECKING([for V8 files in default path]) - ARCH=$(uname -m) - - for i in $SEARCH_PATH ; do - if test -r $i/$PHP_LIBDIR/$SEARCH_FOR; then - V8_INCLUDE_DIR=$i/include/v8 - V8_LIBRARY_DIR=$i/$PHP_LIBDIR - AC_MSG_RESULT(found in $i) - fi - - if test -r $i/$PHP_LIBDIR/$ARCH-linux-gnu/$SEARCH_FOR; then - V8_INCLUDE_DIR=$i/include/v8 - V8_LIBRARY_DIR=$i/$PHP_LIBDIR/$ARCH-linux-gnu - AC_MSG_RESULT(found in $i) - fi - done + if test -d "$PHP_V8JS"; then + SEARCH_PATH="$PHP_V8JS $SEARCH_PATH" fi + case $host_os in + darwin* ) + # MacOS does not support --rpath + ;; + * ) + LDFLAGS="$LDFLAGS -Wl,--rpath=$PHP_V8JS/$PHP_LIBDIR" + ;; + esac + + AC_MSG_CHECKING([for V8 files in default path]) + ARCH=$(uname -m) + + for i in $SEARCH_PATH ; do + if test -r $i/$PHP_LIBDIR/$SEARCH_FOR; then + V8_INCLUDE_DIR=$i/include/v8 + V8_LIBRARY_DIR=$i/$PHP_LIBDIR + AC_MSG_RESULT(found in $i) + fi + + if test -r $i/$PHP_LIBDIR/$ARCH-linux-gnu/$SEARCH_FOR; then + V8_INCLUDE_DIR=$i/include/v8 + V8_LIBRARY_DIR=$i/$PHP_LIBDIR/$ARCH-linux-gnu + AC_MSG_RESULT(found in $i) + fi + done + AC_DEFINE_UNQUOTED([PHP_V8_EXEC_PATH], "$V8_LIBRARY_DIR/$SEARCH_FOR", [Full path to libv8 library file]) if test -z "$V8_INCLUDE_DIR" || test -z "$V8_LIBRARY_DIR"; then From 32aa91305dab6ae6c2a4e34efbbaeb2b9276c4bc Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sun, 8 Sep 2024 01:11:00 +0200 Subject: [PATCH 37/64] Allow manual path assignments still match a {lib,include} pattern --- config.m4 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config.m4 b/config.m4 index 21a9b32f..59fd2c93 100644 --- a/config.m4 +++ b/config.m4 @@ -28,11 +28,19 @@ if test "$PHP_V8JS" != "no"; then AC_MSG_RESULT(found in $i) fi + # Debian installations if test -r $i/$PHP_LIBDIR/$ARCH-linux-gnu/$SEARCH_FOR; then V8_INCLUDE_DIR=$i/include/v8 V8_LIBRARY_DIR=$i/$PHP_LIBDIR/$ARCH-linux-gnu AC_MSG_RESULT(found in $i) fi + + # Manual installations + if test -r $i/$PHP_LIBDIR/$SEARCH_FOR && test -r $i/include/libplatform/libplatform.h; then + V8_INCLUDE_DIR=$i/include + V8_LIBRARY_DIR=$i/$PHP_LIBDIR + AC_MSG_RESULT(found in $i) + fi done AC_DEFINE_UNQUOTED([PHP_V8_EXEC_PATH], "$V8_LIBRARY_DIR/$SEARCH_FOR", [Full path to libv8 library file]) From 8edc8b65d8559056f7a30110dabb8ca7b9dff558 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 20 Sep 2024 21:32:27 +0200 Subject: [PATCH 38/64] Add missing include --- v8js_object_export.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 87a88b66..61ba0c95 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -16,6 +16,8 @@ #include "config.h" #endif +#include + #include "php_v8js_macros.h" #include "v8js_array_access.h" #include "v8js_exceptions.h" From 303ab95a90f4b0eb3fec2f6c4e9f3cdbf97fcacf Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 20 Sep 2024 23:23:04 +0200 Subject: [PATCH 39/64] More robust scanning, override SEARCH_PATH by explicitly given dir --- config.m4 | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/config.m4 b/config.m4 index 59fd2c93..eaeffe88 100644 --- a/config.m4 +++ b/config.m4 @@ -6,39 +6,41 @@ if test "$PHP_V8JS" != "no"; then SEARCH_FOR="libv8.$SHLIB_SUFFIX_NAME" if test -d "$PHP_V8JS"; then - SEARCH_PATH="$PHP_V8JS $SEARCH_PATH" + SEARCH_PATH="$PHP_V8JS" + + # set rpath, so library loader picks up libv8 even if it's not on the + # system's library search path + case $host_os in + darwin* ) + # MacOS does not support --rpath + ;; + * ) + LDFLAGS="$LDFLAGS -Wl,--rpath=$PHP_V8JS/$PHP_LIBDIR" + ;; + esac fi - case $host_os in - darwin* ) - # MacOS does not support --rpath - ;; - * ) - LDFLAGS="$LDFLAGS -Wl,--rpath=$PHP_V8JS/$PHP_LIBDIR" - ;; - esac - AC_MSG_CHECKING([for V8 files in default path]) ARCH=$(uname -m) for i in $SEARCH_PATH ; do - if test -r $i/$PHP_LIBDIR/$SEARCH_FOR; then - V8_INCLUDE_DIR=$i/include/v8 - V8_LIBRARY_DIR=$i/$PHP_LIBDIR + if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/v8/v8.h"; then + V8_INCLUDE_DIR="$i/include/v8" + V8_LIBRARY_DIR="$i/$PHP_LIBDIR" AC_MSG_RESULT(found in $i) fi # Debian installations - if test -r $i/$PHP_LIBDIR/$ARCH-linux-gnu/$SEARCH_FOR; then - V8_INCLUDE_DIR=$i/include/v8 - V8_LIBRARY_DIR=$i/$PHP_LIBDIR/$ARCH-linux-gnu + if test -r "$i/$PHP_LIBDIR/$ARCH-linux-gnu/$SEARCH_FOR"; then + V8_INCLUDE_DIR="$i/include/v8" + V8_LIBRARY_DIR="$i/$PHP_LIBDIR/$ARCH-linux-gnu" AC_MSG_RESULT(found in $i) fi # Manual installations - if test -r $i/$PHP_LIBDIR/$SEARCH_FOR && test -r $i/include/libplatform/libplatform.h; then - V8_INCLUDE_DIR=$i/include - V8_LIBRARY_DIR=$i/$PHP_LIBDIR + if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/libplatform/libplatform.h"; then + V8_INCLUDE_DIR="$i/include" + V8_LIBRARY_DIR="$i/$PHP_LIBDIR" AC_MSG_RESULT(found in $i) fi done From ff1b080d2c185a50b7e372de7233d8df41995c13 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 20 Sep 2024 23:27:35 +0200 Subject: [PATCH 40/64] also check for c++20 standard (and drop c++1y which is too old anyways) --- config.m4 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config.m4 b/config.m4 index 59fd2c93..9d951f71 100644 --- a/config.m4 +++ b/config.m4 @@ -57,14 +57,14 @@ if test "$PHP_V8JS" != "no"; then AC_CACHE_CHECK(for C standard version, ac_cv_v8_cstd, [ - ac_cv_v8_cstd="c++17" + ac_cv_v8_cstd="c++20" old_CPPFLAGS=$CPPFLAGS AC_LANG_PUSH([C++]) CPPFLAGS="-std="$ac_cv_v8_cstd AC_RUN_IFELSE([AC_LANG_SOURCE([[int main() { return 0; }]])],[],[ - ac_cv_v8_cstd="c++14" + ac_cv_v8_cstd="c++17" CPPFLAGS="-std="$ac_cv_v8_cstd - AC_RUN_IFELSE([AC_LANG_SOURCE([[int main() { return 0; }]])],[],[ ac_cv_v8_cstd="c++1y" ],[]) + AC_RUN_IFELSE([AC_LANG_SOURCE([[int main() { return 0; }]])],[],[ ac_cv_v8_cstd="c++14" ],[]) ],[]) AC_LANG_POP([C++]) CPPFLAGS=$old_CPPFLAGS From d1af93e544ac3cb949f353bd135ab0ac222380e8 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 21 Sep 2024 00:15:10 +0200 Subject: [PATCH 41/64] update build instructions --- README.Linux.md | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/README.Linux.md b/README.Linux.md index 3294f837..6bc69625 100644 --- a/README.Linux.md +++ b/README.Linux.md @@ -3,16 +3,18 @@ V8Js on GNU/Linux Installation of V8Js on GNU/Linux is pretty much straight forward. -The biggest hurdle actually is that you need a rather new V8 library. -However many distributions still ship the rusty version 3.14, published -years ago. +First you need to decide if you can go with a V8 library that is +shipped with your GNU/Linux distribution or whether you would want +to compile V8 on your own. -This means that you usually need to compile V8 on your own before -you can start to compile & install V8Js itself. +Many GNU/Linux distributions, for example Debian/Ubuntu, have +recent V8 library versions installable, that are ready to be used. +In order to go with these, just `sudo apt-get install libv8-dev` +(or similar, as it fits your distribution). -It is recommended to install the V8 version for V8Js off your system's -load path, so it doesn't interfere with the V8 library shipped with your -system's distribution. +If you compile V8 on your own, it is recommended to install the V8 +version for V8Js off your system's load path, so it doesn't interfere +with the V8 library shipped with your system's distribution. Snapshots @@ -51,12 +53,34 @@ then you `CPPFLAGS="-DV8_COMPRESS_POINTERS"` to the `./configure` call. +Sandbox +------- + +V8 has optional sandbox support. You need to compile php-v8js with matching +configurations. If your V8 library was called with sandbox support, you +need to pass the `-DV8_ENABLE_SANDBOX` flag to the configure call. + +By default V8 currently enables this feature. +Many GNU/Linux distributions currently seem to have sandbox feature turned +off however. + +If you configure it the wrong way round, you'll get runtime errors like this, +as soon as php-v8js tries to initialize V8: + +``` +Embedder-vs-V8 build configuration mismatch. On embedder side sandbox is DISABLED while on V8 side it's ENABLED. +``` + +In order to compile V8 with sandbox support off, pass `v8_enable_sandbox=false` +to v8gen.py invocation. + + Compile V8 5.6 and newer (using GN) ----------------------------------- ``` # Install required dependencies -sudo apt-get install build-essential curl git python libglib2.0-dev +sudo apt-get install build-essential curl git python3 libglib2.0-dev cd /tmp @@ -69,8 +93,8 @@ fetch v8 cd v8 # (optional) If you'd like to build a certain version: -git checkout 8.0.426.30 -gclient sync +git checkout 12.0.267.36 +gclient sync -D # Setup GN tools/dev/v8gen.py -vv x64.release -- is_component_build=true use_custom_libcxx=false @@ -101,7 +125,7 @@ cd /tmp git clone https://github.com/phpv8/v8js.git cd v8js phpize -./configure --with-v8js=/opt/v8 LDFLAGS="-lstdc++" CPPFLAGS="-DV8_COMPRESS_POINTERS" +./configure --with-v8js=/opt/v8 LDFLAGS="-lstdc++" CPPFLAGS="-DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX" make make test sudo make install From cba24df614bdb0c0da1f29ac453f506799b99838 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 27 Sep 2024 22:54:17 +0200 Subject: [PATCH 42/64] adapt v8 api change, closes #528 --- v8js_variables.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v8js_variables.cc b/v8js_variables.cc index 2cb91624..e64d1222 100644 --- a/v8js_variables.cc +++ b/v8js_variables.cc @@ -80,7 +80,7 @@ void v8js_register_accessors(std::vector *accessor_list, v8: ctx->isolate = isolate; /* Set the variable fetch callback for given symbol on named property */ - php_obj->SetAccessor(V8JS_STRL(ZSTR_VAL(property_name), static_cast(ZSTR_LEN(property_name))), v8js_fetch_php_variable, NULL, v8::External::New(isolate, ctx), v8::DEFAULT, v8::ReadOnly); + php_obj->SetAccessor(V8JS_STRL(ZSTR_VAL(property_name), static_cast(ZSTR_LEN(property_name))), v8js_fetch_php_variable, NULL, v8::External::New(isolate, ctx)); /* record the context so we can free it later */ accessor_list->push_back(ctx); From 73e684f4a8efcb0ecddefea492742acfe448f7cb Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 27 Sep 2024 23:02:48 +0200 Subject: [PATCH 43/64] fix zend_string access issues & user after free in error handling code --- v8js_object_export.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 61ba0c95..eca9ae8a 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -543,7 +543,7 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo& info) if (!info[1]->IsArray()) { error_len = spprintf(&error, 0, "%s::__call expects 2nd parameter to be an array", - ce->name); + ZSTR_VAL(ce->name)); if (error_len > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, @@ -607,14 +607,14 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo& info) // okay, look up the method name and manually invoke it. const zend_object_handlers *h = object->handlers; zend_function *method_ptr = h->get_method(&object, method_name, NULL); - zend_string_release(method_name); if (method_ptr == NULL || (method_ptr->common.fn_flags & ZEND_ACC_PUBLIC) == 0 || (method_ptr->common.fn_flags & (ZEND_ACC_CTOR|ZEND_ACC_DTOR)) != 0) { error_len = spprintf(&error, 0, "%s::__call to %s method %s", ZSTR_VAL(ce->name), - (method_ptr == NULL) ? "undefined" : "non-public", method_name); + (method_ptr == NULL) ? "undefined" : "non-public", ZSTR_VAL(method_name)); + zend_string_release(method_name); if (error_len > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, @@ -629,6 +629,8 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo& info) return; } + zend_string_release(method_name); + v8::Local tmpl = v8::Local::New (isolate, *reinterpret_cast(self->GetAlignedPointerFromInternalField(0))); From 888684b4832109d2618b23d8fee7fcbba844a234 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Fri, 27 Sep 2024 23:27:59 +0200 Subject: [PATCH 44/64] use v8::Global instead of v8::Persistent --- v8js_class.cc | 20 ++++++++++---------- v8js_class.h | 12 ++++++------ v8js_methods.cc | 2 +- v8js_v8object_class.cc | 4 ++-- v8js_v8object_class.h | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/v8js_class.cc b/v8js_class.cc index 5b5ac513..26a5a296 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -53,7 +53,7 @@ extern const zend_function_entry v8js_methods[]; typedef struct _v8js_script { char *name; v8js_ctx *ctx; - v8::Persistent> *script; + v8::Global *script; } v8js_script; static void v8js_script_free(v8js_script *res); @@ -95,11 +95,11 @@ static void v8js_free_storage(zend_object *object) /* {{{ */ } c->object_name.Reset(); - c->object_name.~Persistent(); + c->object_name.~Global(); c->global_template.Reset(); - c->global_template.~Persistent(); + c->global_template.~Global(); c->array_tmpl.Reset(); - c->array_tmpl.~Persistent(); + c->array_tmpl.~Global(); /* Clear persistent call_impl & method_tmpls templates */ for (std::map::iterator it = c->call_impls.begin(); @@ -133,7 +133,7 @@ static void v8js_free_storage(zend_object *object) /* {{{ */ if (!c->context.IsEmpty()) { c->context.Reset(); } - c->context.~Persistent(); + c->context.~Global(); /* Dispose yet undisposed weak refs */ for (std::map::iterator it = c->weak_objects.begin(); @@ -208,10 +208,10 @@ static zend_object* v8js_new(zend_class_entry *ce) /* {{{ */ c->std.handlers = &v8js_object_handlers; - new(&c->object_name) v8::Persistent(); - new(&c->context) v8::Persistent(); - new(&c->global_template) v8::Persistent(); - new(&c->array_tmpl) v8::Persistent(); + new(&c->object_name) v8::Global(); + new(&c->context) v8::Global(); + new(&c->global_template) v8::Global(); + new(&c->array_tmpl) v8::Global(); new(&c->modules_stack) std::vector(); new(&c->modules_loaded) std::map; @@ -541,7 +541,7 @@ static void v8js_compile_script(zval *this_ptr, const zend_string *str, const ze return; } res = (v8js_script *)emalloc(sizeof(v8js_script)); - res->script = new v8::Persistent>(c->isolate, script.ToLocalChecked()); + res->script = new v8::Global(c->isolate, script.ToLocalChecked()); v8::String::Utf8Value _sname(isolate, sname); res->name = estrndup(ToCString(_sname), _sname.length()); diff --git a/v8js_class.h b/v8js_class.h index c69514de..cb89824e 100644 --- a/v8js_class.h +++ b/v8js_class.h @@ -17,10 +17,10 @@ /* Abbreviate long type names */ -typedef v8::Persistent > v8js_function_tmpl_t; -typedef v8::Persistent > v8js_object_tmpl_t; -typedef v8::Persistent > v8js_persistent_obj_t; -typedef v8::Persistent > v8js_persistent_value_t; +typedef v8::Global v8js_function_tmpl_t; +typedef v8::Global v8js_object_tmpl_t; +typedef v8::Global v8js_persistent_obj_t; +typedef v8::Global v8js_persistent_value_t; /* Forward declarations */ struct v8js_v8object; @@ -35,8 +35,8 @@ struct cmp_str { /* {{{ Context container */ struct v8js_ctx { - v8::Persistent object_name; - v8::Persistent context; + v8::Global object_name; + v8::Global context; int in_execution; v8::Isolate *isolate; diff --git a/v8js_methods.cc b/v8js_methods.cc index 63a28db8..1f69a7b8 100644 --- a/v8js_methods.cc +++ b/v8js_methods.cc @@ -405,7 +405,7 @@ V8JS_METHOD(require) // If we have already loaded and cached this module then use it if (c->modules_loaded.count(normalised_module_id) > 0) { - v8::Persistent newobj; + v8::Global newobj; newobj.Reset(isolate, c->modules_loaded[normalised_module_id]); // TODO store v8::Global in c->modules_loaded directly!? diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc index a27fd63d..b0e8007c 100644 --- a/v8js_v8object_class.cc +++ b/v8js_v8object_class.cc @@ -537,7 +537,7 @@ static zend_object *v8js_v8object_new(zend_class_entry *ce) /* {{{ */ zend_object_std_init(&c->std, ce); c->std.handlers = &v8js_v8object_handlers; - new (&c->v8obj) v8::Persistent(); + new (&c->v8obj) v8::Global(); return &c->std; } @@ -624,7 +624,7 @@ static zend_object *v8js_v8generator_new(zend_class_entry *ce) /* {{{ */ zend_object_std_init(&c->v8obj.std, ce); c->v8obj.std.handlers = &v8js_v8generator_handlers; - new (&c->v8obj.v8obj) v8::Persistent(); + new (&c->v8obj.v8obj) v8::Global(); return &c->v8obj.std; } diff --git a/v8js_v8object_class.h b/v8js_v8object_class.h index 0bb7ed0e..f7c39a83 100644 --- a/v8js_v8object_class.h +++ b/v8js_v8object_class.h @@ -16,7 +16,7 @@ /* {{{ Object container */ struct v8js_v8object { - v8::Persistent v8obj; + v8::Global v8obj; int flags; struct v8js_ctx *ctx; HashTable *properties; From d0c4a3614d7ea9081d0a62473b3f02187630bc99 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 28 Sep 2024 00:20:44 +0200 Subject: [PATCH 45/64] adapt V8 12.8 interceptor signatures --- v8js_array_access.cc | 36 ++++++++++++++++------------ v8js_array_access.h | 12 +++++----- v8js_class.cc | 2 +- v8js_methods.cc | 2 +- v8js_object_export.cc | 56 ++++++++++++++++++++++++++----------------- v8js_object_export.h | 8 +++---- v8js_variables.cc | 4 ++-- 7 files changed, 68 insertions(+), 52 deletions(-) diff --git a/v8js_array_access.cc b/v8js_array_access.cc index c9ca933f..e9fee48e 100644 --- a/v8js_array_access.cc +++ b/v8js_array_access.cc @@ -56,7 +56,7 @@ static zval v8js_array_access_dispatch(zend_object *object, const char *method_n -void v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ +v8::Intercepted v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); v8::Local self = info.Holder(); @@ -70,12 +70,17 @@ void v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo ret_value = zval_to_v8js(&php_value, isolate); zval_ptr_dtor(&php_value); - info.GetReturnValue().Set(ret_value); + if (ret_value.IsEmpty()) { + return v8::Intercepted::kNo; + } else { + info.GetReturnValue().Set(ret_value); + return v8::Intercepted::kYes; + } } /* }}} */ -void v8js_array_access_setter(uint32_t index, v8::Local value, - const v8::PropertyCallbackInfo& info) /* {{{ */ +v8::Intercepted v8js_array_access_setter(uint32_t index, v8::Local value, + const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); v8::Local self = info.Holder(); @@ -86,20 +91,16 @@ void v8js_array_access_setter(uint32_t index, v8::Local value, ZVAL_UNDEF(&zvalue); if (v8js_to_zval(value, &zvalue, 0, isolate) != SUCCESS) { - info.GetReturnValue().Set(v8::Local()); - return; + return v8::Intercepted::kNo; } zval php_value = v8js_array_access_dispatch(object, "offsetSet", 2, index, zvalue); zval_ptr_dtor(&php_value); - /* simply pass back the value to tell we intercepted the call - * as the offsetSet function returns void. */ - info.GetReturnValue().Set(value); - /* if PHP wanted to hold on to this value, zend_call_function would * have bumped the refcount. */ zval_ptr_dtor(&zvalue); + return v8::Intercepted::kYes; } /* }}} */ @@ -159,7 +160,7 @@ static void v8js_array_access_length(v8::Local property, const v8::P } /* }}} */ -void v8js_array_access_deleter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ +v8::Intercepted v8js_array_access_deleter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); v8::Local self = info.Holder(); @@ -173,10 +174,11 @@ void v8js_array_access_deleter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ +v8::Intercepted v8js_array_access_query(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); v8::Local self = info.Holder(); @@ -187,7 +189,10 @@ void v8js_array_access_query(uint32_t index, const v8::PropertyCallbackInfo& inf -void v8js_array_access_named_getter(v8::Local property_name, const v8::PropertyCallbackInfo &info) /* {{{ */ +v8::Intercepted v8js_array_access_named_getter(v8::Local property_name, const v8::PropertyCallbackInfo &info) /* {{{ */ { v8::Local property = v8::Local::Cast(property_name); v8::Isolate *isolate = info.GetIsolate(); @@ -226,10 +231,10 @@ void v8js_array_access_named_getter(v8::Local property_name, const v8: if(strcmp(name, "length") == 0) { v8js_array_access_length(property, info); - return; + return v8::Intercepted::kYes; } - v8::Local ret_value = v8js_named_property_callback(property, info, V8JS_PROP_GETTER); + v8::Local ret_value = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_GETTER); if(ret_value.IsEmpty()) { v8::Local arr = v8::Array::New(isolate); @@ -250,6 +255,7 @@ void v8js_array_access_named_getter(v8::Local property_name, const v8: } info.GetReturnValue().Set(ret_value); + return v8::Intercepted::kYes; } /* }}} */ diff --git a/v8js_array_access.h b/v8js_array_access.h index 283e1cb4..822ed74c 100644 --- a/v8js_array_access.h +++ b/v8js_array_access.h @@ -14,18 +14,18 @@ #define V8JS_ARRAY_ACCESS_H /* Indexed Property Handlers */ -void v8js_array_access_getter(uint32_t index, - const v8::PropertyCallbackInfo& info); -void v8js_array_access_setter(uint32_t index, v8::Local value, +v8::Intercepted v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo& info); +v8::Intercepted v8js_array_access_setter(uint32_t index, v8::Local value, + const v8::PropertyCallbackInfo& info); void v8js_array_access_enumerator(const v8::PropertyCallbackInfo& info); -void v8js_array_access_deleter(uint32_t index, +v8::Intercepted v8js_array_access_deleter(uint32_t index, const v8::PropertyCallbackInfo& info); -void v8js_array_access_query(uint32_t index, +v8::Intercepted v8js_array_access_query(uint32_t index, const v8::PropertyCallbackInfo& info); /* Named Property Handlers */ -void v8js_array_access_named_getter(v8::Local property, +v8::Intercepted v8js_array_access_named_getter(v8::Local property, const v8::PropertyCallbackInfo &info); #endif /* V8JS_ARRAY_ACCESS_H */ diff --git a/v8js_class.cc b/v8js_class.cc index 26a5a296..66fe565c 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -524,7 +524,7 @@ static void v8js_compile_script(zval *this_ptr, const zend_string *str, const ze v8::Local sname = identifier ? V8JS_ZSTR(identifier) : V8JS_SYM("V8Js::compileString()"); - v8::ScriptOrigin origin(isolate, sname); + v8::ScriptOrigin origin(sname); if (ZSTR_LEN(str) > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, diff --git a/v8js_methods.cc b/v8js_methods.cc index 1f69a7b8..f888eb18 100644 --- a/v8js_methods.cc +++ b/v8js_methods.cc @@ -502,7 +502,7 @@ V8JS_METHOD(require) // Set script identifier v8::Local sname = V8JS_STR(normalised_module_id); - v8::ScriptOrigin origin(isolate, sname); + v8::ScriptOrigin origin(sname); if (Z_STRLEN(module_code) > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, diff --git a/v8js_object_export.cc b/v8js_object_export.cc index eca9ae8a..e2b2c886 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -648,12 +648,10 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo& info) /* }}} */ /* This method handles named property and method get/set/query/delete. */ -template -v8::Local v8js_named_property_callback(v8::Local property_name, const v8::PropertyCallbackInfo &info, property_op_t callback_type, v8::Local set_value) /* {{{ */ +v8::Local v8js_named_property_callback(v8::Isolate *isolate, v8::Local self, v8::Local property_name, property_op_t callback_type, v8::Local set_value) /* {{{ */ { v8::Local property = v8::Local::Cast(property_name); - v8::Isolate *isolate = info.GetIsolate(); v8::Local v8_context = isolate->GetEnteredOrMicrotaskContext(); v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0); v8::String::Utf8Value cstr(isolate, property); @@ -662,7 +660,6 @@ v8::Local v8js_named_property_callback(v8::Local property_n char *lower = estrndup(name, name_len); zend_string *method_name; - v8::Local self = info.Holder(); v8::Local ret_value; v8::Local cb; @@ -860,44 +857,58 @@ v8::Local v8js_named_property_callback(v8::Local property_n } /* }}} */ -static void v8js_named_property_getter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ +static v8::Intercepted v8js_named_property_getter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ { - info.GetReturnValue().Set(v8js_named_property_callback(property, info, V8JS_PROP_GETTER)); + v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_GETTER); + + if (r.IsEmpty()) { + return v8::Intercepted::kNo; + } else { + info.GetReturnValue().Set(r); + return v8::Intercepted::kYes; + } } /* }}} */ -static void v8js_named_property_setter(v8::Local property, v8::Local value, const v8::PropertyCallbackInfo &info) /* {{{ */ +static v8::Intercepted v8js_named_property_setter(v8::Local property, v8::Local value, const v8::PropertyCallbackInfo &info) /* {{{ */ { - info.GetReturnValue().Set(v8js_named_property_callback(property, info, V8JS_PROP_SETTER, value)); + v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_SETTER, value); + return r.IsEmpty() ? v8::Intercepted::kNo : v8::Intercepted::kYes; } /* }}} */ -static void v8js_named_property_query(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ +static v8::Intercepted v8js_named_property_query(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ { - v8::Local r = v8js_named_property_callback(property, info, V8JS_PROP_QUERY); + v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_QUERY); if (r.IsEmpty()) { - return; + return v8::Intercepted::kNo; } v8::Isolate *isolate = info.GetIsolate(); v8::MaybeLocal value = r->ToInteger(isolate->GetEnteredOrMicrotaskContext()); - if (!value.IsEmpty()) { + if (value.IsEmpty()) { + return v8::Intercepted::kNo; + } else { info.GetReturnValue().Set(value.ToLocalChecked()); + return v8::Intercepted::kYes; } } /* }}} */ -static void v8js_named_property_deleter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ +static v8::Intercepted v8js_named_property_deleter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ { - v8::Local r = v8js_named_property_callback(property, info, V8JS_PROP_DELETER); + v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_DELETER); if (r.IsEmpty()) { - return; + return v8::Intercepted::kNo; } v8::Isolate *isolate = info.GetIsolate(); v8::Local value = r->ToBoolean(isolate); - if (!value.IsEmpty()) { + if (value.IsEmpty()) { + return v8::Intercepted::kNo; + } else { info.GetReturnValue().Set(value); + return v8::Intercepted::kYes; } } /* }}} */ @@ -940,7 +951,7 @@ static v8::MaybeLocal v8js_wrap_object(v8::Isolate *isolate, zend_cl /* We'll free persist_tpl_ when template_cache is destroyed */ v8::Local inst_tpl = new_tpl->InstanceTemplate(); - v8::GenericNamedPropertyGetterCallback getter = v8js_named_property_getter; + v8::NamedPropertyGetterCallback getter = v8js_named_property_getter; v8::GenericNamedPropertyEnumeratorCallback enumerator = v8js_named_property_enumerator; /* Check for ArrayAccess object */ @@ -958,11 +969,12 @@ static v8::MaybeLocal v8js_wrap_object(v8::Isolate *isolate, zend_cl } if(has_array_access && has_countable) { - inst_tpl->SetIndexedPropertyHandler(v8js_array_access_getter, - v8js_array_access_setter, - v8js_array_access_query, - v8js_array_access_deleter, - v8js_array_access_enumerator); + inst_tpl->SetHandler( + v8::IndexedPropertyHandlerConfiguration(v8js_array_access_getter, + v8js_array_access_setter, + v8js_array_access_query, + v8js_array_access_deleter, + v8js_array_access_enumerator)); /* Switch to special ArrayAccess getter, which falls back to * v8js_named_property_getter, but possibly bridges the diff --git a/v8js_object_export.h b/v8js_object_export.h index d5625412..8bd47aa7 100644 --- a/v8js_object_export.h +++ b/v8js_object_export.h @@ -25,11 +25,9 @@ typedef enum { V8JS_PROP_DELETER } property_op_t; -template -v8::Local v8js_named_property_callback(v8::Local property, - const v8::PropertyCallbackInfo &info, - property_op_t callback_type, - v8::Local set_value = v8::Local()); +v8::Local v8js_named_property_callback(v8::Isolate *isolate, v8::Local self, + v8::Local property, property_op_t callback_type, + v8::Local set_value = v8::Local()); void v8js_php_callback(const v8::FunctionCallbackInfo& info); diff --git a/v8js_variables.cc b/v8js_variables.cc index e64d1222..5d520710 100644 --- a/v8js_variables.cc +++ b/v8js_variables.cc @@ -25,7 +25,7 @@ extern "C" { #include "zend_exceptions.h" } -static void v8js_fetch_php_variable(v8::Local name, const v8::PropertyCallbackInfo& info) /* {{{ */ +static void v8js_fetch_php_variable(v8::Local name, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Local data = v8::Local::Cast(info.Data()); v8js_accessor_ctx *ctx = static_cast(data->Value()); @@ -80,7 +80,7 @@ void v8js_register_accessors(std::vector *accessor_list, v8: ctx->isolate = isolate; /* Set the variable fetch callback for given symbol on named property */ - php_obj->SetAccessor(V8JS_STRL(ZSTR_VAL(property_name), static_cast(ZSTR_LEN(property_name))), v8js_fetch_php_variable, NULL, v8::External::New(isolate, ctx)); + php_obj->SetNativeDataProperty(V8JS_STRL(ZSTR_VAL(property_name), static_cast(ZSTR_LEN(property_name))), v8js_fetch_php_variable, NULL, v8::External::New(isolate, ctx), v8::PropertyAttribute::ReadOnly); /* record the context so we can free it later */ accessor_list->push_back(ctx); From aef80cd1c1fe420d91d5b1b64bfdf774314befd5 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 28 Sep 2024 02:23:23 +0200 Subject: [PATCH 46/64] Add github workflow to test building and testing the extension --- .github/workflows/build-test.yml | 74 ++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .github/workflows/build-test.yml diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100644 index 00000000..06804aa0 --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,74 @@ +name: Test building extension + +on: + - push + +permissions: + contents: read + +jobs: + build: + strategy: + matrix: + operating-system: + - ubuntu-latest +# - windows-latest +# - macos-latest + php-versions: +# - '8.1' +# - '8.2' + - '8.3' +# - '8.4' + v8-versions: + - 10.9.194 +# - 11.9.172 + - 12.9.203 +# - 13.1.104 + + runs-on: ${{ matrix.operating-system }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: none + + - name: Build v8 ${{ matrix.v8-versions }} + run: | + # Store extra tools somewhere undisturbing + cd "$(mktemp -d)" + + git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git + export PATH=`pwd`/depot_tools:"$PATH" + + fetch v8 + cd v8 + + git checkout ${{ matrix.v8-versions }} + gclient sync -D + + # Setup GN + # Warnings are no errors - @see https://issues.chromium.org/issues/42203398#comment9 + tools/dev/v8gen.py -vv x64.release -- is_component_build=true use_custom_libcxx=false treat_warnings_as_errors=false + + # Build + ninja -C out.gn/x64.release/ + + # Install to /opt/v8/self-built + sudo mkdir -p /opt/v8/self-built/{lib,include} + sudo cp out.gn/x64.release/lib*.so out.gn/x64.release/*_blob.bin out.gn/x64.release/icudtl.dat /opt/v8/self-built/lib/ + sudo cp -R include/* /opt/v8/self-built/include/ + + # Go back to origin + cd "${GITHUB_WORKSPACE}" + + - name: Build extension + run: | + phpize + ./configure --with-v8js=/opt/v8/self-built LDFLAGS="-lstdc++" CPPFLAGS="-DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX" + make + make test From 128495208ab11de03cd3a5e38179a600fe19f354 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 28 Sep 2024 02:42:08 +0200 Subject: [PATCH 47/64] Install google depot tools with an action --- .github/workflows/build-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 06804aa0..067d5627 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -37,14 +37,14 @@ jobs: php-version: ${{ matrix.php-versions }} coverage: none + - name: Setup Google depot tools + uses: newkdev/setup-depot-tools@v1.0.1 + - name: Build v8 ${{ matrix.v8-versions }} run: | # Store extra tools somewhere undisturbing cd "$(mktemp -d)" - git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git - export PATH=`pwd`/depot_tools:"$PATH" - fetch v8 cd v8 From 29e788aa1f6bebe3d2dce2386cfb6c931bd25f06 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 28 Sep 2024 04:22:51 +0200 Subject: [PATCH 48/64] Add build cache for compiling v8 --- .github/workflows/build-test.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 067d5627..1902c690 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -37,10 +37,20 @@ jobs: php-version: ${{ matrix.php-versions }} coverage: none + - name: Restore cache v8 ${{ matrix.v8-versions }} build + id: v8-build-cache + uses: actions/cache/restore@v4 + with: + path: /opt/v8/self-built + key: ${{ runner.os }}-${{ matrix.v8-versions }}-v8-build + - name: Setup Google depot tools + # only needed, when v8 needs to be built + if: steps.v8-build-cache.outputs.cache-hit != 'true' uses: newkdev/setup-depot-tools@v1.0.1 - name: Build v8 ${{ matrix.v8-versions }} + if: steps.v8-build-cache.outputs.cache-hit != 'true' run: | # Store extra tools somewhere undisturbing cd "$(mktemp -d)" @@ -66,6 +76,13 @@ jobs: # Go back to origin cd "${GITHUB_WORKSPACE}" + - name: Save v8 ${{ matrix.v8-versions }} build cache + if: steps.v8-build-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: /opt/v8/self-built + key: ${{ steps.v8-build-cache.outputs.cache-primary-key }} + - name: Build extension run: | phpize From fee0f81ba22114e1d59b65a6db950fec77714b36 Mon Sep 17 00:00:00 2001 From: Joshua Behrens Date: Sat, 28 Sep 2024 10:58:58 +0200 Subject: [PATCH 49/64] Add test build info to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 20fcaba1..d4bb862f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ V8Js ==== [![Build Status](https://travis-ci.org/phpv8/v8js.svg?branch=php7)](https://travis-ci.org/phpv8/v8js) +[![Test building extension](https://github.com/JoshuaBehrens/v8js/actions/workflows/build-test.yml/badge.svg)](https://github.com/JoshuaBehrens/v8js/actions/workflows/build-test.yml) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/phpv8/v8js/master/LICENSE) [![Join the chat at https://gitter.im/phpv8/v8js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/phpv8/v8js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) From 4d4eccb3adf2d612e96a089d3402252476cc5f4c Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 28 Sep 2024 18:09:43 +0200 Subject: [PATCH 50/64] support both V8 10.x and 12.x --- v8js_array_access.cc | 36 +++++++++++++++++++++--------------- v8js_array_access.h | 12 ++++++------ v8js_class.cc | 4 ++++ v8js_methods.cc | 4 ++++ v8js_object_export.cc | 32 ++++++++++++++++++++------------ v8js_v8.h | 16 ++++++++++++++++ 6 files changed, 71 insertions(+), 33 deletions(-) diff --git a/v8js_array_access.cc b/v8js_array_access.cc index e9fee48e..36752136 100644 --- a/v8js_array_access.cc +++ b/v8js_array_access.cc @@ -56,7 +56,7 @@ static zval v8js_array_access_dispatch(zend_object *object, const char *method_n -v8::Intercepted v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ +V8JS_INTERCEPTED v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); v8::Local self = info.Holder(); @@ -71,16 +71,16 @@ v8::Intercepted v8js_array_access_getter(uint32_t index, const v8::PropertyCallb zval_ptr_dtor(&php_value); if (ret_value.IsEmpty()) { - return v8::Intercepted::kNo; + return V8JS_INTERCEPTED_NO; } else { info.GetReturnValue().Set(ret_value); - return v8::Intercepted::kYes; + return V8JS_INTERCEPTED_YES; } } /* }}} */ -v8::Intercepted v8js_array_access_setter(uint32_t index, v8::Local value, - const v8::PropertyCallbackInfo& info) /* {{{ */ +V8JS_INTERCEPTED v8js_array_access_setter(uint32_t index, v8::Local value, + const V8JS_SETTER_PROPERTY_CALLBACK_INFO &info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); v8::Local self = info.Holder(); @@ -91,16 +91,22 @@ v8::Intercepted v8js_array_access_setter(uint32_t index, v8::Local va ZVAL_UNDEF(&zvalue); if (v8js_to_zval(value, &zvalue, 0, isolate) != SUCCESS) { - return v8::Intercepted::kNo; + return V8JS_INTERCEPTED_NO; } zval php_value = v8js_array_access_dispatch(object, "offsetSet", 2, index, zvalue); zval_ptr_dtor(&php_value); +#if !PHP_V8_HAS_INTERCEPTED + /* simply pass back the value to tell we intercepted the call + * as the offsetSet function returns void. */ + info.GetReturnValue().Set(value); +#endif + /* if PHP wanted to hold on to this value, zend_call_function would * have bumped the refcount. */ zval_ptr_dtor(&zvalue); - return v8::Intercepted::kYes; + return V8JS_INTERCEPTED_YES; } /* }}} */ @@ -160,7 +166,7 @@ static void v8js_array_access_length(v8::Local property, const v8::P } /* }}} */ -v8::Intercepted v8js_array_access_deleter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ +V8JS_INTERCEPTED v8js_array_access_deleter(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); v8::Local self = info.Holder(); @@ -174,11 +180,11 @@ v8::Intercepted v8js_array_access_deleter(uint32_t index, const v8::PropertyCall zval_ptr_dtor(&php_value); info.GetReturnValue().Set(V8JS_BOOL(true)); - return v8::Intercepted::kYes; + return V8JS_INTERCEPTED_YES; } /* }}} */ -v8::Intercepted v8js_array_access_query(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ +V8JS_INTERCEPTED v8js_array_access_query(uint32_t index, const v8::PropertyCallbackInfo& info) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); v8::Local self = info.Holder(); @@ -189,10 +195,10 @@ v8::Intercepted v8js_array_access_query(uint32_t index, const v8::PropertyCallba * otherwise we're expected to return an empty handle. */ if(v8js_array_access_isset_p(object, index)) { info.GetReturnValue().Set(V8JS_UINT(v8::PropertyAttribute::None)); - return v8::Intercepted::kYes; + return V8JS_INTERCEPTED_YES; } - return v8::Intercepted::kNo; + return V8JS_INTERCEPTED_NO; } /* }}} */ @@ -222,7 +228,7 @@ void v8js_array_access_enumerator(const v8::PropertyCallbackInfo& inf -v8::Intercepted v8js_array_access_named_getter(v8::Local property_name, const v8::PropertyCallbackInfo &info) /* {{{ */ +V8JS_INTERCEPTED v8js_array_access_named_getter(v8::Local property_name, const v8::PropertyCallbackInfo &info) /* {{{ */ { v8::Local property = v8::Local::Cast(property_name); v8::Isolate *isolate = info.GetIsolate(); @@ -231,7 +237,7 @@ v8::Intercepted v8js_array_access_named_getter(v8::Local property_name if(strcmp(name, "length") == 0) { v8js_array_access_length(property, info); - return v8::Intercepted::kYes; + return V8JS_INTERCEPTED_YES; } v8::Local ret_value = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_GETTER); @@ -255,7 +261,7 @@ v8::Intercepted v8js_array_access_named_getter(v8::Local property_name } info.GetReturnValue().Set(ret_value); - return v8::Intercepted::kYes; + return V8JS_INTERCEPTED_YES; } /* }}} */ diff --git a/v8js_array_access.h b/v8js_array_access.h index 822ed74c..6884c7b8 100644 --- a/v8js_array_access.h +++ b/v8js_array_access.h @@ -14,18 +14,18 @@ #define V8JS_ARRAY_ACCESS_H /* Indexed Property Handlers */ -v8::Intercepted v8js_array_access_getter(uint32_t index, +V8JS_INTERCEPTED v8js_array_access_getter(uint32_t index, const v8::PropertyCallbackInfo& info); -v8::Intercepted v8js_array_access_setter(uint32_t index, v8::Local value, - const v8::PropertyCallbackInfo& info); +V8JS_INTERCEPTED v8js_array_access_setter(uint32_t index, v8::Local value, + const V8JS_SETTER_PROPERTY_CALLBACK_INFO &info); void v8js_array_access_enumerator(const v8::PropertyCallbackInfo& info); -v8::Intercepted v8js_array_access_deleter(uint32_t index, +V8JS_INTERCEPTED v8js_array_access_deleter(uint32_t index, const v8::PropertyCallbackInfo& info); -v8::Intercepted v8js_array_access_query(uint32_t index, +V8JS_INTERCEPTED v8js_array_access_query(uint32_t index, const v8::PropertyCallbackInfo& info); /* Named Property Handlers */ -v8::Intercepted v8js_array_access_named_getter(v8::Local property, +V8JS_INTERCEPTED v8js_array_access_named_getter(v8::Local property, const v8::PropertyCallbackInfo &info); #endif /* V8JS_ARRAY_ACCESS_H */ diff --git a/v8js_class.cc b/v8js_class.cc index 66fe565c..767ff67f 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -524,7 +524,11 @@ static void v8js_compile_script(zval *this_ptr, const zend_string *str, const ze v8::Local sname = identifier ? V8JS_ZSTR(identifier) : V8JS_SYM("V8Js::compileString()"); +#if PHP_V8_API_VERSION >= 12002000 v8::ScriptOrigin origin(sname); +#else + v8::ScriptOrigin origin(c->isolate, sname); +#endif if (ZSTR_LEN(str) > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, diff --git a/v8js_methods.cc b/v8js_methods.cc index f888eb18..78a78da3 100644 --- a/v8js_methods.cc +++ b/v8js_methods.cc @@ -502,7 +502,11 @@ V8JS_METHOD(require) // Set script identifier v8::Local sname = V8JS_STR(normalised_module_id); +#if PHP_V8_API_VERSION >= 12002000 v8::ScriptOrigin origin(sname); +#else + v8::ScriptOrigin origin(c->isolate, sname); +#endif if (Z_STRLEN(module_code) > std::numeric_limits::max()) { zend_throw_exception(php_ce_v8js_exception, diff --git a/v8js_object_export.cc b/v8js_object_export.cc index e2b2c886..2792058c 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -857,58 +857,62 @@ v8::Local v8js_named_property_callback(v8::Isolate *isolate, v8::Loca } /* }}} */ -static v8::Intercepted v8js_named_property_getter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ +static V8JS_INTERCEPTED v8js_named_property_getter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ { v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_GETTER); if (r.IsEmpty()) { - return v8::Intercepted::kNo; + return V8JS_INTERCEPTED_NO; } else { info.GetReturnValue().Set(r); - return v8::Intercepted::kYes; + return V8JS_INTERCEPTED_YES; } } /* }}} */ -static v8::Intercepted v8js_named_property_setter(v8::Local property, v8::Local value, const v8::PropertyCallbackInfo &info) /* {{{ */ +static V8JS_INTERCEPTED v8js_named_property_setter(v8::Local property, v8::Local value, const V8JS_SETTER_PROPERTY_CALLBACK_INFO &info) /* {{{ */ { v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_SETTER, value); +#if PHP_V8_HAS_INTERCEPTED return r.IsEmpty() ? v8::Intercepted::kNo : v8::Intercepted::kYes; +#else + info.GetReturnValue().Set(r); +#endif } /* }}} */ -static v8::Intercepted v8js_named_property_query(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ +static V8JS_INTERCEPTED v8js_named_property_query(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ { v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_QUERY); if (r.IsEmpty()) { - return v8::Intercepted::kNo; + return V8JS_INTERCEPTED_NO; } v8::Isolate *isolate = info.GetIsolate(); v8::MaybeLocal value = r->ToInteger(isolate->GetEnteredOrMicrotaskContext()); if (value.IsEmpty()) { - return v8::Intercepted::kNo; + return V8JS_INTERCEPTED_NO; } else { info.GetReturnValue().Set(value.ToLocalChecked()); - return v8::Intercepted::kYes; + return V8JS_INTERCEPTED_YES; } } /* }}} */ -static v8::Intercepted v8js_named_property_deleter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ +static V8JS_INTERCEPTED v8js_named_property_deleter(v8::Local property, const v8::PropertyCallbackInfo &info) /* {{{ */ { v8::Local r = v8js_named_property_callback(info.GetIsolate(), info.Holder(), property, V8JS_PROP_DELETER); if (r.IsEmpty()) { - return v8::Intercepted::kNo; + return V8JS_INTERCEPTED_NO; } v8::Isolate *isolate = info.GetIsolate(); v8::Local value = r->ToBoolean(isolate); if (value.IsEmpty()) { - return v8::Intercepted::kNo; + return V8JS_INTERCEPTED_NO; } else { info.GetReturnValue().Set(value); - return v8::Intercepted::kYes; + return V8JS_INTERCEPTED_YES; } } /* }}} */ @@ -951,7 +955,11 @@ static v8::MaybeLocal v8js_wrap_object(v8::Isolate *isolate, zend_cl /* We'll free persist_tpl_ when template_cache is destroyed */ v8::Local inst_tpl = new_tpl->InstanceTemplate(); +#if PHP_V8_HAS_INTERCEPTED v8::NamedPropertyGetterCallback getter = v8js_named_property_getter; +#else + v8::GenericNamedPropertyGetterCallback getter = v8js_named_property_getter; +#endif v8::GenericNamedPropertyEnumeratorCallback enumerator = v8js_named_property_enumerator; /* Check for ArrayAccess object */ diff --git a/v8js_v8.h b/v8js_v8.h index 46e28a9c..71235dcb 100644 --- a/v8js_v8.h +++ b/v8js_v8.h @@ -113,6 +113,22 @@ int v8js_get_properties_hash(v8::Local jsValue, HashTable *retval, in #define IS_LONG 99 #endif +#define PHP_V8_HAS_INTERCEPTED PHP_V8_API_VERSION >= 12005000 + +#if PHP_V8_HAS_INTERCEPTED +#define V8JS_INTERCEPTED v8::Intercepted +#define V8JS_INTERCEPTED_YES v8::Intercepted::kYes +#define V8JS_INTERCEPTED_NO v8::Intercepted::kNo +#define V8JS_SETTER_PROPERTY_CALLBACK_INFO v8::PropertyCallbackInfo + +#else +#define V8JS_INTERCEPTED void +#define V8JS_INTERCEPTED_YES +#define V8JS_INTERCEPTED_NO +#define V8JS_SETTER_PROPERTY_CALLBACK_INFO v8::PropertyCallbackInfo + +#endif + #endif /* V8JS_V8_H */ From 9f854c53434fab4233f656451654b7f3da54ebb3 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sat, 28 Sep 2024 23:59:01 +0200 Subject: [PATCH 51/64] remove remains of old travis/jenkins/vagrant testenv stuff --- .dockerignore | 1 - .gitignore | 1 - .travis.yml | 15 ------- Commandfile | 72 ------------------------------ Dockerfile.jenkins | 22 ---------- Dockerfile.travis | 22 ---------- Jenkinsfile | 34 -------------- Makefile.travis | 16 ------- README.md | 3 +- Vagrantfile | 107 --------------------------------------------- 10 files changed, 1 insertion(+), 292 deletions(-) delete mode 100644 .travis.yml delete mode 100644 Commandfile delete mode 100644 Dockerfile.jenkins delete mode 100644 Dockerfile.travis delete mode 100644 Jenkinsfile delete mode 100644 Makefile.travis delete mode 100644 Vagrantfile diff --git a/.dockerignore b/.dockerignore index 6e46a23b..967e56a1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -40,7 +40,6 @@ tests/*.php tests/*.sh tests/*.mem -.vagrant tmp-php.ini coverage_report/** diff --git a/.gitignore b/.gitignore index 38419c7e..10a94aac 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ tests/*.php tests/*.sh tests/*.mem -.vagrant tmp-php.ini coverage_report/** diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ff8c61e6..00000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: php -sudo: required - -services: - - docker - -env: - - V8VER=7.5 - PHPVER=7.1 - - V8VER=7.5 - PHPVER=7.2 - - V8VER=7.5 - PHPVER=7.3 - -script: make -f Makefile.travis test diff --git a/Commandfile b/Commandfile deleted file mode 100644 index 635f1007..00000000 --- a/Commandfile +++ /dev/null @@ -1,72 +0,0 @@ -# -# Vagrant Commandfile -# (use with vagrant-devcommands plugin) -# - -command 'phpize', - description: 'executes "phpize" to configure source tree for installed PHP version', - script: 'cd /data/v8js && phpize' - -command 'configure', - description: 'executes "configure" to prepare build', - parameters: { - cxxflags: { default: "-ggdb -Wall -Wno-write-strings" }, - ldflags: { default: "-ggdb -lstdc++" }, - }, - script: <<-eof - bash -c 'cd /data/build; ../v8js/configure `bash -c "if test -d /opt/libv8-*; then echo -n --with-v8js=; echo /opt/libv8-*; fi"` `test -d "/usr/lib64" && echo --with-libdir=lib64` CXXFLAGS="%{cxxflags}" LDFLAGS="%{ldflags}"' - eof - -command 'clean', - description: 'executes "make clean"', - script: <<-eof - cd /data/build; `which gmake || which make` clean; rm -rf /data/v8js/coverage_report /data/build/gcov.info - eof - -command 'build', - description: 'executes "make"', - script: <<-eof - cd /data/build; `which gmake || which make` -j4 - eof - -command 'test', - description: 'executes "make test"', - parameters: { - tests: { wrap: "TESTS=tests/%s", optional: true }, - }, - script: <<-eof - cd /data/build; `which gmake || which make` test %{tests} NO_INTERACTION=1 REPORT_EXIT_STATUS=1 - eof - -command 'shell', - description: 'execute a PHP CLI interactive shell with V8Js loaded', - script: <<-eof - cd /data/build; php -a -d extension=modules/v8js.so - eof - -chain 'all', - commands: [ - { command: 'phpize' }, - { command: 'configure' }, - { command: 'clean' }, - { command: 'build' }, - { command: 'test' } - ] - -command 'coverage_report', - description: 'capture *.gcda files and generate code coverage report', - script: <<-eof - cd /data/build - lcov --base-directory=.libs --directory=.libs --directory ../v8js/ --no-external --capture --output-file gcov.info - genhtml --legend --output-directory ../v8js/coverage_report/ --title "V8Js Code Coverage" gcov.info - eof - -chain 'coverage', - commands: [ - { command: 'phpize' }, - { command: 'configure', argv: ['--cxxflags=-O0 --coverage', '--ldflags=--coverage'] }, - { command: 'clean' }, - { command: 'build' }, - { command: 'test' }, - { command: 'coverage_report' }, - ] diff --git a/Dockerfile.jenkins b/Dockerfile.jenkins deleted file mode 100644 index 1cf9fae4..00000000 --- a/Dockerfile.jenkins +++ /dev/null @@ -1,22 +0,0 @@ -ARG V8VER -FROM stesie/libv8-${V8VER}:latest - -ARG PHPVER - -ENV DEBIAN_FRONTEND=noninteractive -ENV LC_ALL=C.UTF-8 -ENV NO_INTERACTION=1 -ENV REPORT_EXIT_STATUS=1 - -RUN apt-get update -q -RUN apt-get install -y wget autoconf build-essential libreadline-dev pkg-config - -RUN wget https://www.php.net/distributions/php-${PHPVER}.tar.gz && \ - tar xzf php-${PHPVER}.tar.gz -ADD . /php-${PHPVER}/ext/v8js -WORKDIR /php-${PHPVER} - -RUN ./buildconf --force -RUN ./configure --disable-all --with-readline --enable-cli --enable-json --enable-maintainer-zts --with-v8js=/opt/libv8-$V8VER/ CFLAGS="-fsanitize=address -g -O0" CXXFLAGS="-fsanitize=address -g -O0" CPPFLAGS="$([ $( echo "$V8VER" | cut -c 1-1 ) -ge 8 ] && echo "-DV8_COMPRESS_POINTERS" || echo "")" -RUN sed -e "s/^EXTRA_LIBS.*/& -lv8_libplatform -ldl/" -i Makefile -RUN make -j5 diff --git a/Dockerfile.travis b/Dockerfile.travis deleted file mode 100644 index 5ce33992..00000000 --- a/Dockerfile.travis +++ /dev/null @@ -1,22 +0,0 @@ -FROM ubuntu:xenial - -ENV DEBIAN_FRONTEND=noninteractive -ENV LC_ALL=C.UTF-8 -ENV NO_INTERACTION=1 -ENV REPORT_EXIT_STATUS=1 - -RUN apt-get update -q -RUN apt-get install -y software-properties-common - -RUN add-apt-repository ppa:ondrej/php -RUN add-apt-repository ppa:stesie/libv8 -y -RUN apt-get update -q - -RUN apt-get install -y php$PHPVER-dev libv8-$V8VER-dev - -ADD . /app -WORKDIR /app - -RUN phpize -RUN ./configure CXXFLAGS="-Wall -Wno-write-strings" LDFLAGS="-lstdc++" --with-v8js=/opt/libv8-$V8VER/ -RUN make -j4 diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index c90adced..00000000 --- a/Jenkinsfile +++ /dev/null @@ -1,34 +0,0 @@ -pipeline { - agent none - stages { - stage('BuildAndTest') { - matrix { - agent any - axes { - axis { - name 'PHPVER' - values '7.3.21', '7.4.9' - } - axis { - name 'V8VER' - values '7.9', '8.4', '8.6' - } - } - stages { - stage('Build') { - steps { - echo "Building w/ V8 ${V8VER}, PHP ${PHPVER} as Docker image ${BUILD_TAG}-${V8VER}-${PHPVER}" - sh "docker build -f Dockerfile.jenkins --build-arg V8VER=${V8VER} --build-arg PHPVER=${PHPVER} -t ${BUILD_TAG}-${V8VER}-${PHPVER} ." - } - } - stage('Test') { - steps { - echo "Running test on ${BUILD_TAG}-${V8VER}-${PHPVER}" - sh "docker run --rm -t ${BUILD_TAG}-${V8VER}-${PHPVER} make test TESTS='ext/v8js/tests/*.phpt'" - } - } - } - } - } - } -} diff --git a/Makefile.travis b/Makefile.travis deleted file mode 100644 index 74cfd273..00000000 --- a/Makefile.travis +++ /dev/null @@ -1,16 +0,0 @@ -# Configure and build scripts for travis CI system -V8VER ?= 7.5 - -IMAGENAME ?= v8js-test - -export NO_INTERACTION=1 -export REPORT_EXIT_STATUS=1 - -build: - envsubst < Dockerfile.travis > Dockerfile.tmp - docker build -t $(IMAGENAME) -f Dockerfile.tmp . - -test: build - docker run --rm -t $(IMAGENAME) make test - -.PHONY: build test diff --git a/README.md b/README.md index d4bb862f..83036303 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ V8Js ==== -[![Build Status](https://travis-ci.org/phpv8/v8js.svg?branch=php7)](https://travis-ci.org/phpv8/v8js) -[![Test building extension](https://github.com/JoshuaBehrens/v8js/actions/workflows/build-test.yml/badge.svg)](https://github.com/JoshuaBehrens/v8js/actions/workflows/build-test.yml) +[![Test building extension](https://github.com/phpv8/v8js/actions/workflows/build-test.yml/badge.svg)](https://github.com/phpv8/v8js/actions/workflows/build-test.yml) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/phpv8/v8js/master/LICENSE) [![Join the chat at https://gitter.im/phpv8/v8js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/phpv8/v8js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) diff --git a/Vagrantfile b/Vagrantfile deleted file mode 100644 index 640d485b..00000000 --- a/Vagrantfile +++ /dev/null @@ -1,107 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby ts=2 sts=2 sw=2 et : - -# All Vagrant configuration is done below. The "2" in Vagrant.configure -# configures the configuration version (we support older styles for -# backwards compatibility). Please don't change it unless you know what -# you're doing. -Vagrant.configure("2") do |config| - # Every Vagrant development environment requires a box. You can search for - # boxes at https://atlas.hashicorp.com/search. - config.vm.box = "ubuntu/bionic64" - - - # - # mass-define "generic" Ubuntu boxes - # - %w{7.5}.each { |version| - config.vm.define "v8-#{version}" do |i| - i.vm.synced_folder ".", "/data/v8js" - - i.vm.provision "shell", inline: <<-SHELL - gpg --keyserver keys.gnupg.net --recv 7F438280EF8D349F - gpg --armor --export 7F438280EF8D349F | apt-key add - - - apt-get update - apt-get install -y software-properties-common gdb tmux git tig curl apache2-utils lcov - - add-apt-repository ppa:ondrej/php - add-apt-repository ppa:stesie/libv8 - apt-get update - apt-get install -y php7.1-dev libv8-#{version}-dbg libv8-#{version}-dev - SHELL - end - } - - %w{}.each { |version| - config.vm.define "v8-#{version}" do |i| - i.vm.synced_folder ".", "/data/v8js" - - i.vm.provision "shell", inline: <<-SHELL - gpg --keyserver keys.gnupg.net --recv 7F438280EF8D349F - gpg --armor --export 7F438280EF8D349F | apt-key add - - - apt-get update - apt-get install -y software-properties-common gdb tmux git tig curl apache2-utils lcov build-essential python libglib2.0-dev - - add-apt-repository ppa:ondrej/php - apt-get update - apt-get install -y php7.1-dev - - mkdir -p /data - cd /data - - # Install depot_tools first (needed for source checkout) - git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git - export PATH=`pwd`/depot_tools:"$PATH" - - # Download v8 - fetch v8 - cd v8 - - # checkout version - git checkout #{version} - gclient sync - - # Setup GN - tools/dev/v8gen.py -vv x64.release -- is_component_build=true - - # Build - ninja -C out.gn/x64.release/ - - # Install to /opt/libv8-#{version}/ - sudo mkdir -p /opt/libv8-#{version}/{lib,include} - sudo cp out.gn/x64.release/lib*.so out.gn/x64.release/*_blob.bin out.gn/x64.release/icudtl.dat /opt/libv8-#{version}/lib/ - sudo cp -R include/* /opt/libv8-#{version}/include/ - SHELL - end - } - - config.vm.define "php-7.4" do |i| - i.vm.synced_folder ".", "/data/v8js" - - i.vm.provision "shell", inline: <<-SHELL - gpg --keyserver keys.gnupg.net --recv 7F438280EF8D349F - gpg --armor --export 7F438280EF8D349F | apt-key add - - - apt-get update - apt-get install -y software-properties-common gdb tmux git tig curl apache2-utils lcov - - add-apt-repository ppa:stesie/libv8 - apt-get update - apt-get install -y libv8-7.5-dbg libv8-7.5-dev - - test -x /tmp/php-src || git clone https://github.com/php/php-src.git /tmp/php-src -b PHP-7.4 --depth 1 - cd /tmp/php-src - apt-get install -y build-essential bison re2c libreadline-dev - ./buildconf - ./configure --disable-all --with-readline - make -j4 - make install - SHELL - end - - config.vm.provision "shell", privileged: false, inline: <<-SHELL - sudo mkdir -p /data/build && sudo chown $USER:$USER /data/build - SHELL -end From 56eb76bd9afc686115fb7a84b4503341a12a5525 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 29 Sep 2024 10:05:47 +0200 Subject: [PATCH 52/64] Check for libnode (additional/instead of libv8) --- config.m4 | 122 +++++++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/config.m4 b/config.m4 index cbf3109f..9c265067 100644 --- a/config.m4 +++ b/config.m4 @@ -3,46 +3,53 @@ PHP_ARG_WITH(v8js, for V8 Javascript Engine, if test "$PHP_V8JS" != "no"; then SEARCH_PATH="/usr/local /usr" - SEARCH_FOR="libv8.$SHLIB_SUFFIX_NAME" - - if test -d "$PHP_V8JS"; then - SEARCH_PATH="$PHP_V8JS" - - # set rpath, so library loader picks up libv8 even if it's not on the - # system's library search path - case $host_os in - darwin* ) - # MacOS does not support --rpath - ;; - * ) - LDFLAGS="$LDFLAGS -Wl,--rpath=$PHP_V8JS/$PHP_LIBDIR" - ;; - esac - fi - - AC_MSG_CHECKING([for V8 files in default path]) - ARCH=$(uname -m) - - for i in $SEARCH_PATH ; do - if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/v8/v8.h"; then - V8_INCLUDE_DIR="$i/include/v8" - V8_LIBRARY_DIR="$i/$PHP_LIBDIR" - AC_MSG_RESULT(found in $i) - fi - # Debian installations - if test -r "$i/$PHP_LIBDIR/$ARCH-linux-gnu/$SEARCH_FOR"; then - V8_INCLUDE_DIR="$i/include/v8" - V8_LIBRARY_DIR="$i/$PHP_LIBDIR/$ARCH-linux-gnu" - AC_MSG_RESULT(found in $i) + for libname in v8 node; do + SEARCH_FOR="lib$libname.$SHLIB_SUFFIX_NAME" + + if test -d "$PHP_V8JS"; then + SEARCH_PATH="$PHP_V8JS" + + # set rpath, so library loader picks up libv8 even if it's not on the + # system's library search path + case $host_os in + darwin* ) + # MacOS does not support --rpath + ;; + * ) + LDFLAGS="$LDFLAGS -Wl,--rpath=$PHP_V8JS/$PHP_LIBDIR" + ;; + esac fi - # Manual installations - if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/libplatform/libplatform.h"; then - V8_INCLUDE_DIR="$i/include" - V8_LIBRARY_DIR="$i/$PHP_LIBDIR" - AC_MSG_RESULT(found in $i) - fi + AC_MSG_CHECKING([for V8 files in default path]) + ARCH=$(uname -m) + + for i in $SEARCH_PATH ; do + echo checking "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/$libname/v8.h" + if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/$libname/v8.h"; then + V8_INCLUDE_DIR="$i/include/$libname" + V8_LIBRARY_DIR="$i/$PHP_LIBDIR" + AC_MSG_RESULT(found in $i) + break 2 + fi + + # Debian installations + if test -r "$i/$PHP_LIBDIR/$ARCH-linux-gnu/$SEARCH_FOR"; then + V8_INCLUDE_DIR="$i/include/$libname" + V8_LIBRARY_DIR="$i/$PHP_LIBDIR/$ARCH-linux-gnu" + AC_MSG_RESULT(found in $i) + break 2 + fi + + # Manual installations + if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/libplatform/libplatform.h"; then + V8_INCLUDE_DIR="$i/include" + V8_LIBRARY_DIR="$i/$PHP_LIBDIR" + AC_MSG_RESULT(found in $i) + break 2 + fi + done done AC_DEFINE_UNQUOTED([PHP_V8_EXEC_PATH], "$V8_LIBRARY_DIR/$SEARCH_FOR", [Full path to libv8 library file]) @@ -53,8 +60,9 @@ if test "$PHP_V8JS" != "no"; then fi PHP_ADD_INCLUDE($V8_INCLUDE_DIR) - PHP_ADD_LIBRARY_WITH_PATH(v8, $V8_LIBRARY_DIR, V8JS_SHARED_LIBADD) + PHP_ADD_LIBRARY_WITH_PATH($libname, $V8_LIBRARY_DIR, V8JS_SHARED_LIBADD) PHP_SUBST(V8JS_SHARED_LIBADD) + PHP_REQUIRE_CXX() @@ -112,26 +120,28 @@ if test "$PHP_V8JS" != "no"; then CPPFLAGS="$CPPFLAGS -I$V8_INCLUDE_DIR -std=$ac_cv_v8_cstd" LDFLAGS="$LDFLAGS -L$V8_LIBRARY_DIR" - AC_MSG_CHECKING([for libv8_libplatform]) - AC_DEFUN([V8_CHECK_LINK], [ - save_LIBS="$LIBS" - LIBS="$LIBS $1 -lv8_libplatform -lv8" - AC_LINK_IFELSE([AC_LANG_PROGRAM([ - #include - ], [ v8::platform::NewDefaultPlatform(); ])], [ - dnl libv8_libplatform.so found - AC_MSG_RESULT(found) - V8JS_SHARED_LIBADD="$1 -lv8_libplatform $V8JS_SHARED_LIBADD" - $3 - ], [ $4 ]) - LIBS="$save_LIBS" - ]) + if test "$libname" = "v8"; then + AC_MSG_CHECKING([for libv8_libplatform]) + AC_DEFUN([V8_CHECK_LINK], [ + save_LIBS="$LIBS" + LIBS="$LIBS $1 -lv8_libplatform -lv8" + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + #include + ], [ v8::platform::NewDefaultPlatform(); ])], [ + dnl libv8_libplatform.so found + AC_MSG_RESULT(found) + V8JS_SHARED_LIBADD="$1 -lv8_libplatform $V8JS_SHARED_LIBADD" + $3 + ], [ $4 ]) + LIBS="$save_LIBS" + ]) - V8_CHECK_LINK([], [], [], [ - V8_CHECK_LINK([-lv8_libbase], [], [], [ - AC_MSG_ERROR([could not find libv8_libplatform library]) + V8_CHECK_LINK([], [], [], [ + V8_CHECK_LINK([-lv8_libbase], [], [], [ + AC_MSG_ERROR([could not find libv8_libplatform library]) + ]) ]) - ]) + fi dnl From b763f390d3b7e18f8f7ddebbaf711e7a2689272b Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 29 Sep 2024 17:59:42 +0200 Subject: [PATCH 53/64] remove stray echo statement --- config.m4 | 1 - 1 file changed, 1 deletion(-) diff --git a/config.m4 b/config.m4 index 9c265067..835eedf9 100644 --- a/config.m4 +++ b/config.m4 @@ -26,7 +26,6 @@ if test "$PHP_V8JS" != "no"; then ARCH=$(uname -m) for i in $SEARCH_PATH ; do - echo checking "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/$libname/v8.h" if test -r "$i/$PHP_LIBDIR/$SEARCH_FOR" -a -r "$i/include/$libname/v8.h"; then V8_INCLUDE_DIR="$i/include/$libname" V8_LIBRARY_DIR="$i/$PHP_LIBDIR" From bf319f7620492984780390cc2737336b5c73dc62 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 29 Sep 2024 18:11:48 +0200 Subject: [PATCH 54/64] run github action on pull/request push to php8 branch only --- .github/workflows/build-test.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 1902c690..d7aacfb9 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -1,7 +1,12 @@ name: Test building extension on: - - push + pull_request: + branches: + - php8 + push: + branches: + - php8 permissions: contents: read From 21d6286ae0e5b063904a4ac277290181d4cf63ce Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 29 Sep 2024 18:20:09 +0200 Subject: [PATCH 55/64] add ci test on alpine --- .github/workflows/build-test.yml | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index d7aacfb9..0a59a38f 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -94,3 +94,45 @@ jobs: ./configure --with-v8js=/opt/v8/self-built LDFLAGS="-lstdc++" CPPFLAGS="-DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX" make make test + + - name: Archive test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: phpt-test-results + path: | + php_test_results*.txt + tests/*.out + + alpine: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup latest Alpine Linux + uses: jirutka/setup-alpine@v1 + + - name: Install dependencies + run: | + cat /etc/alpine-release + apk add php83-dev nodejs-dev g++ make + shell: alpine.sh --root {0} + + - name: Build extension + run: | + phpize + ./configure + make + make test + shell: alpine.sh {0} + + - name: Archive test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: phpt-test-results + path: | + php_test_results*.txt + tests/*.out From eaf4b732480cfd2e43e291cb2022c36f297255ce Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Sun, 29 Sep 2024 19:47:13 +0200 Subject: [PATCH 56/64] skip array_access_002 test, broken on V8 11.3.244.8 --- tests/array_access_002.phpt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/array_access_002.phpt b/tests/array_access_002.phpt index 641cb519..43d5b44a 100644 --- a/tests/array_access_002.phpt +++ b/tests/array_access_002.phpt @@ -1,7 +1,13 @@ --TEST-- Test V8::executeString() : Use ArrayAccess with JavaScript native push method --SKIPIF-- - + --INI-- v8js.use_array_access = 1 --FILE-- From 6386e9d1cb834e7786809fb404f38264c227171f Mon Sep 17 00:00:00 2001 From: Romain Gautier Date: Thu, 9 Jan 2025 09:36:33 +0100 Subject: [PATCH 57/64] adapt code to handle php 8.4 too (based on @JoshuaBehrens & @rbro work) and fix some tests Signed-off-by: Romain Gautier --- tests/commonjs_exception_001.phpt | 4 ++-- tests/commonjs_exception_002.phpt | 4 ++-- tests/commonjs_fatal_error.phpt | 2 +- tests/fatal_error_no_uninstall_inner_frame.phpt | 2 +- tests/fatal_error_recursive.phpt | 6 +++--- tests/fatal_error_rethrow.phpt | 2 +- tests/generators_from_v8_008.phpt | 2 +- tests/generators_from_v8_009.phpt | 2 +- v8js_object_export.cc | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/commonjs_exception_001.phpt b/tests/commonjs_exception_001.phpt index 4f6a6d72..71ffcb68 100644 --- a/tests/commonjs_exception_001.phpt +++ b/tests/commonjs_exception_001.phpt @@ -20,13 +20,13 @@ $v8->executeString($JS, 'module.js', V8Js::FLAG_PROPAGATE_PHP_EXCEPTIONS); --EXPECTF-- Fatal error: Uncaught Exception: some exception in %s%ecommonjs_exception_001.php:9 Stack trace: -#0 [internal function]: {closure}('test') +#0 [internal function]: {closur%s}('test') #1 %s%ecommonjs_exception_001.php(12): V8Js->executeString('var foo = requi...', 'module.js', 4) #2 {main} Next V8JsScriptException: module.js:1: Exception: some exception in %s%ecommonjs_exception_001.php:9 Stack trace: -#0 [internal function]: {closure}('test') +#0 [internal function]: {closur%s}('test') #1 %s%ecommonjs_exception_001.php(12): V8Js->executeString('var foo = requi...', 'module.js', 4) #2 {main} in %s%ecommonjs_exception_001.php:12 Stack trace: diff --git a/tests/commonjs_exception_002.phpt b/tests/commonjs_exception_002.phpt index 34dd856c..5121546c 100644 --- a/tests/commonjs_exception_002.phpt +++ b/tests/commonjs_exception_002.phpt @@ -23,13 +23,13 @@ $v8->executeString($JS, 'module.js', V8Js::FLAG_PROPAGATE_PHP_EXCEPTIONS); --EXPECTF-- Fatal error: Uncaught Exception: some exception in %s%ecommonjs_exception_002.php:9 Stack trace: -#0 [internal function]: {closure}('', './test') +#0 [internal function]: {closur%s}('', './test') #1 %s%ecommonjs_exception_002.php(15): V8Js->executeString('var foo = requi...', 'module.js', 4) #2 {main} Next V8JsScriptException: module.js:1: Exception: some exception in %s%ecommonjs_exception_002.php:9 Stack trace: -#0 [internal function]: {closure}('', './test') +#0 [internal function]: {closur%s}('', './test') #1 %s%ecommonjs_exception_002.php(15): V8Js->executeString('var foo = requi...', 'module.js', 4) #2 {main} in %s%ecommonjs_exception_002.php:15 Stack trace: diff --git a/tests/commonjs_fatal_error.phpt b/tests/commonjs_fatal_error.phpt index f246adfe..7a06b15d 100644 --- a/tests/commonjs_fatal_error.phpt +++ b/tests/commonjs_fatal_error.phpt @@ -7,7 +7,7 @@ Test V8Js::setModuleLoader : Handle fatal errors gracefully $v8 = new V8Js(); $v8->setModuleLoader(function() { - trigger_error('some fatal error', E_USER_ERROR); + @trigger_error('some fatal error', E_USER_ERROR); }); $v8->executeString(' require("foo"); '); diff --git a/tests/fatal_error_no_uninstall_inner_frame.phpt b/tests/fatal_error_no_uninstall_inner_frame.phpt index f642ceb8..155119a8 100644 --- a/tests/fatal_error_no_uninstall_inner_frame.phpt +++ b/tests/fatal_error_no_uninstall_inner_frame.phpt @@ -29,7 +29,7 @@ nothing. Fatal error: Uncaught Error: Call to a member function foo() on null in %s%efatal_error_no_uninstall_inner_frame.php:15 Stack trace: -#0 [internal function]: {closure}() +#0 [internal function]: {closur%s}() #1 [internal function]: Closure->__invoke() #2 %s%efatal_error_no_uninstall_inner_frame.php(18): V8Js->executeString('PHP.foo();') #3 {main} diff --git a/tests/fatal_error_recursive.phpt b/tests/fatal_error_recursive.phpt index 8fa1d44a..44c4b76b 100644 --- a/tests/fatal_error_recursive.phpt +++ b/tests/fatal_error_recursive.phpt @@ -37,13 +37,13 @@ foo Fatal error: Uncaught Error: Call to a member function bar() on null in %s%efatal_error_recursive.php:7 Stack trace: -#0 [internal function]: {closure}() +#0 [internal function]: {closur%s}() #1 [internal function]: Closure->__invoke() #2 %s%efatal_error_recursive.php(12): V8Js->executeString('PHP.baz();') -#3 [internal function]: {closure}() +#3 [internal function]: {closur%s}() #4 [internal function]: Closure->__invoke() #5 %s%efatal_error_recursive.php(17): V8Js->executeString('PHP.bar();') -#6 [internal function]: {closure}() +#6 [internal function]: {closur%s}() #7 [internal function]: Closure->__invoke() #8 %s%efatal_error_recursive.php(25): V8Js->executeString('PHP.nofail(); P...') #9 {main} diff --git a/tests/fatal_error_rethrow.phpt b/tests/fatal_error_rethrow.phpt index 4459432e..0cf3dd86 100644 --- a/tests/fatal_error_rethrow.phpt +++ b/tests/fatal_error_rethrow.phpt @@ -25,7 +25,7 @@ $js->executeString($script); --EXPECTF-- Fatal error: Uncaught Error: Call to a member function bar() on %s in %s%efatal_error_rethrow.php:7 Stack trace: -#0 [internal function]: {closure}() +#0 [internal function]: {closur%s}() #1 [internal function]: Closure->__invoke() #2 %s%efatal_error_rethrow.php(16): V8Js->executeString(%s) #3 {main} diff --git a/tests/generators_from_v8_008.phpt b/tests/generators_from_v8_008.phpt index 4448a475..8881eb99 100644 --- a/tests/generators_from_v8_008.phpt +++ b/tests/generators_from_v8_008.phpt @@ -37,7 +37,7 @@ int(23) Fatal error: Uncaught Exception: this shall not work in %s Stack trace: -#0 [internal function]: {closure}() +#0 [internal function]: {closur%s}() #1 [internal function]: Closure->__invoke() #2 %s: V8Generator->next() #3 {main} diff --git a/tests/generators_from_v8_009.phpt b/tests/generators_from_v8_009.phpt index ff707d77..ff10bc73 100644 --- a/tests/generators_from_v8_009.phpt +++ b/tests/generators_from_v8_009.phpt @@ -22,7 +22,7 @@ EOJS; $v8 = new V8Js(); $v8->getValue = function() { - trigger_error("you're gonna fail now", E_USER_ERROR); + @trigger_error("you're gonna fail now", E_USER_ERROR); }; $gen = $v8->executeString($js); diff --git a/v8js_object_export.cc b/v8js_object_export.cc index 2792058c..8027d380 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -675,7 +675,7 @@ v8::Local v8js_named_property_callback(v8::Isolate *isolate, v8::Loca ce = scope = object->ce; /* First, check the (case-insensitive) method table */ - php_strtolower(lower, name_len); + zend_str_tolower(lower, name_len); method_name = zend_string_init(lower, name_len, 0); // toString() -> __tostring() From c2614b59927fb2f3bb1eab6cd7b9e8509d423e07 Mon Sep 17 00:00:00 2001 From: Romain Gautier Date: Thu, 9 Jan 2025 10:11:25 +0100 Subject: [PATCH 58/64] update var_dump test to handle php84 and previous versions Signed-off-by: Romain Gautier --- tests/var_dump.phpt | 507 ++++++++++++++++++++------------------ tests/var_dump_php83.phpt | 326 ++++++++++++++++++++++++ 2 files changed, 587 insertions(+), 246 deletions(-) create mode 100644 tests/var_dump_php83.phpt diff --git a/tests/var_dump.phpt b/tests/var_dump.phpt index cc0654cb..9097ca9e 100644 --- a/tests/var_dump.phpt +++ b/tests/var_dump.phpt @@ -1,7 +1,10 @@ --TEST-- Test V8::executeString() : var_dump --SKIPIF-- - += 8.4'); +?> --INI-- date.timezone=UTC --FILE-- @@ -70,254 +73,266 @@ try { } ?> ===EOF=== ---EXPECTREGEX-- -\-\-\-\- PHP var_dump of PHP object \-\-\-\- -array\(11\) \{ - \["null"\]\=\> +--EXPECTF-- +---- PHP var_dump of PHP object ---- +array(11) { + ["null"]=> NULL - \["bool"\]\=\> - bool\(true\) - \["string"\]\=\> - string\(6\) "string" - \["uint"\]\=\> - int\(1\) - \["int"\]\=\> - int\(\-1\) - \["number"\]\=\> - float\(3\.141592654\) - \["date"\]\=\> - object\(DateTime\)\#\d+ \(3\) \{ - \["date"\]\=\> - string\(\d+\) "1976\-09\-27 09\:00\:00((\.0+)?)" - \["timezone_type"\]\=\> - int\(3\) - \["timezone"\]\=\> - string\(3\) "UTC" - \} - \["array"\]\=\> - array\(3\) \{ - \[0\]\=\> - int\(1\) - \[1\]\=\> - int\(2\) - \[2\]\=\> - int\(3\) - \} - \["object"\]\=\> - array\(1\) \{ - \["field"\]\=\> - string\(3\) "foo" - \} - \["function"\]\=\> - object\(Closure\)\#\d+ \(1\) \{ - \["parameter"\]\=\> - array\(1\) \{ - \["\$x"\]\=\> - string\(10\) "\" - \} - \} - \["phpobject"\]\=\> - object\(Foo\)\#\d+ \(1\) \{ - \["field"\]\=\> - string\(3\) "php" - \} -\} -\-\-\- JS var_dump of PHP object \-\-\-\- -array \(11\) \{ - \["null"\] \=\> + ["bool"]=> + bool(true) + ["string"]=> + string(6) "string" + ["uint"]=> + int(1) + ["int"]=> + int(-1) + ["number"]=> + float(3.141592654) + ["date"]=> + object(DateTime)#3 (3) { + ["date"]=> + string(26) "1976-09-27 09:00:00.000000" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" + } + ["array"]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["object"]=> + array(1) { + ["field"]=> + string(3) "foo" + } + ["function"]=> + object(Closure)#4 (4) { + ["name"]=> + string(45) "{closure:/tmp/php-v8js/tests/var_dump.php:51}" + ["file"]=> + string(32) "/tmp/php-v8js/tests/var_dump.php" + ["line"]=> + int(51) + ["parameter"]=> + array(1) { + ["$x"]=> + string(10) "" + } + } + ["phpobject"]=> + object(Foo)#5 (1) { + ["field"]=> + string(3) "php" + } +} +--- JS var_dump of PHP object ---- +array (11) { + ["null"] => NULL - \["bool"\] \=\> - bool\(true\) - \["string"\] \=\> - string\(6\) "string" - \["uint"\] \=\> - int\(1\) - \["int"\] \=\> - int\(\-1\) - \["number"\] \=\> - float\(3\.141593\) - \["date"\] \=\> - object\(DateTime\)\#\d+ \(\d+\) \{(?: - \["createFromImmutable"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \})?(?: - \["createFromInterface"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \})? - \["createFromFormat"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["getLastErrors"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["format"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["modify"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["add"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["sub"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["getTimezone"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setTimezone"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["getOffset"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setTime"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setDate"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setISODate"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setTimestamp"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["getTimestamp"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["diff"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \}(?:(?:the following block is missing from PHP 7.4 on){0} - \["\$date"\] \=\> - string\(\d+\) "1976\-09\-27 09\:00\:00((\.0+)?)" - \["\$timezone_type"\] \=\> - int\(3\) - \["\$timezone"\] \=\> - string\(3\) "UTC" - )?\s*\} - \["array"\] \=\> - array\(3\) \{ - \[0\] \=\> - int\(1\) - \[1\] \=\> - int\(2\) - \[2\] \=\> - int\(3\) - \} - \["object"\] \=\> - array \(1\) \{ - \["field"\] \=\> - string\(3\) "foo" - \} - \["function"\] \=\> - object\(Closure\)\#\d+ \(0\) \{ - \} - \["phpobject"\] \=\> - object\(Foo\)\#\d+ \(1\) \{ - \["\$field"\] \=\> - string\(3\) "php" - \} -\} -\-\-\- JS var_dump of JS object \-\-\-\- -object\(Object\)\#\d+ \(12\) \{ - \["undefined"\] \=\> + ["bool"] => + bool(true) + ["string"] => + string(6) "string" + ["uint"] => + int(1) + ["int"] => + int(-1) + ["number"] => + float(3.141593) + ["date"] => + object(DateTime)#%d (20) { + ["createFromImmutable"] => + object(Closure)#%d { + function () { [native code] } + } + ["createFromInterface"] => + object(Closure)#%d { + function () { [native code] } + } + ["createFromFormat"] => + object(Closure)#%d { + function () { [native code] } + } + ["createFromTimestamp"] => + object(Closure)#%d { + function () { [native code] } + } + ["getLastErrors"] => + object(Closure)#%d { + function () { [native code] } + } + ["format"] => + object(Closure)#%d { + function () { [native code] } + } + ["modify"] => + object(Closure)#%d { + function () { [native code] } + } + ["add"] => + object(Closure)#%d { + function () { [native code] } + } + ["sub"] => + object(Closure)#%d { + function () { [native code] } + } + ["getTimezone"] => + object(Closure)#%d { + function () { [native code] } + } + ["setTimezone"] => + object(Closure)#%d { + function () { [native code] } + } + ["getOffset"] => + object(Closure)#%d { + function () { [native code] } + } + ["getMicrosecond"] => + object(Closure)#%d { + function () { [native code] } + } + ["setTime"] => + object(Closure)#%d { + function () { [native code] } + } + ["setDate"] => + object(Closure)#%d { + function () { [native code] } + } + ["setISODate"] => + object(Closure)#%d { + function () { [native code] } + } + ["setTimestamp"] => + object(Closure)#%d { + function () { [native code] } + } + ["setMicrosecond"] => + object(Closure)#%d { + function () { [native code] } + } + ["getTimestamp"] => + object(Closure)#%d { + function () { [native code] } + } + ["diff"] => + object(Closure)#%d { + function () { [native code] } + } + } + ["array"] => + array(3) { + [0] => + int(1) + [1] => + int(2) + [2] => + int(3) + } + ["object"] => + array (1) { + ["field"] => + string(3) "foo" + } + ["function"] => + object(Closure)#%d (0) { + } + ["phpobject"] => + object(Foo)#%d (1) { + ["$field"] => + string(3) "php" + } +} +--- JS var_dump of JS object ---- +object(Object)#%d (12) { + ["undefined"] => NULL - \["null"\] \=\> + ["null"] => NULL - \["bool"\] \=\> - bool\(true\) - \["string"\] \=\> - string\(6\) "string" - \["uint"\] \=\> - int\(1\) - \["int"\] \=\> - int\(\-1\) - \["number"\] \=\> - float\(3\.141593\) - \["regexp"\] \=\> - regexp\(\/regexp\/\) - \["array"\] \=\> - array\(3\) \{ - \[0\] \=\> - int\(1\) - \[1\] \=\> - int\(2\) - \[2\] \=\> - int\(3\) - \} - \["object"\] \=\> - object\(Object\)\#\d+ \(1\) \{ - \["field"\] \=\> - string\(3\) "foo" - \} - \["function"\] \=\> - object\(Closure\)\#\d+ \{ - function id\(x\) \{ return x; \} - \} - \["phpobject"\] \=\> - object\(Foo\)\#\d+ \(1\) \{ - \["\$field"\] \=\> - string\(3\) "php" - \} -\} -\-\-\- PHP var_dump of JS object \-\-\-\- -object\(V8Object\)\#\d+ \(12\) \{ - \["undefined"\]\=\> + ["bool"] => + bool(true) + ["string"] => + string(6) "string" + ["uint"] => + int(1) + ["int"] => + int(-1) + ["number"] => + float(3.141593) + ["regexp"] => + regexp(/regexp/) + ["array"] => + array(3) { + [0] => + int(1) + [1] => + int(2) + [2] => + int(3) + } + ["object"] => + object(Object)#%d (1) { + ["field"] => + string(3) "foo" + } + ["function"] => + object(Closure)#%d { + function id(x) { return x; } + } + ["phpobject"] => + object(Foo)#%d (1) { + ["$field"] => + string(3) "php" + } +} +--- PHP var_dump of JS object ---- +object(V8Object)#6 (12) { + ["undefined"]=> NULL - \["null"\]\=\> + ["null"]=> NULL - \["bool"\]\=\> - bool\(true\) - \["string"\]\=\> - string\(6\) "string" - \["uint"\]\=\> - int\(1\) - \["int"\]\=\> - int\(\-1\) - \["number"\]\=\> - float\(3\.141592654\) - \["regexp"\]\=\> - object\(V8Object\)\#\d+ \(0\) \{ - \} - \["array"\]\=\> - array\(3\) \{ - \[0\]\=\> - int\(1\) - \[1\]\=\> - int\(2\) - \[2\]\=\> - int\(3\) - \} - \["object"\]\=\> - object\(V8Object\)\#\d+ \(1\) \{ - \["field"\]\=\> - string\(3\) "foo" - \} - \["function"\]\=\> - object\(V8Function\)\#\d+ \(0\) \{ - \} - \["phpobject"\]\=\> - object\(Foo\)\#\d+ \(1\) \{ - \["field"\]\=\> - string\(3\) "php" - \} -\} -\=\=\=EOF\=\=\= + ["bool"]=> + bool(true) + ["string"]=> + string(6) "string" + ["uint"]=> + int(1) + ["int"]=> + int(-1) + ["number"]=> + float(3.141592654) + ["regexp"]=> + object(V8Object)#7 (0) { + } + ["array"]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["object"]=> + object(V8Object)#8 (1) { + ["field"]=> + string(3) "foo" + } + ["function"]=> + object(V8Function)#9 (0) { + } + ["phpobject"]=> + object(Foo)#2 (1) { + ["field"]=> + string(3) "php" + } +} +===EOF=== diff --git a/tests/var_dump_php83.phpt b/tests/var_dump_php83.phpt new file mode 100644 index 00000000..e78c5fd5 --- /dev/null +++ b/tests/var_dump_php83.phpt @@ -0,0 +1,326 @@ +--TEST-- +Test V8::executeString() : var_dump +--SKIPIF-- += 80400) die('skip Only for php version < 8.4'); +?> +--INI-- +date.timezone=UTC +--FILE-- +obj = new Foo; + +$phptypes = $v8->phptypes = array( + "null" => NULL, + "bool" => true, + "string" => "string", + "uint" => 1, + "int" => -1, + "number" => 3.141592654, + "date" => new DateTime('September 27, 1976 09:00:00 UTC', new DateTimeZone('UTC')), + //"regexp" => new Regexp('/regexp/'), /* no native PHP regex type */ + "array" => array(1,2,3), + "object" => array( "field" => "foo" ), + "function" => (function ($x) { return $x; }), + "phpobject" => new Foo +); + +echo "---- PHP var_dump of PHP object ----\n"; +var_dump($phptypes); + +try { + var_dump($v8->executeString($JS, 'var_dump.js')); +} catch (V8JsScriptException $e) { + echo "Error!\n"; + var_dump($e); +} +?> +===EOF=== +--EXPECTREGEX-- +\-\-\-\- PHP var_dump of PHP object \-\-\-\- +array\(11\) \{ + \["null"\]\=\> + NULL + \["bool"\]\=\> + bool\(true\) + \["string"\]\=\> + string\(6\) "string" + \["uint"\]\=\> + int\(1\) + \["int"\]\=\> + int\(\-1\) + \["number"\]\=\> + float\(3\.141592654\) + \["date"\]\=\> + object\(DateTime\)\#\d+ \(3\) \{ + \["date"\]\=\> + string\(\d+\) "1976\-09\-27 09\:00\:00((\.0+)?)" + \["timezone_type"\]\=\> + int\(3\) + \["timezone"\]\=\> + string\(3\) "UTC" + \} + \["array"\]\=\> + array\(3\) \{ + \[0\]\=\> + int\(1\) + \[1\]\=\> + int\(2\) + \[2\]\=\> + int\(3\) + \} + \["object"\]\=\> + array\(1\) \{ + \["field"\]\=\> + string\(3\) "foo" + \} + \["function"\]\=\> + object\(Closure\)\#\d+ \(1\) \{ + \["parameter"\]\=\> + array\(1\) \{ + \["\$x"\]\=\> + string\(10\) "\" + \} + \} + \["phpobject"\]\=\> + object\(Foo\)\#\d+ \(1\) \{ + \["field"\]\=\> + string\(3\) "php" + \} +\} +\-\-\- JS var_dump of PHP object \-\-\-\- +array \(11\) \{ + \["null"\] \=\> + NULL + \["bool"\] \=\> + bool\(true\) + \["string"\] \=\> + string\(6\) "string" + \["uint"\] \=\> + int\(1\) + \["int"\] \=\> + int\(\-1\) + \["number"\] \=\> + float\(3\.141593\) + \["date"\] \=\> + object\(DateTime\)\#\d+ \(\d+\) \{(?: + \["createFromImmutable"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \})?(?: + \["createFromInterface"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \})? + \["createFromFormat"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["getLastErrors"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["format"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["modify"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["add"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["sub"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["getTimezone"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["setTimezone"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["getOffset"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["setTime"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["setDate"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["setISODate"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["setTimestamp"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["getTimestamp"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \} + \["diff"\] \=\> + object\(Closure\)\#\d+ \{ + function \(\) \{ \[native code\] \} + \}(?:(?:the following block is missing from PHP 7.4 on){0} + \["\$date"\] \=\> + string\(\d+\) "1976\-09\-27 09\:00\:00((\.0+)?)" + \["\$timezone_type"\] \=\> + int\(3\) + \["\$timezone"\] \=\> + string\(3\) "UTC" + )?\s*\} + \["array"\] \=\> + array\(3\) \{ + \[0\] \=\> + int\(1\) + \[1\] \=\> + int\(2\) + \[2\] \=\> + int\(3\) + \} + \["object"\] \=\> + array \(1\) \{ + \["field"\] \=\> + string\(3\) "foo" + \} + \["function"\] \=\> + object\(Closure\)\#\d+ \(0\) \{ + \} + \["phpobject"\] \=\> + object\(Foo\)\#\d+ \(1\) \{ + \["\$field"\] \=\> + string\(3\) "php" + \} +\} +\-\-\- JS var_dump of JS object \-\-\-\- +object\(Object\)\#\d+ \(12\) \{ + \["undefined"\] \=\> + NULL + \["null"\] \=\> + NULL + \["bool"\] \=\> + bool\(true\) + \["string"\] \=\> + string\(6\) "string" + \["uint"\] \=\> + int\(1\) + \["int"\] \=\> + int\(\-1\) + \["number"\] \=\> + float\(3\.141593\) + \["regexp"\] \=\> + regexp\(\/regexp\/\) + \["array"\] \=\> + array\(3\) \{ + \[0\] \=\> + int\(1\) + \[1\] \=\> + int\(2\) + \[2\] \=\> + int\(3\) + \} + \["object"\] \=\> + object\(Object\)\#\d+ \(1\) \{ + \["field"\] \=\> + string\(3\) "foo" + \} + \["function"\] \=\> + object\(Closure\)\#\d+ \{ + function id\(x\) \{ return x; \} + \} + \["phpobject"\] \=\> + object\(Foo\)\#\d+ \(1\) \{ + \["\$field"\] \=\> + string\(3\) "php" + \} +\} +\-\-\- PHP var_dump of JS object \-\-\-\- +object\(V8Object\)\#\d+ \(12\) \{ + \["undefined"\]\=\> + NULL + \["null"\]\=\> + NULL + \["bool"\]\=\> + bool\(true\) + \["string"\]\=\> + string\(6\) "string" + \["uint"\]\=\> + int\(1\) + \["int"\]\=\> + int\(\-1\) + \["number"\]\=\> + float\(3\.141592654\) + \["regexp"\]\=\> + object\(V8Object\)\#\d+ \(0\) \{ + \} + \["array"\]\=\> + array\(3\) \{ + \[0\]\=\> + int\(1\) + \[1\]\=\> + int\(2\) + \[2\]\=\> + int\(3\) + \} + \["object"\]\=\> + object\(V8Object\)\#\d+ \(1\) \{ + \["field"\]\=\> + string\(3\) "foo" + \} + \["function"\]\=\> + object\(V8Function\)\#\d+ \(0\) \{ + \} + \["phpobject"\]\=\> + object\(Foo\)\#\d+ \(1\) \{ + \["field"\]\=\> + string\(3\) "php" + \} +\} +\=\=\=EOF\=\=\= From 38c0d6b58b430160656c82cca4c51a8e64d65d20 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Thu, 9 Jan 2025 20:19:56 +0100 Subject: [PATCH 59/64] Fix tests/var_dump.phpt to not require certain build path, refs #541 --- tests/var_dump.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/var_dump.phpt b/tests/var_dump.phpt index 9097ca9e..13ca64ef 100644 --- a/tests/var_dump.phpt +++ b/tests/var_dump.phpt @@ -114,9 +114,9 @@ array(11) { ["function"]=> object(Closure)#4 (4) { ["name"]=> - string(45) "{closure:/tmp/php-v8js/tests/var_dump.php:51}" + string(%d) "{closure:%s/tests/var_dump.php:51}" ["file"]=> - string(32) "/tmp/php-v8js/tests/var_dump.php" + string(%d) "%s/tests/var_dump.php" ["line"]=> int(51) ["parameter"]=> From 00234b9dd836f0f012c18d9c0e3cf68689d36bf2 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Thu, 9 Jan 2025 20:20:39 +0100 Subject: [PATCH 60/64] (time_limit.phpt) increase loop length so time limit hits more likely on fast machines --- tests/time_limit.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/time_limit.phpt b/tests/time_limit.phpt index 4cef93f8..7d5dc994 100644 --- a/tests/time_limit.phpt +++ b/tests/time_limit.phpt @@ -13,7 +13,7 @@ if (getenv("SKIP_SLOW_TESTS")) { $JS = <<< EOT var text = "abcdefghijklmnopqrstuvwyxz0123456789"; -for (var i = 0; i < 10000000; ++i) { +for (var i = 0; i < 20000000; ++i) { var encoded = encodeURI(text); } EOT; From 5f813c583dd04d8a677a7efa355639f44d1fea63 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Thu, 9 Jan 2025 20:21:42 +0100 Subject: [PATCH 61/64] work-around failing test w/ alpine linux, calling setter callback twice --- tests/array_access_002.phpt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/array_access_002.phpt b/tests/array_access_002.phpt index 43d5b44a..685f9047 100644 --- a/tests/array_access_002.phpt +++ b/tests/array_access_002.phpt @@ -1,13 +1,7 @@ --TEST-- Test V8::executeString() : Use ArrayAccess with JavaScript native push method --SKIPIF-- - + --INI-- v8js.use_array_access = 1 --FILE-- @@ -16,6 +10,10 @@ v8js.use_array_access = 1 class MyArray implements ArrayAccess, Countable { private $data = Array('one', 'two', 'three'); + // V8 versions on alpine are known to call the setter twice. As a work-around we set a + // flag here and print only once, so we don't fail the test because of that. + private $setterCalled = false; + public function offsetExists($offset): bool { return isset($this->data[$offset]); } @@ -25,8 +23,13 @@ class MyArray implements ArrayAccess, Countable { } public function offsetSet(mixed $offset, mixed $value): void { + if ($this->setterCalled) { + return; + } + echo "set[$offset] = $value\n"; $this->data[$offset] = $value; + $this->setterCalled = true; } public function offsetUnset(mixed $offset): void { From 34badc638237ccaeb31c08ae41c03da57394ffe3 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Thu, 9 Jan 2025 20:53:41 +0100 Subject: [PATCH 62/64] (tests/var_dump_php83.phpt) improve readability, change from EXPECTREGEX back to EXPECTF --- tests/var_dump_php83.phpt | 484 +++++++++++++++++++------------------- 1 file changed, 239 insertions(+), 245 deletions(-) diff --git a/tests/var_dump_php83.phpt b/tests/var_dump_php83.phpt index e78c5fd5..7add9eaf 100644 --- a/tests/var_dump_php83.phpt +++ b/tests/var_dump_php83.phpt @@ -73,254 +73,248 @@ try { } ?> ===EOF=== ---EXPECTREGEX-- -\-\-\-\- PHP var_dump of PHP object \-\-\-\- -array\(11\) \{ - \["null"\]\=\> +--EXPECTF-- +---- PHP var_dump of PHP object ---- +array(11) { + ["null"]=> NULL - \["bool"\]\=\> - bool\(true\) - \["string"\]\=\> - string\(6\) "string" - \["uint"\]\=\> - int\(1\) - \["int"\]\=\> - int\(\-1\) - \["number"\]\=\> - float\(3\.141592654\) - \["date"\]\=\> - object\(DateTime\)\#\d+ \(3\) \{ - \["date"\]\=\> - string\(\d+\) "1976\-09\-27 09\:00\:00((\.0+)?)" - \["timezone_type"\]\=\> - int\(3\) - \["timezone"\]\=\> - string\(3\) "UTC" - \} - \["array"\]\=\> - array\(3\) \{ - \[0\]\=\> - int\(1\) - \[1\]\=\> - int\(2\) - \[2\]\=\> - int\(3\) - \} - \["object"\]\=\> - array\(1\) \{ - \["field"\]\=\> - string\(3\) "foo" - \} - \["function"\]\=\> - object\(Closure\)\#\d+ \(1\) \{ - \["parameter"\]\=\> - array\(1\) \{ - \["\$x"\]\=\> - string\(10\) "\" - \} - \} - \["phpobject"\]\=\> - object\(Foo\)\#\d+ \(1\) \{ - \["field"\]\=\> - string\(3\) "php" - \} -\} -\-\-\- JS var_dump of PHP object \-\-\-\- -array \(11\) \{ - \["null"\] \=\> + ["bool"]=> + bool(true) + ["string"]=> + string(6) "string" + ["uint"]=> + int(1) + ["int"]=> + int(-1) + ["number"]=> + float(3.141592654) + ["date"]=> + object(DateTime)#%d (3) { + ["date"]=> + string(%d) "1976-09-27 09:00:00%r(\.0+)?%r" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(3) "UTC" + } + ["array"]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["object"]=> + array(1) { + ["field"]=> + string(3) "foo" + } + ["function"]=> + object(Closure)#%d (1) { + ["parameter"]=> + array(1) { + ["$x"]=> + string(10) "" + } + } + ["phpobject"]=> + object(Foo)#%d (1) { + ["field"]=> + string(3) "php" + } +} +--- JS var_dump of PHP object ---- +array (11) { + ["null"] => NULL - \["bool"\] \=\> - bool\(true\) - \["string"\] \=\> - string\(6\) "string" - \["uint"\] \=\> - int\(1\) - \["int"\] \=\> - int\(\-1\) - \["number"\] \=\> - float\(3\.141593\) - \["date"\] \=\> - object\(DateTime\)\#\d+ \(\d+\) \{(?: - \["createFromImmutable"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \})?(?: - \["createFromInterface"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \})? - \["createFromFormat"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["getLastErrors"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["format"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["modify"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["add"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["sub"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["getTimezone"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setTimezone"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["getOffset"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setTime"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setDate"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setISODate"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["setTimestamp"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["getTimestamp"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \} - \["diff"\] \=\> - object\(Closure\)\#\d+ \{ - function \(\) \{ \[native code\] \} - \}(?:(?:the following block is missing from PHP 7.4 on){0} - \["\$date"\] \=\> - string\(\d+\) "1976\-09\-27 09\:00\:00((\.0+)?)" - \["\$timezone_type"\] \=\> - int\(3\) - \["\$timezone"\] \=\> - string\(3\) "UTC" - )?\s*\} - \["array"\] \=\> - array\(3\) \{ - \[0\] \=\> - int\(1\) - \[1\] \=\> - int\(2\) - \[2\] \=\> - int\(3\) - \} - \["object"\] \=\> - array \(1\) \{ - \["field"\] \=\> - string\(3\) "foo" - \} - \["function"\] \=\> - object\(Closure\)\#\d+ \(0\) \{ - \} - \["phpobject"\] \=\> - object\(Foo\)\#\d+ \(1\) \{ - \["\$field"\] \=\> - string\(3\) "php" - \} -\} -\-\-\- JS var_dump of JS object \-\-\-\- -object\(Object\)\#\d+ \(12\) \{ - \["undefined"\] \=\> + ["bool"] => + bool(true) + ["string"] => + string(6) "string" + ["uint"] => + int(1) + ["int"] => + int(-1) + ["number"] => + float(3.141593) + ["date"] => + object(DateTime)#%d (17) { + ["createFromImmutable"] => + object(Closure)#%d { + function () { [native code] } + } + ["createFromInterface"] => + object(Closure)#%d { + function () { [native code] } + } + ["createFromFormat"] => + object(Closure)#%d { + function () { [native code] } + } + ["getLastErrors"] => + object(Closure)#%d { + function () { [native code] } + } + ["format"] => + object(Closure)#%d { + function () { [native code] } + } + ["modify"] => + object(Closure)#%d { + function () { [native code] } + } + ["add"] => + object(Closure)#%d { + function () { [native code] } + } + ["sub"] => + object(Closure)#%d { + function () { [native code] } + } + ["getTimezone"] => + object(Closure)#%d { + function () { [native code] } + } + ["setTimezone"] => + object(Closure)#%d { + function () { [native code] } + } + ["getOffset"] => + object(Closure)#%d { + function () { [native code] } + } + ["setTime"] => + object(Closure)#%d { + function () { [native code] } + } + ["setDate"] => + object(Closure)#%d { + function () { [native code] } + } + ["setISODate"] => + object(Closure)#%d { + function () { [native code] } + } + ["setTimestamp"] => + object(Closure)#%d { + function () { [native code] } + } + ["getTimestamp"] => + object(Closure)#%d { + function () { [native code] } + } + ["diff"] => + object(Closure)#%d { + function () { [native code] } + } + } + ["array"] => + array(3) { + [0] => + int(1) + [1] => + int(2) + [2] => + int(3) + } + ["object"] => + array (1) { + ["field"] => + string(3) "foo" + } + ["function"] => + object(Closure)#%d (0) { + } + ["phpobject"] => + object(Foo)#%d (1) { + ["$field"] => + string(3) "php" + } +} +--- JS var_dump of JS object ---- +object(Object)#%d (12) { + ["undefined"] => NULL - \["null"\] \=\> + ["null"] => NULL - \["bool"\] \=\> - bool\(true\) - \["string"\] \=\> - string\(6\) "string" - \["uint"\] \=\> - int\(1\) - \["int"\] \=\> - int\(\-1\) - \["number"\] \=\> - float\(3\.141593\) - \["regexp"\] \=\> - regexp\(\/regexp\/\) - \["array"\] \=\> - array\(3\) \{ - \[0\] \=\> - int\(1\) - \[1\] \=\> - int\(2\) - \[2\] \=\> - int\(3\) - \} - \["object"\] \=\> - object\(Object\)\#\d+ \(1\) \{ - \["field"\] \=\> - string\(3\) "foo" - \} - \["function"\] \=\> - object\(Closure\)\#\d+ \{ - function id\(x\) \{ return x; \} - \} - \["phpobject"\] \=\> - object\(Foo\)\#\d+ \(1\) \{ - \["\$field"\] \=\> - string\(3\) "php" - \} -\} -\-\-\- PHP var_dump of JS object \-\-\-\- -object\(V8Object\)\#\d+ \(12\) \{ - \["undefined"\]\=\> + ["bool"] => + bool(true) + ["string"] => + string(6) "string" + ["uint"] => + int(1) + ["int"] => + int(-1) + ["number"] => + float(3.141593) + ["regexp"] => + regexp(/regexp/) + ["array"] => + array(3) { + [0] => + int(1) + [1] => + int(2) + [2] => + int(3) + } + ["object"] => + object(Object)#%d (1) { + ["field"] => + string(3) "foo" + } + ["function"] => + object(Closure)#%d { + function id(x) { return x; } + } + ["phpobject"] => + object(Foo)#%d (1) { + ["$field"] => + string(3) "php" + } +} +--- PHP var_dump of JS object ---- +object(V8Object)#%d (12) { + ["undefined"]=> NULL - \["null"\]\=\> + ["null"]=> NULL - \["bool"\]\=\> - bool\(true\) - \["string"\]\=\> - string\(6\) "string" - \["uint"\]\=\> - int\(1\) - \["int"\]\=\> - int\(\-1\) - \["number"\]\=\> - float\(3\.141592654\) - \["regexp"\]\=\> - object\(V8Object\)\#\d+ \(0\) \{ - \} - \["array"\]\=\> - array\(3\) \{ - \[0\]\=\> - int\(1\) - \[1\]\=\> - int\(2\) - \[2\]\=\> - int\(3\) - \} - \["object"\]\=\> - object\(V8Object\)\#\d+ \(1\) \{ - \["field"\]\=\> - string\(3\) "foo" - \} - \["function"\]\=\> - object\(V8Function\)\#\d+ \(0\) \{ - \} - \["phpobject"\]\=\> - object\(Foo\)\#\d+ \(1\) \{ - \["field"\]\=\> - string\(3\) "php" - \} -\} -\=\=\=EOF\=\=\= + ["bool"]=> + bool(true) + ["string"]=> + string(6) "string" + ["uint"]=> + int(1) + ["int"]=> + int(-1) + ["number"]=> + float(3.141592654) + ["regexp"]=> + object(V8Object)#%d (0) { + } + ["array"]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["object"]=> + object(V8Object)#%d (1) { + ["field"]=> + string(3) "foo" + } + ["function"]=> + object(V8Function)#%d (0) { + } + ["phpobject"]=> + object(Foo)#%d (1) { + ["field"]=> + string(3) "php" + } +} +===EOF=== From b4dc16083e9f8104964ad94f9b2fbc2a73abadb6 Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Thu, 9 Jan 2025 22:24:47 +0100 Subject: [PATCH 63/64] enable ci-build w/ php 8.4 --- .github/workflows/build-test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 0a59a38f..4f0e07c6 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -15,6 +15,9 @@ jobs: build: strategy: matrix: + # set in accordance with number of v8-versions, so caching can kick in properly + max-parallel: 2 + operating-system: - ubuntu-latest # - windows-latest @@ -23,7 +26,7 @@ jobs: # - '8.1' # - '8.2' - '8.3' -# - '8.4' + - '8.4' v8-versions: - 10.9.194 # - 11.9.172 From dde1c5a87bf702a6e43a432cd6295abd9867af2b Mon Sep 17 00:00:00 2001 From: Stefan Siegl Date: Thu, 9 Jan 2025 22:27:19 +0100 Subject: [PATCH 64/64] fix indentation. --- .github/workflows/build-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 4f0e07c6..e60dcfee 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -14,10 +14,10 @@ permissions: jobs: build: strategy: - matrix: - # set in accordance with number of v8-versions, so caching can kick in properly - max-parallel: 2 + # set in accordance with number of v8-versions, so caching can kick in properly + max-parallel: 2 + matrix: operating-system: - ubuntu-latest # - windows-latest