15
15
use crate :: {
16
16
classes:: { ClassEntry , RawVisibility , Visibility } ,
17
17
errors:: { throw, ArgumentCountError , ExceptionGuard , ThrowObject , Throwable } ,
18
+ modules:: global_module,
18
19
objects:: { StateObj , ZObj , ZObject } ,
19
20
strings:: { ZStr , ZString } ,
20
21
sys:: * ,
22
+ types:: TypeInfo ,
21
23
utils:: ensure_end_with_zero,
22
24
values:: { ExecuteData , ZVal } ,
23
25
} ;
24
26
use phper_alloc:: ToRefOwned ;
25
27
use std:: {
28
+ collections:: HashMap ,
26
29
ffi:: { CStr , CString } ,
27
30
marker:: PhantomData ,
28
- mem:: { transmute, zeroed, ManuallyDrop } ,
31
+ mem:: { size_of , transmute, zeroed, ManuallyDrop } ,
29
32
ptr:: { self , null_mut} ,
30
33
rc:: Rc ,
34
+ slice,
31
35
} ;
32
36
37
+ /// Used to mark the arguments obtained by the invoke function as mysterious
38
+ /// codes from phper
39
+ const INVOKE_MYSTERIOUS_CODE : & [ u8 ] = b"PHPER" ;
40
+
41
+ /// Used to find the handler in the invoke function.
42
+ pub ( crate ) type HandlerMap = HashMap < ( Option < CString > , CString ) , Rc < dyn Callable > > ;
43
+
33
44
pub ( crate ) trait Callable {
34
45
fn call ( & self , execute_data : & mut ExecuteData , arguments : & mut [ ZVal ] , return_value : & mut ZVal ) ;
35
46
}
@@ -107,6 +118,7 @@ impl FunctionEntry {
107
118
Self :: entry (
108
119
& entity. name ,
109
120
& entity. arguments ,
121
+ entity. return_type . as_ref ( ) ,
110
122
Some ( entity. handler . clone ( ) ) ,
111
123
None ,
112
124
)
@@ -116,20 +128,31 @@ impl FunctionEntry {
116
128
Self :: entry (
117
129
& entity. name ,
118
130
& entity. arguments ,
131
+ entity. return_type . as_ref ( ) ,
119
132
entity. handler . clone ( ) ,
120
133
Some ( entity. visibility ) ,
121
134
)
122
135
}
123
136
124
137
/// Will leak memory
125
138
unsafe fn entry (
126
- name : & CStr , arguments : & [ Argument ] , handler : Option < Rc < dyn Callable > > ,
127
- visibility : Option < RawVisibility > ,
139
+ name : & CStr , arguments : & [ Argument ] , return_type : Option < & ReturnType > ,
140
+ handler : Option < Rc < dyn Callable > > , visibility : Option < RawVisibility > ,
128
141
) -> zend_function_entry {
129
142
let mut infos = Vec :: new ( ) ;
130
143
131
144
let require_arg_count = arguments. iter ( ) . filter ( |arg| arg. required ) . count ( ) ;
132
- infos. push ( phper_zend_begin_arg_info_ex ( false , require_arg_count) ) ;
145
+
146
+ if let Some ( return_type) = return_type {
147
+ infos. push ( phper_zend_begin_arg_with_return_type_info_ex (
148
+ return_type. ret_by_ref ,
149
+ require_arg_count,
150
+ return_type. type_info . into_raw ( ) ,
151
+ return_type. allow_null ,
152
+ ) ) ;
153
+ } else {
154
+ infos. push ( phper_zend_begin_arg_info_ex ( false , require_arg_count) ) ;
155
+ }
133
156
134
157
for arg in arguments {
135
158
infos. push ( phper_zend_arg_info (
@@ -140,6 +163,9 @@ impl FunctionEntry {
140
163
141
164
infos. push ( zeroed :: < zend_internal_arg_info > ( ) ) ;
142
165
166
+ // Will be checked in `invoke` function.
167
+ infos. push ( Self :: create_mysterious_code ( ) ) ;
168
+
143
169
let raw_handler = handler. as_ref ( ) . map ( |_| invoke as _ ) ;
144
170
145
171
if let Some ( handler) = handler {
@@ -160,13 +186,22 @@ impl FunctionEntry {
160
186
flags,
161
187
}
162
188
}
189
+
190
+ unsafe fn create_mysterious_code ( ) -> zend_internal_arg_info {
191
+ let mut mysterious_code = [ 0u8 ; size_of :: < zend_internal_arg_info > ( ) ] ;
192
+ for ( i, n) in INVOKE_MYSTERIOUS_CODE . iter ( ) . enumerate ( ) {
193
+ mysterious_code[ i] = * n;
194
+ }
195
+ transmute ( mysterious_code)
196
+ }
163
197
}
164
198
165
199
/// Builder for registering php function.
166
200
pub struct FunctionEntity {
167
201
name : CString ,
168
202
handler : Rc < dyn Callable > ,
169
203
arguments : Vec < Argument > ,
204
+ return_type : Option < ReturnType > ,
170
205
}
171
206
172
207
impl FunctionEntity {
@@ -176,6 +211,7 @@ impl FunctionEntity {
176
211
name : ensure_end_with_zero ( name) ,
177
212
handler,
178
213
arguments : Default :: default ( ) ,
214
+ return_type : None ,
179
215
}
180
216
}
181
217
@@ -192,14 +228,22 @@ impl FunctionEntity {
192
228
self . arguments . extend ( arguments) ;
193
229
self
194
230
}
231
+
232
+ /// Add return type info.
233
+ #[ inline]
234
+ pub fn return_type ( & mut self , return_type : ReturnType ) -> & mut Self {
235
+ self . return_type = Some ( return_type) ;
236
+ self
237
+ }
195
238
}
196
239
197
240
/// Builder for registering class method.
198
241
pub struct MethodEntity {
199
- name : CString ,
200
- handler : Option < Rc < dyn Callable > > ,
242
+ pub ( crate ) name : CString ,
243
+ pub ( crate ) handler : Option < Rc < dyn Callable > > ,
201
244
arguments : Vec < Argument > ,
202
245
visibility : RawVisibility ,
246
+ return_type : Option < ReturnType > ,
203
247
}
204
248
205
249
impl MethodEntity {
@@ -212,6 +256,7 @@ impl MethodEntity {
212
256
handler,
213
257
visibility : visibility as RawVisibility ,
214
258
arguments : Default :: default ( ) ,
259
+ return_type : None ,
215
260
}
216
261
}
217
262
@@ -240,6 +285,13 @@ impl MethodEntity {
240
285
self . arguments . extend ( arguments) ;
241
286
self
242
287
}
288
+
289
+ /// Add return type info.
290
+ #[ inline]
291
+ pub fn return_type ( & mut self , return_type : ReturnType ) -> & mut Self {
292
+ self . return_type = Some ( return_type) ;
293
+ self
294
+ }
243
295
}
244
296
245
297
/// Function or method argument info.
@@ -291,6 +343,42 @@ impl Argument {
291
343
}
292
344
}
293
345
346
+ /// Function or method return type.
347
+ pub struct ReturnType {
348
+ type_info : TypeInfo ,
349
+ ret_by_ref : bool ,
350
+ allow_null : bool ,
351
+ }
352
+
353
+ impl ReturnType {
354
+ /// Indicate the return type is return by value.
355
+ #[ inline]
356
+ pub fn by_val ( type_info : TypeInfo ) -> Self {
357
+ Self {
358
+ type_info,
359
+ ret_by_ref : false ,
360
+ allow_null : false ,
361
+ }
362
+ }
363
+
364
+ /// Indicate the return type is return by reference.
365
+ #[ inline]
366
+ pub fn by_ref ( type_info : TypeInfo ) -> Self {
367
+ Self {
368
+ type_info,
369
+ ret_by_ref : true ,
370
+ allow_null : false ,
371
+ }
372
+ }
373
+
374
+ /// Indicate the return type can be null.
375
+ #[ inline]
376
+ pub fn allow_null ( mut self ) -> Self {
377
+ self . allow_null = true ;
378
+ self
379
+ }
380
+ }
381
+
294
382
/// Wrapper of [`zend_function`].
295
383
#[ repr( transparent) ]
296
384
pub struct ZFunc {
@@ -447,12 +535,43 @@ unsafe extern "C" fn invoke(execute_data: *mut zend_execute_data, return_value:
447
535
let num_args = execute_data. common_num_args ( ) ;
448
536
let arg_info = execute_data. common_arg_info ( ) ;
449
537
450
- let last_arg_info = arg_info. offset ( ( num_args + 1 ) as isize ) ;
451
- let translator = CallableTranslator {
452
- arg_info : * last_arg_info,
538
+ // should be mysterious code
539
+ let mysterious_arg_info = arg_info. offset ( ( num_args + 1 ) as isize ) ;
540
+ let mysterious_code = slice:: from_raw_parts (
541
+ mysterious_arg_info as * const u8 ,
542
+ INVOKE_MYSTERIOUS_CODE . len ( ) ,
543
+ ) ;
544
+
545
+ let handler = if mysterious_code == INVOKE_MYSTERIOUS_CODE {
546
+ // hiddden real handler
547
+ let last_arg_info = arg_info. offset ( ( num_args + 2 ) as isize ) ;
548
+ let translator = CallableTranslator {
549
+ arg_info : * last_arg_info,
550
+ } ;
551
+ let handler = translator. callable ;
552
+ handler. as_ref ( ) . expect ( "handler is null" )
553
+ } else {
554
+ let function_name = execute_data
555
+ . func ( )
556
+ . get_function_name ( )
557
+ . and_then ( |name| name. to_c_str ( ) . ok ( ) )
558
+ . map ( CString :: from) ;
559
+
560
+ function_name
561
+ . and_then ( |function_name| {
562
+ let class_name = execute_data
563
+ . func ( )
564
+ . get_class ( )
565
+ . and_then ( |cls| cls. get_name ( ) . to_c_str ( ) . ok ( ) )
566
+ . map ( CString :: from) ;
567
+
568
+ global_module ( )
569
+ . handler_map
570
+ . get ( & ( class_name, function_name) )
571
+ } )
572
+ . expect ( "invoke handler is not correct" )
573
+ . as_ref ( )
453
574
} ;
454
- let handler = translator. callable ;
455
- let handler = handler. as_ref ( ) . expect ( "handler is null" ) ;
456
575
457
576
// Check arguments count.
458
577
let num_args = execute_data. num_args ( ) ;
0 commit comments