flush
[m6w6/ext-psi] / src / compiler.c
1 #include <stdlib.h>
2
3 #include <jit/jit.h>
4
5 #include <php.h>
6 #include <Zend/zend_API.h>
7
8 #include "compiler.h"
9
10 PSI_Compiler *PSI_CompilerInit(PSI_Compiler *C, PSI_Validator *V, void *context)
11 {
12 if (!C) {
13 C = malloc(sizeof(*C));
14 }
15 memset(C, 0, sizeof(*C));
16
17 PSI_DataExchange((PSI_Data *) C, (PSI_Data *) V);
18
19 C->context = context;
20
21 return C;
22 }
23
24 void PSI_CompilerDtor(PSI_Compiler *C)
25 {
26 PSI_DataDtor((PSI_Data *) C);
27 }
28
29 void PSI_Compiler_Free(PSI_Compiler **C)
30 {
31 if (*C) {
32 PSI_CompilerDtor(*C);
33 free(*C);
34 *C = NULL;
35 }
36 }
37
38 typedef struct PSI_ClosureData {
39 void *context;
40 impl *impl;
41 jit_type_t signature;
42 zval return_value;
43 } PSI_ClosureData;
44
45 static inline PSI_ClosureData *PSI_ClosureDataAlloc(void *context, impl *impl) {
46 PSI_ClosureData *data = malloc(sizeof(*data));
47
48 data->context = context;
49 data->impl = impl;
50
51 return data;
52 }
53
54 static inline size_t impl_num_min_args(impl *impl) {
55 size_t i, n = impl->func->args->count;
56
57 for (i = 0; i < impl->func->args->count; ++i) {
58 if (impl->func->args->args[i]->def) {
59 --n;
60 }
61 }
62 return n;
63 }
64
65 static inline jit_abi_t psi_jit_abi(const char *convention) {
66 return jit_abi_cdecl;
67 }
68 static inline jit_type_t psi_jit_type(token_t t) {
69 switch (t) {
70 case PSI_T_VOID:
71 return jit_type_void;
72 case PSI_T_SINT8:
73 return jit_type_sbyte;
74 case PSI_T_UINT8:
75 return jit_type_ubyte;
76 case PSI_T_SINT16:
77 return jit_type_short;
78 case PSI_T_UINT16:
79 return jit_type_ushort;
80 case PSI_T_SINT32:
81 return jit_type_int;
82 case PSI_T_UINT32:
83 return jit_type_uint;
84 case PSI_T_SINT64:
85 return jit_type_long;
86 case PSI_T_UINT64:
87 return jit_type_ulong;
88 case PSI_T_BOOL:
89 return jit_type_sys_bool;
90 case PSI_T_CHAR:
91 return jit_type_sys_char;
92 case PSI_T_SHORT:
93 return jit_type_sys_short;
94 case PSI_T_INT:
95 return jit_type_sys_int;
96 case PSI_T_LONG:
97 return jit_type_sys_long;
98 case PSI_T_FLOAT:
99 return jit_type_sys_float;
100 case PSI_T_DOUBLE:
101 return jit_type_sys_double;
102 default:
103 abort();
104 }
105 }
106 static inline jit_type_t psi_jit_decl_type(decl_type *type) {
107 return psi_jit_type(real_decl_type(type)->type);
108 }
109 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) {
110 if (darg->var->pointer_level) {
111 return jit_type_void_ptr;
112 } else {
113 return psi_jit_decl_type(darg->type);
114 }
115 }
116 static void psi_jit_closure_handler(jit_type_t _sig, void *result, void **_args, void *_data)
117 {
118 zend_execute_data *execute_data = *(zend_execute_data **)_args[0];
119 zval *return_value = *(zval **)_args[1];
120 PSI_ClosureData *data = _data;
121 impl_arg *iarg;
122 size_t i;
123 void **arg_ptr = NULL, **arg_prm = NULL;
124 impl_val ret_val, *arg_val = NULL;
125 jit_type_t signature, *sig_prm;
126
127 if (!data->impl->func->args->count) {
128 if (SUCCESS != zend_parse_parameters_none()) {
129 return;
130 }
131 } else
132 ZEND_PARSE_PARAMETERS_START(impl_num_min_args(data->impl), data->impl->func->args->count)
133 nextarg:
134 iarg = data->impl->func->args->args[_i];
135 if (iarg->def) {
136 Z_PARAM_OPTIONAL;
137 }
138 if (PSI_T_BOOL == iarg->type->type) {
139 if (iarg->def) {
140 iarg->val.bval = iarg->def->type == PSI_T_TRUE ? 1 : 0;
141 }
142 Z_PARAM_BOOL(iarg->val.bval);
143 } else if (PSI_T_INT == iarg->type->type) {
144 if (iarg->def) {
145 iarg->val.lval = zend_atol(iarg->def->text, strlen(iarg->def->text));
146 }
147 Z_PARAM_LONG(iarg->val.lval);
148 } else if (PSI_T_FLOAT == iarg->type->type) {
149 if (iarg->def) {
150 iarg->val.dval = zend_strtod(iarg->def->text, NULL);
151 }
152 Z_PARAM_DOUBLE(iarg->val.dval);
153 } else if (PSI_T_STRING == iarg->type->type) {
154 if (iarg->def) {
155 /* FIXME */
156 iarg->val.str.len = strlen(iarg->def->text) - 2;
157 iarg->val.str.val = &iarg->def->text[1];
158 }
159 Z_PARAM_STRING(iarg->val.str.val, iarg->val.str.len);
160 } else {
161 error_code = ZPP_ERROR_FAILURE;
162 break;
163 }
164 iarg->_zv = _arg;
165 if (_i < _max_num_args) {
166 goto nextarg;
167 }
168 ZEND_PARSE_PARAMETERS_END();
169
170 if (data->impl->decl->args->count) {
171 arg_ptr = malloc(data->impl->decl->args->count * sizeof(*arg_ptr));
172 arg_prm = malloc(data->impl->decl->args->count * sizeof(*arg_prm));
173 arg_val = malloc(data->impl->decl->args->count * sizeof(*arg_val));
174 sig_prm = malloc(data->impl->decl->args->count * sizeof(*sig_prm));
175
176 for (i = 0; i < data->impl->decl->args->count; ++i) {
177 decl_arg *darg = data->impl->decl->args->args[i];
178 impl_arg *iarg = darg->let->arg;
179
180 switch (darg->let->val->func->type) {
181 case PSI_T_BOOLVAL:
182 if (iarg->type->type == PSI_T_BOOL) {
183 arg_val[i].bval = iarg->val.bval;
184 } else {
185 arg_val[i].bval = zend_is_true(iarg->_zv);
186 }
187 break;
188 case PSI_T_INTVAL:
189 if (iarg->type->type == PSI_T_INT) {
190 arg_val[i].lval = iarg->val.lval;
191 } else {
192 arg_val[i].lval = zval_get_long(iarg->_zv);
193 }
194 break;
195 case PSI_T_STRVAL:
196 if (iarg->type->type == PSI_T_STRING) {
197 arg_val[i].str.val = estrndup(iarg->val.str.val, iarg->val.str.len);
198 } else {
199 zend_string *zs = zval_get_string(iarg->_zv);
200 arg_val[i].str.val = estrndup(zs->val, zs->len);
201 zend_string_release(zs);
202 }
203 break;
204 case PSI_T_STRLEN:
205 if (iarg->type->type == PSI_T_STRING) {
206 arg_val[i].lval =iarg->val.str.len;
207 } else {
208 zend_string *zs = zval_get_string(iarg->_zv);
209 arg_val[i].lval = zs->len;
210 zend_string_release(zs);
211 }
212 break;
213 }
214 arg_ptr[i] = &arg_val[i];
215 arg_prm[i] = darg->let->val->is_reference ? &arg_ptr[i] : arg_ptr[i];
216 sig_prm[i] = psi_jit_decl_arg_type(darg);
217 }
218 }
219
220 signature = jit_type_create_signature(
221 psi_jit_abi(data->impl->decl->abi->convention),
222 psi_jit_decl_arg_type(data->impl->decl->func),
223 sig_prm,
224 data->impl->decl->args->count,
225 1);
226 jit_apply(signature, data->impl->decl->dlptr, arg_prm, data->impl->decl->args->count, &ret_val);
227
228 switch (data->impl->stmts->ret.list[0]->func->type) {
229 case PSI_T_TO_STRING:
230 if (data->impl->decl->func->var->pointer_level) {
231 switch (real_decl_type(data->impl->decl->func->type)->type) {
232 case PSI_T_CHAR:
233 case PSI_T_SINT8:
234 case PSI_T_UINT8:
235 RETVAL_STRING(ret_val.str.val);
236 break;
237 }
238 }
239 break;
240 }
241 }
242
243 zend_function_entry *PSI_CompilerCompile(PSI_Compiler *C)
244 {
245 size_t i, j = 0;
246 jit_type_t signature, params[] = {
247 jit_type_void_ptr,
248 jit_type_void_ptr
249 };
250 zend_function_entry *zfe = calloc(C->impls->count + 1, sizeof(*zfe));
251
252 for (i = 0; i < C->impls->count; ++i) {
253 zend_function_entry *zf;
254 PSI_ClosureData *data;
255
256 if (!C->impls->list[i]->decl) {
257 continue;
258 }
259
260 zf = &zfe[j++];
261 data = PSI_ClosureDataAlloc(C->context, C->impls->list[i]);
262 signature = jit_type_create_signature(jit_abi_vararg, jit_type_void, params, 2, 1);
263 zf->fname = C->impls->list[i]->func->name + (C->impls->list[i]->func->name[0] == '\\');
264 zf->handler = jit_closure_create(C->context, signature, &psi_jit_closure_handler, data);
265 }
266
267 return zfe;
268 }