@@ -51,6 +51,40 @@ static ir_ref zend_jit_ffi_guard(zend_jit_ctx *jit,
51
51
zend_ffi_type * ffi_type ,
52
52
zend_jit_ffi_info * ffi_info );
53
53
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
+
54
88
static int zend_jit_ffi_init_call_sym (zend_jit_ctx * jit ,
55
89
const zend_op * opline ,
56
90
const zend_op_array * op_array ,
@@ -349,10 +383,135 @@ static int zend_jit_ffi_send_val(zend_jit_ctx *jit,
349
383
} else if (opline -> op2 .num == 2 ) {
350
384
ZEND_ASSERT (opline -> op1_type == IS_CONST );
351
385
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 );
353
388
ZEND_ASSERT (opline -> op1_type == IS_CONST );
354
389
SET_STACK_TYPE (stack , 2 , zend_is_true (RT_CONSTANT (opline , opline -> op1 )) ? IS_TRUE : IS_FALSE , 0 );
355
390
}
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
+ }
356
515
} else if (TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_TYPE ) {
357
516
ZEND_ASSERT (opline -> op2 .num == 1 );
358
517
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,
811
970
flags |= ZEND_FFI_FLAG_PERSISTENT ;
812
971
}
813
972
// 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 );
829
974
ref = ir_CALL_2 (IR_ADDR , ir_CONST_FUNC (zend_ffi_api -> cdata_create ), ref , ir_CONST_ADDR (type ));
830
975
ir_STORE (ir_ADD_OFFSET (ref , offsetof(zend_ffi_cdata , flags )), ir_CONST_U32 (flags ));
831
976
jit_set_Z_PTR (jit , res_addr , ref );
832
977
jit_set_Z_TYPE_INFO (jit , res_addr , IS_OBJECT_EX );
833
978
}
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
+ }
834
989
} else if (TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_TYPE ) {
835
990
if (res_addr ) {
836
991
ref = ir_CONST_ADDR (type );
@@ -1060,6 +1215,7 @@ static int zend_jit_ffi_do_call(zend_jit_ctx *jit,
1060
1215
1061
1216
if (!TRACE_FRAME_FFI_FUNC (call )
1062
1217
|| TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_NEW
1218
+ || TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_CAST
1063
1219
|| TRACE_FRAME_FFI_FUNC (call ) == TRACE_FRAME_FFI_FUNC_TYPE ) {
1064
1220
func_ref = (intptr_t )(void * )call -> ce ;
1065
1221
if (func_ref && !IR_IS_CONST_REF (func_ref )) {
0 commit comments