@@ -1345,6 +1345,193 @@ static void ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic(zend_object *zobj, intpt
13451345 zend_jit_fetch_obj_is_slow (zobj , offset , result , cache_slot );
13461346}
13471347
1348+ static zend_always_inline zend_bool promotes_to_array (zval * val ) {
1349+ return Z_TYPE_P (val ) <= IS_FALSE
1350+ || (Z_ISREF_P (val ) && Z_TYPE_P (Z_REFVAL_P (val )) <= IS_FALSE );
1351+ }
1352+
1353+ static zend_always_inline zend_bool check_type_array_assignable (zend_type type ) {
1354+ if (!ZEND_TYPE_IS_SET (type )) {
1355+ return 1 ;
1356+ }
1357+ return (ZEND_TYPE_FULL_MASK (type ) & (MAY_BE_ITERABLE |MAY_BE_ARRAY )) != 0 ;
1358+ }
1359+
1360+ static zend_property_info * zend_object_fetch_property_type_info (
1361+ zend_object * obj , zval * slot )
1362+ {
1363+ if (EXPECTED (!ZEND_CLASS_HAS_TYPE_HINTS (obj -> ce ))) {
1364+ return NULL ;
1365+ }
1366+
1367+ /* Not a declared property */
1368+ if (UNEXPECTED (slot < obj -> properties_table ||
1369+ slot >= obj -> properties_table + obj -> ce -> default_properties_count )) {
1370+ return NULL ;
1371+ }
1372+
1373+ return zend_get_typed_property_info_for_slot (obj , slot );
1374+ }
1375+
1376+ static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_prop_error (zend_property_info * prop , const char * type ) {
1377+ zend_string * type_str = zend_type_to_string (prop -> type );
1378+ zend_type_error (
1379+ "Cannot auto-initialize an %s inside property %s::$%s of type %s" ,
1380+ type ,
1381+ ZSTR_VAL (prop -> ce -> name ), zend_get_unmangled_property_name (prop -> name ),
1382+ ZSTR_VAL (type_str )
1383+ );
1384+ zend_string_release (type_str );
1385+ }
1386+
1387+ static zend_never_inline ZEND_COLD void zend_throw_access_uninit_prop_by_ref_error (
1388+ zend_property_info * prop ) {
1389+ zend_throw_error (NULL ,
1390+ "Cannot access uninitialized non-nullable property %s::$%s by reference" ,
1391+ ZSTR_VAL (prop -> ce -> name ),
1392+ zend_get_unmangled_property_name (prop -> name ));
1393+ }
1394+
1395+ static zend_never_inline zend_bool zend_handle_fetch_obj_flags (
1396+ zval * result , zval * ptr , zend_object * obj , zend_property_info * prop_info , uint32_t flags )
1397+ {
1398+ switch (flags ) {
1399+ case ZEND_FETCH_DIM_WRITE :
1400+ if (promotes_to_array (ptr )) {
1401+ if (!prop_info ) {
1402+ prop_info = zend_object_fetch_property_type_info (obj , ptr );
1403+ if (!prop_info ) {
1404+ break ;
1405+ }
1406+ }
1407+ if (!check_type_array_assignable (prop_info -> type )) {
1408+ zend_throw_auto_init_in_prop_error (prop_info , "array" );
1409+ if (result ) ZVAL_ERROR (result );
1410+ return 0 ;
1411+ }
1412+ }
1413+ break ;
1414+ case ZEND_FETCH_REF :
1415+ if (Z_TYPE_P (ptr ) != IS_REFERENCE ) {
1416+ if (!prop_info ) {
1417+ prop_info = zend_object_fetch_property_type_info (obj , ptr );
1418+ if (!prop_info ) {
1419+ break ;
1420+ }
1421+ }
1422+ if (Z_TYPE_P (ptr ) == IS_UNDEF ) {
1423+ if (!ZEND_TYPE_ALLOW_NULL (prop_info -> type )) {
1424+ zend_throw_access_uninit_prop_by_ref_error (prop_info );
1425+ if (result ) ZVAL_ERROR (result );
1426+ return 0 ;
1427+ }
1428+ ZVAL_NULL (ptr );
1429+ }
1430+
1431+ ZVAL_NEW_REF (ptr , ptr );
1432+ ZEND_REF_ADD_TYPE_SOURCE (Z_REF_P (ptr ), prop_info );
1433+ }
1434+ break ;
1435+ EMPTY_SWITCH_DEFAULT_CASE ()
1436+ }
1437+ return 1 ;
1438+ }
1439+
1440+ static void ZEND_FASTCALL zend_jit_fetch_obj_w_slow (zend_object * zobj , zval * offset , zval * result , uint32_t cache_slot )
1441+ {
1442+ zval * retval ;
1443+ zend_execute_data * execute_data = EG (current_execute_data );
1444+ const zend_op * opline = execute_data -> opline ;
1445+ zend_string * name , * tmp_name ;
1446+
1447+ name = zval_get_tmp_string (offset , & tmp_name );
1448+ retval = zobj -> handlers -> get_property_ptr_ptr (zobj , name , BP_VAR_W , CACHE_ADDR (cache_slot ));
1449+ if (NULL == retval ) {
1450+ retval = zobj -> handlers -> read_property (zobj , name , BP_VAR_W , CACHE_ADDR (cache_slot ), result );
1451+ if (retval == result ) {
1452+ if (UNEXPECTED (Z_ISREF_P (retval ) && Z_REFCOUNT_P (retval ) == 1 )) {
1453+ ZVAL_UNREF (retval );
1454+ }
1455+ goto end ;
1456+ }
1457+ } else if (UNEXPECTED (Z_ISERROR_P (retval ))) {
1458+ ZVAL_ERROR (result );
1459+ goto end ;
1460+ }
1461+
1462+ ZVAL_INDIRECT (result , retval );
1463+
1464+ /* Support for typed properties */
1465+ do {
1466+ uint32_t flags = opline -> extended_value & ZEND_FETCH_OBJ_FLAGS ;
1467+
1468+ if (flags ) {
1469+ zend_property_info * prop_info = NULL ;
1470+
1471+ if (opline -> op2_type == IS_CONST ) {
1472+ prop_info = CACHED_PTR_EX (CACHE_ADDR (cache_slot ) + 2 );
1473+ if (!prop_info ) {
1474+ break ;
1475+ }
1476+ }
1477+ if (UNEXPECTED (!zend_handle_fetch_obj_flags (result , retval , zobj , prop_info , flags ))) {
1478+ goto end ;
1479+ }
1480+ }
1481+ } while (0 );
1482+
1483+ if (UNEXPECTED (Z_TYPE_P (retval ) == IS_UNDEF )) {
1484+ ZVAL_NULL (retval );
1485+ }
1486+
1487+ end :
1488+ zend_tmp_string_release (tmp_name );
1489+ }
1490+
1491+ static void ZEND_FASTCALL zend_jit_check_array_promotion (zval * val , zend_property_info * prop )
1492+ {
1493+ zend_execute_data * execute_data = EG (current_execute_data );
1494+ const zend_op * opline = execute_data -> opline ;
1495+ zval * result = EX_VAR (opline -> result .var );
1496+
1497+ if (((Z_TYPE_P (val ) <= IS_FALSE
1498+ || (Z_ISREF_P (val ) && Z_TYPE_P (Z_REFVAL_P (val )) <= IS_FALSE ))
1499+ && ZEND_TYPE_IS_SET (prop -> type )
1500+ && ZEND_TYPE_FULL_MASK (prop -> type ) & (MAY_BE_ITERABLE |MAY_BE_ARRAY )) == 0 ) {
1501+ zend_string * type_str = zend_type_to_string (prop -> type );
1502+ zend_type_error (
1503+ "Cannot auto-initialize an array inside property %s::$%s of type %s" ,
1504+ ZSTR_VAL (prop -> ce -> name ), zend_get_unmangled_property_name (prop -> name ),
1505+ ZSTR_VAL (type_str )
1506+ );
1507+ zend_string_release (type_str );
1508+ ZVAL_ERROR (result );
1509+ } else {
1510+ ZVAL_INDIRECT (result , val );
1511+ }
1512+ }
1513+
1514+ static void ZEND_FASTCALL zend_jit_create_typed_ref (zval * val , zend_property_info * prop , zval * result )
1515+ {
1516+ if (!Z_ISREF_P (val )) {
1517+ ZVAL_NEW_REF (val , val );
1518+ ZEND_REF_ADD_TYPE_SOURCE (Z_REF_P (val ), prop );
1519+ }
1520+ ZVAL_INDIRECT (result , val );
1521+ }
1522+
1523+ static void ZEND_FASTCALL zend_jit_extract_helper (zend_refcounted * garbage )
1524+ {
1525+ zend_execute_data * execute_data = EG (current_execute_data );
1526+ const zend_op * opline = execute_data -> opline ;
1527+ zval * zv = EX_VAR (opline -> result .var );
1528+
1529+ if (EXPECTED (Z_TYPE_P (zv ) == IS_INDIRECT )) {
1530+ ZVAL_COPY (zv , Z_INDIRECT_P (zv ));
1531+ }
1532+ rc_dtor_func (garbage );
1533+ }
1534+
13481535static void ZEND_FASTCALL zend_jit_vm_stack_free_args_helper (zend_execute_data * call )
13491536{
13501537 zend_vm_stack_free_args (call );
@@ -1508,6 +1695,13 @@ static void ZEND_FASTCALL zend_jit_invalid_property_read(zval *container, const
15081695 zend_error (E_WARNING , "Attempt to read property '%s' on %s" , property_name , zend_zval_type_name (container ));
15091696}
15101697
1698+ static void ZEND_FASTCALL zend_jit_invalid_property_write (zval * container , const char * property_name )
1699+ {
1700+ zend_throw_error (NULL ,
1701+ "Attempt to modify property '%s' on %s" ,
1702+ property_name , zend_zval_type_name (container ));
1703+ }
1704+
15111705static zval * ZEND_FASTCALL zend_jit_prepare_assign_dim_ref (zval * ref ) {
15121706 zval * val = Z_REFVAL_P (ref );
15131707 if (Z_TYPE_P (val ) <= IS_FALSE ) {
0 commit comments