@@ -51,6 +51,40 @@ static ir_ref zend_jit_ffi_guard(zend_jit_ctx *jit,
5151 zend_ffi_type * ffi_type ,
5252 zend_jit_ffi_info * ffi_info );
5353
54+ static int zend_jit_ffi_write (zend_jit_ctx * jit ,
55+ zend_ffi_type * ffi_type ,
56+ ir_ref ptr ,
57+ uint32_t val_info ,
58+ zend_jit_addr val_addr ,
59+ zend_ffi_type * val_ffi_type ,
60+ zend_jit_addr res_addr );
61+
62+ static ir_ref zend_jit_calloc (zend_jit_ctx * jit ,
63+ size_t size ,
64+ bool persistent ,
65+ const zend_op * opline ,
66+ const zend_op_array * op_array )
67+ {
68+ ir_ref ref ;
69+
70+ if (persistent ) {
71+ ref = ir_CALL_2 (IR_ADDR , ir_CONST_FUNC (calloc ), ir_CONST_LONG (1 ), ir_CONST_ADDR (size ));
72+ } else {
73+ #if ZEND_DEBUG
74+ ref = ir_CALL_6 (IR_ADDR , ir_CONST_FC_FUNC (_ecalloc ),
75+ ir_CONST_LONG (1 ),
76+ ir_CONST_ADDR (size ),
77+ op_array -> filename ? ir_CONST_ADDR (op_array -> filename -> val ) : IR_NULL ,
78+ ir_CONST_U32 (opline ? opline -> lineno : 0 ),
79+ IR_NULL ,
80+ ir_CONST_U32 (0 ));
81+ #else
82+ ref = ir_CALL_2 (IR_ADDR , ir_CONST_FC_FUNC (_ecalloc ), ir_CONST_LONG (1 ), ir_CONST_ADDR (size ));
83+ #endif
84+ }
85+ return ref ;
86+ }
87+
5488static int zend_jit_ffi_init_call_sym (zend_jit_ctx * jit ,
5589 const zend_op * opline ,
5690 const zend_op_array * op_array ,
@@ -349,10 +383,135 @@ static int zend_jit_ffi_send_val(zend_jit_ctx *jit,
349383 } else if (opline -> op2 .num == 2 ) {
350384 ZEND_ASSERT (opline -> op1_type == IS_CONST );
351385 SET_STACK_TYPE (stack , 1 , zend_is_true (RT_CONSTANT (opline , opline -> op1 )) ? IS_TRUE : IS_FALSE , 0 );
352- } else if (opline -> op2 .num == 3 ) {
386+ } else {
387+ ZEND_ASSERT (opline -> op2 .num == 3 );
353388 ZEND_ASSERT (opline -> op1_type == IS_CONST );
354389 SET_STACK_TYPE (stack , 2 , zend_is_true (RT_CONSTANT (opline , opline -> op1 )) ? IS_TRUE : IS_FALSE , 0 );
355390 }
391+ } else if (TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_CAST ) {
392+ if (opline -> op2 .num == 1 ) {
393+ if (op1_ffi_type && (opline -> op1_type & (IS_VAR |IS_TMP_VAR ))) {
394+ arg_flags |= ZREG_FFI_ZVAL_DTOR ;
395+ if (op1_info & MAY_BE_REF ) {
396+ arg_flags |= ZREG_FFI_ZVAL_DEREF ;
397+ }
398+ ref = jit_Z_PTR (jit , op1_addr );
399+ SET_STACK_TYPE (stack , 0 , IS_OBJECT , 0 );
400+ SET_STACK_REF_EX (stack , 0 , ref , arg_flags );
401+ }
402+ } else {
403+ ZEND_ASSERT (opline -> op2 .num == 2 );
404+
405+ /* Call FFI::cast() right here and pass result */
406+ if (op1_ffi_type ) {
407+
408+ ref = jit_Z_PTR (jit , op1_addr );
409+ if (op1_info & MAY_BE_REF ) {
410+ ir_ref if_ref = ir_IF (ir_EQ (jit_Z_TYPE (jit , op1_addr ), ir_CONST_U8 (IS_REFERENCE )));
411+ ir_IF_TRUE (if_ref );
412+ ir_ref ref2 = jit_Z_PTR_ref (jit , ir_ADD_OFFSET (ref , offsetof(zend_reference , val )));
413+ ir_MERGE_WITH_EMPTY_FALSE (if_ref );
414+ ref = ir_PHI_2 (IR_ADDR , ref2 , ref );
415+ }
416+
417+ if (op1_ffi_type -> kind == ZEND_FFI_TYPE_POINTER
418+ && type -> kind != ZEND_FFI_TYPE_POINTER
419+ && ZEND_FFI_TYPE (op1_ffi_type -> pointer .type )-> kind == ZEND_FFI_TYPE_VOID ) {
420+ /* automatically dereference void* pointers ??? */
421+ // JIT: cdata->ptr = *(void**)arg->ptr
422+ ref = ir_LOAD_A (jit_FFI_CDATA_PTR (jit , ref ));
423+ ref = ir_CALL_2 (IR_ADDR , ir_CONST_FUNC (zend_ffi_api -> cdata_create ), ref , ir_CONST_ADDR (type ));
424+ } else if (op1_ffi_type -> kind == ZEND_FFI_TYPE_ARRAY
425+ && type -> kind == ZEND_FFI_TYPE_POINTER
426+ && zend_ffi_api -> is_compatible_type (ZEND_FFI_TYPE (op1_ffi_type -> array .type ), ZEND_FFI_TYPE (type -> pointer .type ))) {
427+ ref = ir_CALL_2 (IR_ADDR , ir_CONST_FC_FUNC (zend_jit_ffi_create_ptr ),
428+ ir_CONST_ADDR (type ), jit_FFI_CDATA_PTR (jit , ref ));
429+ SET_STACK_TYPE (stack , 1 , IS_OBJECT , 0 );
430+ SET_STACK_REF_EX (stack , 1 , ref , 0 );
431+ } else if (op1_ffi_type -> kind == ZEND_FFI_TYPE_POINTER
432+ && type -> kind == ZEND_FFI_TYPE_ARRAY
433+ && zend_ffi_api -> is_compatible_type (ZEND_FFI_TYPE (op1_ffi_type -> pointer .type ), ZEND_FFI_TYPE (type -> array .type ))) {
434+ // JIT: cdata->ptr = *arg->ptr;
435+ ref = ir_LOAD_A (jit_FFI_CDATA_PTR (jit , ref ));
436+ ref = ir_CALL_2 (IR_ADDR , ir_CONST_FUNC (zend_ffi_api -> cdata_create ), ref , ir_CONST_ADDR (type ));
437+ } else if (type -> size > op1_ffi_type -> size ) {
438+ ZEND_ASSERT (type -> size <= op1_ffi_type -> size );
439+ } else {
440+ // TODO: holder usage ???
441+ ref = jit_FFI_CDATA_PTR (jit , ref );
442+ ref = ir_CALL_2 (IR_ADDR , ir_CONST_FUNC (zend_ffi_api -> cdata_create ), ref , ir_CONST_ADDR (type ));
443+ }
444+ SET_STACK_TYPE (stack , 1 , IS_OBJECT , 0 );
445+ SET_STACK_REF_EX (stack , 1 , ref , 0 );
446+ if (opline -> op1_type & (IS_VAR |IS_TMP_VAR )) {
447+ /* release argument and transfer ownweship */
448+ ir_ref src = jit_Z_PTR (jit , op1_addr );
449+
450+ // JIT: if (!GC_DELREF(src))
451+ ir_ref if_not_zero = ir_IF (jit_GC_DELREF (jit , src ));
452+ ir_IF_FALSE (if_not_zero );
453+
454+ // JIT: if (Z_TYPE_P(arg) == IS_REFERENCE)
455+ ir_ref if_ref = ir_IF (ir_EQ (jit_Z_TYPE (jit , op1_addr ), ir_CONST_U8 (IS_REFERENCE )));
456+ ir_IF_TRUE (if_ref );
457+
458+ // JIT: arg = Z_PTR(Z_REFVAL_P(arg));
459+ ir_ref src_obj = jit_Z_PTR_ref (jit , ir_ADD_OFFSET (src , offsetof(zend_reference , val )));
460+
461+ // JIT: if (GC_REFCOUNT(arg_obj) == 1)
462+ ir_ref if_one = ir_IF (ir_EQ (jit_GC_REFCOUNT (jit , src_obj ), ir_CONST_U32 (1 )));
463+ ir_IF_TRUE (if_one );
464+ ir_MERGE_WITH_EMPTY_FALSE (if_ref );
465+ src_obj = ir_PHI_2 (IR_ADDR , src_obj , src );
466+
467+ // JIT: if (old_cdata->flags & ZEND_FFI_FLAG_OWNED)
468+ ir_ref a = ir_ADD_OFFSET (src_obj , offsetof(zend_ffi_cdata , flags ));
469+ ir_ref f = ir_LOAD_U32 (a );
470+ ir_ref if_owned = ir_IF (ir_AND_U32 (f , ir_CONST_U32 (ZEND_FFI_FLAG_OWNED )));
471+ ir_IF_TRUE (if_owned );
472+
473+ /* transfer ownership */
474+ // JIT: old_cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
475+ ir_STORE (a , ir_AND_U32 (f , ir_CONST_U32 (~ZEND_FFI_FLAG_OWNED )));
476+ // JIT: cdata->flags |= ZEND_FFI_FLAG_OWNED;
477+ a = ir_ADD_OFFSET (ref , offsetof(zend_ffi_cdata , flags ));
478+ ir_STORE (a , ir_OR_U32 (ir_LOAD_U32 (a ), ir_CONST_U32 (ZEND_FFI_FLAG_OWNED )));
479+
480+ ir_MERGE_WITH_EMPTY_FALSE (if_owned );
481+ ir_MERGE_WITH_EMPTY_FALSE (if_one );
482+
483+ /* release */
484+ jit_ZVAL_DTOR (jit , src , op1_info , opline );
485+ ir_MERGE_WITH_EMPTY_TRUE (if_not_zero );
486+ }
487+ } else if (type -> kind < ZEND_FFI_TYPE_POINTER ) {
488+ /* numeric conversion */
489+ ref = zend_jit_calloc (jit , type -> size , 0 , opline , op_array );
490+ if (!zend_jit_ffi_write (jit , type , ref , op1_info , op1_addr , op1_ffi_type , 0 )) {
491+ return 0 ;
492+ }
493+ ref = ir_CALL_2 (IR_ADDR , ir_CONST_FUNC (zend_ffi_api -> cdata_create ), ref , ir_CONST_ADDR (type ));
494+ ir_STORE (ir_ADD_OFFSET (ref , offsetof(zend_ffi_cdata , flags )), ir_CONST_U32 (ZEND_FFI_FLAG_OWNED ));
495+ SET_STACK_TYPE (stack , 1 , IS_OBJECT , 0 );
496+ SET_STACK_REF_EX (stack , 1 , ref , 0 );
497+ } else if (type -> kind == ZEND_FFI_TYPE_POINTER ) {
498+ if ((op1_info & (MAY_BE_REF |MAY_BE_ANY |MAY_BE_UNDEF )) == MAY_BE_NULL ) {
499+ ref = ir_CALL_2 (IR_ADDR , ir_CONST_FC_FUNC (zend_jit_ffi_create_ptr ),
500+ ir_CONST_ADDR (type ), IR_NULL );
501+ SET_STACK_TYPE (stack , 1 , IS_OBJECT , 0 );
502+ SET_STACK_REF_EX (stack , 1 , ref , 0 );
503+ } else if ((op1_info & (MAY_BE_REF |MAY_BE_ANY |MAY_BE_UNDEF )) == MAY_BE_LONG ) {
504+ ref = ir_CALL_2 (IR_ADDR , ir_CONST_FC_FUNC (zend_jit_ffi_create_ptr ),
505+ ir_CONST_ADDR (type ), jit_Z_LVAL (jit , op1_addr ));
506+ SET_STACK_TYPE (stack , 1 , IS_OBJECT , 0 );
507+ SET_STACK_REF_EX (stack , 1 , ref , 0 );
508+ } else {
509+ ZEND_UNREACHABLE ();
510+ }
511+ } else {
512+ ZEND_UNREACHABLE ();
513+ }
514+ }
356515 } else if (TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_TYPE ) {
357516 ZEND_ASSERT (opline -> op2 .num == 1 );
358517 if (op1_ffi_type && (opline -> op1_type & (IS_VAR |IS_TMP_VAR ))) {
@@ -811,26 +970,22 @@ static int zend_jit_ffi_do_call(zend_jit_ctx *jit,
811970 flags |= ZEND_FFI_FLAG_PERSISTENT ;
812971 }
813972 // TODO: ZEND_FFI_FLAG_CONST flag ???
814- if (flags & ZEND_FFI_FLAG_PERSISTENT ) {
815- ref = ir_CALL_2 (IR_ADDR , ir_CONST_FUNC (calloc ), ir_CONST_LONG (1 ), ir_CONST_ADDR (type -> size ));
816- } else {
817- #if ZEND_DEBUG
818- ref = ir_CALL_6 (IR_ADDR , ir_CONST_FC_FUNC (_ecalloc ),
819- ir_CONST_LONG (1 ),
820- ir_CONST_ADDR (type -> size ),
821- op_array -> filename ? ir_CONST_ADDR (op_array -> filename -> val ) : IR_NULL ,
822- ir_CONST_U32 (opline ? opline -> lineno : 0 ),
823- IR_NULL ,
824- ir_CONST_U32 (0 ));
825- #else
826- ref = ir_CALL_2 (IR_ADDR , ir_CONST_FC_FUNC (_ecalloc ), ir_CONST_LONG (1 ), ir_CONST_ADDR (type -> size ));
827- #endif
828- }
973+ ref = zend_jit_calloc (jit , type -> size , (flags & ZEND_FFI_FLAG_PERSISTENT ) != 0 , opline , op_array );
829974 ref = ir_CALL_2 (IR_ADDR , ir_CONST_FUNC (zend_ffi_api -> cdata_create ), ref , ir_CONST_ADDR (type ));
830975 ir_STORE (ir_ADD_OFFSET (ref , offsetof(zend_ffi_cdata , flags )), ir_CONST_U32 (flags ));
831976 jit_set_Z_PTR (jit , res_addr , ref );
832977 jit_set_Z_TYPE_INFO (jit , res_addr , IS_OBJECT_EX );
833978 }
979+ } else if (TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_CAST ) {
980+ ZEND_ASSERT (STACK_TYPE (stack , 1 ) == IS_OBJECT );
981+ ref = STACK_REF (stack , 1 );
982+ if (res_addr ) {
983+ jit_set_Z_PTR (jit , res_addr , ref );
984+ jit_set_Z_TYPE_INFO (jit , res_addr , IS_OBJECT_EX );
985+ } else {
986+ // TODO: release object ???
987+ ZEND_UNREACHABLE ();
988+ }
834989 } else if (TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_TYPE ) {
835990 if (res_addr ) {
836991 ref = ir_CONST_ADDR (type );
@@ -1060,6 +1215,7 @@ static int zend_jit_ffi_do_call(zend_jit_ctx *jit,
10601215
10611216 if (!TRACE_FRAME_FFI_FUNC (call )
10621217 || TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_NEW
1218+ || TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_CAST
10631219 || TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_TYPE ) {
10641220 func_ref = (intptr_t )(void * )call -> ce ;
10651221 if (func_ref && !IR_IS_CONST_REF (func_ref )) {
0 commit comments