diff options
author | David Walter Seikel | 2012-01-23 23:36:30 +1000 |
---|---|---|
committer | David Walter Seikel | 2012-01-23 23:36:30 +1000 |
commit | 6523585c66c04cea54df50013df8886b589847d8 (patch) | |
tree | 0b22aee7064166d88595eda260ca2d17c0773da5 /libraries/luajit-2.0/src/lj_crecord.c | |
parent | Update the EFL to what I'm actually using, coz I'm using some stuff not yet r... (diff) | |
download | SledjHamr-6523585c66c04cea54df50013df8886b589847d8.zip SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.gz SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.bz2 SledjHamr-6523585c66c04cea54df50013df8886b589847d8.tar.xz |
Add luaproc and LuaJIT libraries.
Two versions of LuaJIT, the stable release, and the dev version. Try the dev version first, until ih fails badly.
Diffstat (limited to '')
-rw-r--r-- | libraries/luajit-2.0/src/lj_crecord.c | 1316 |
1 files changed, 1316 insertions, 0 deletions
diff --git a/libraries/luajit-2.0/src/lj_crecord.c b/libraries/luajit-2.0/src/lj_crecord.c new file mode 100644 index 0000000..27001f6 --- /dev/null +++ b/libraries/luajit-2.0/src/lj_crecord.c | |||
@@ -0,0 +1,1316 @@ | |||
1 | /* | ||
2 | ** Trace recorder for C data operations. | ||
3 | ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | #define lj_ffrecord_c | ||
7 | #define LUA_CORE | ||
8 | |||
9 | #include "lj_obj.h" | ||
10 | |||
11 | #if LJ_HASJIT && LJ_HASFFI | ||
12 | |||
13 | #include "lj_err.h" | ||
14 | #include "lj_str.h" | ||
15 | #include "lj_tab.h" | ||
16 | #include "lj_frame.h" | ||
17 | #include "lj_ctype.h" | ||
18 | #include "lj_cdata.h" | ||
19 | #include "lj_cparse.h" | ||
20 | #include "lj_cconv.h" | ||
21 | #include "lj_clib.h" | ||
22 | #include "lj_ccall.h" | ||
23 | #include "lj_ir.h" | ||
24 | #include "lj_jit.h" | ||
25 | #include "lj_ircall.h" | ||
26 | #include "lj_iropt.h" | ||
27 | #include "lj_trace.h" | ||
28 | #include "lj_record.h" | ||
29 | #include "lj_ffrecord.h" | ||
30 | #include "lj_snap.h" | ||
31 | #include "lj_crecord.h" | ||
32 | #include "lj_dispatch.h" | ||
33 | |||
34 | /* Some local macros to save typing. Undef'd at the end. */ | ||
35 | #define IR(ref) (&J->cur.ir[(ref)]) | ||
36 | |||
37 | /* Pass IR on to next optimization in chain (FOLD). */ | ||
38 | #define emitir(ot, a, b) (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J)) | ||
39 | |||
40 | #define emitconv(a, dt, st, flags) \ | ||
41 | emitir(IRT(IR_CONV, (dt)), (a), (st)|((dt) << 5)|(flags)) | ||
42 | |||
43 | /* -- C type checks ------------------------------------------------------- */ | ||
44 | |||
45 | static GCcdata *argv2cdata(jit_State *J, TRef tr, cTValue *o) | ||
46 | { | ||
47 | GCcdata *cd; | ||
48 | TRef trtypeid; | ||
49 | if (!tref_iscdata(tr)) | ||
50 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
51 | cd = cdataV(o); | ||
52 | /* Specialize to the CTypeID. */ | ||
53 | trtypeid = emitir(IRT(IR_FLOAD, IRT_U16), tr, IRFL_CDATA_TYPEID); | ||
54 | emitir(IRTG(IR_EQ, IRT_INT), trtypeid, lj_ir_kint(J, (int32_t)cd->typeid)); | ||
55 | return cd; | ||
56 | } | ||
57 | |||
58 | /* Specialize to the CTypeID held by a cdata constructor. */ | ||
59 | static CTypeID crec_constructor(jit_State *J, GCcdata *cd, TRef tr) | ||
60 | { | ||
61 | CTypeID id; | ||
62 | lua_assert(tref_iscdata(tr) && cd->typeid == CTID_CTYPEID); | ||
63 | id = *(CTypeID *)cdataptr(cd); | ||
64 | tr = emitir(IRT(IR_ADD, IRT_PTR), tr, lj_ir_kintp(J, sizeof(GCcdata))); | ||
65 | tr = emitir(IRT(IR_XLOAD, IRT_INT), tr, 0); | ||
66 | emitir(IRTG(IR_EQ, IRT_INT), tr, lj_ir_kint(J, (int32_t)id)); | ||
67 | return id; | ||
68 | } | ||
69 | |||
70 | static CTypeID argv2ctype(jit_State *J, TRef tr, cTValue *o) | ||
71 | { | ||
72 | if (tref_isstr(tr)) { | ||
73 | GCstr *s = strV(o); | ||
74 | CPState cp; | ||
75 | CTypeID oldtop; | ||
76 | /* Specialize to the string containing the C type declaration. */ | ||
77 | emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, s)); | ||
78 | cp.L = J->L; | ||
79 | cp.cts = ctype_ctsG(J2G(J)); | ||
80 | oldtop = cp.cts->top; | ||
81 | cp.srcname = strdata(s); | ||
82 | cp.p = strdata(s); | ||
83 | cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT; | ||
84 | if (lj_cparse(&cp) || cp.cts->top > oldtop) /* Avoid new struct defs. */ | ||
85 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
86 | return cp.val.id; | ||
87 | } else { | ||
88 | GCcdata *cd = argv2cdata(J, tr, o); | ||
89 | return cd->typeid == CTID_CTYPEID ? crec_constructor(J, cd, tr) : | ||
90 | cd->typeid; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /* -- Convert C type to C type -------------------------------------------- */ | ||
95 | |||
96 | /* | ||
97 | ** This code mirrors the code in lj_cconv.c. It performs the same steps | ||
98 | ** for the trace recorder that lj_cconv.c does for the interpreter. | ||
99 | ** | ||
100 | ** One major difference is that we can get away with much fewer checks | ||
101 | ** here. E.g. checks for casts, constness or correct types can often be | ||
102 | ** omitted, even if they might fail. The interpreter subsequently throws | ||
103 | ** an error, which aborts the trace. | ||
104 | ** | ||
105 | ** All operations are specialized to their C types, so the on-trace | ||
106 | ** outcome must be the same as the outcome in the interpreter. If the | ||
107 | ** interpreter doesn't throw an error, then the trace is correct, too. | ||
108 | ** Care must be taken not to generate invalid (temporary) IR or to | ||
109 | ** trigger asserts. | ||
110 | */ | ||
111 | |||
112 | /* Convert CType to IRType. */ | ||
113 | static IRType crec_ct2irt(CType *ct) | ||
114 | { | ||
115 | if (LJ_LIKELY(ctype_isnum(ct->info))) { | ||
116 | if ((ct->info & CTF_FP)) { | ||
117 | if (ct->size == sizeof(double)) | ||
118 | return IRT_NUM; | ||
119 | else if (ct->size == sizeof(float)) | ||
120 | return IRT_FLOAT; | ||
121 | } else { | ||
122 | uint32_t b = lj_fls(ct->size); | ||
123 | if (b <= 3) | ||
124 | return IRT_I8 + 2*b + ((ct->info & CTF_UNSIGNED) ? 1 : 0); | ||
125 | } | ||
126 | } else if (ctype_isptr(ct->info)) { | ||
127 | return (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32; | ||
128 | } else if (ctype_iscomplex(ct->info)) { | ||
129 | if (ct->size == 2*sizeof(double)) | ||
130 | return IRT_NUM; | ||
131 | else if (ct->size == 2*sizeof(float)) | ||
132 | return IRT_FLOAT; | ||
133 | } | ||
134 | return IRT_CDATA; | ||
135 | } | ||
136 | |||
137 | /* Determine whether a passed number or cdata number is non-zero. */ | ||
138 | static int crec_isnonzero(CType *s, void *p) | ||
139 | { | ||
140 | if (p == (void *)0) | ||
141 | return 0; | ||
142 | if (p == (void *)1) | ||
143 | return 1; | ||
144 | if ((s->info & CTF_FP)) { | ||
145 | if (s->size == sizeof(float)) | ||
146 | return (*(float *)p != 0); | ||
147 | else | ||
148 | return (*(double *)p != 0); | ||
149 | } else { | ||
150 | if (s->size == 1) | ||
151 | return (*(uint8_t *)p != 0); | ||
152 | else if (s->size == 2) | ||
153 | return (*(uint16_t *)p != 0); | ||
154 | else if (s->size == 4) | ||
155 | return (*(uint32_t *)p != 0); | ||
156 | else | ||
157 | return (*(uint64_t *)p != 0); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | static TRef crec_ct_ct(jit_State *J, CType *d, CType *s, TRef dp, TRef sp, | ||
162 | void *svisnz) | ||
163 | { | ||
164 | CTSize dsize = d->size, ssize = s->size; | ||
165 | CTInfo dinfo = d->info, sinfo = s->info; | ||
166 | IRType dt = crec_ct2irt(d); | ||
167 | IRType st = crec_ct2irt(s); | ||
168 | |||
169 | if (ctype_type(dinfo) > CT_MAYCONVERT || ctype_type(sinfo) > CT_MAYCONVERT) | ||
170 | goto err_conv; | ||
171 | |||
172 | /* | ||
173 | ** Note: Unlike lj_cconv_ct_ct(), sp holds the _value_ of pointers and | ||
174 | ** numbers up to 8 bytes. Otherwise sp holds a pointer. | ||
175 | */ | ||
176 | |||
177 | switch (cconv_idx2(dinfo, sinfo)) { | ||
178 | /* Destination is a bool. */ | ||
179 | case CCX(B, B): | ||
180 | goto xstore; /* Source operand is already normalized. */ | ||
181 | case CCX(B, I): | ||
182 | case CCX(B, F): | ||
183 | if (st != IRT_CDATA) { | ||
184 | /* Specialize to the result of a comparison against 0. */ | ||
185 | TRef zero = (st == IRT_NUM || st == IRT_FLOAT) ? lj_ir_knum(J, 0) : | ||
186 | (st == IRT_I64 || st == IRT_U64) ? lj_ir_kint64(J, 0) : | ||
187 | lj_ir_kint(J, 0); | ||
188 | int isnz = crec_isnonzero(s, svisnz); | ||
189 | emitir(IRTG(isnz ? IR_NE : IR_EQ, st), sp, zero); | ||
190 | sp = lj_ir_kint(J, isnz); | ||
191 | goto xstore; | ||
192 | } | ||
193 | goto err_nyi; | ||
194 | |||
195 | /* Destination is an integer. */ | ||
196 | case CCX(I, B): | ||
197 | case CCX(I, I): | ||
198 | conv_I_I: | ||
199 | if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; | ||
200 | /* Extend 32 to 64 bit integer. */ | ||
201 | if (dsize == 8 && ssize < 8 && !(LJ_64 && (sinfo & CTF_UNSIGNED))) | ||
202 | sp = emitconv(sp, dt, ssize < 4 ? IRT_INT : st, | ||
203 | (sinfo & CTF_UNSIGNED) ? 0 : IRCONV_SEXT); | ||
204 | else if (dsize < 8 && ssize == 8) /* Truncate from 64 bit integer. */ | ||
205 | sp = emitconv(sp, dsize < 4 ? IRT_INT : dt, st, 0); | ||
206 | else if (st == IRT_INT) | ||
207 | sp = lj_opt_narrow_toint(J, sp); | ||
208 | xstore: | ||
209 | if (dt == IRT_I64 || dt == IRT_U64) lj_needsplit(J); | ||
210 | if (dp == 0) return sp; | ||
211 | emitir(IRT(IR_XSTORE, dt), dp, sp); | ||
212 | break; | ||
213 | case CCX(I, C): | ||
214 | sp = emitir(IRT(IR_XLOAD, st), sp, 0); /* Load re. */ | ||
215 | /* fallthrough */ | ||
216 | case CCX(I, F): | ||
217 | if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; | ||
218 | sp = emitconv(sp, dsize < 4 ? IRT_INT : dt, st, IRCONV_TRUNC|IRCONV_ANY); | ||
219 | goto xstore; | ||
220 | case CCX(I, P): | ||
221 | case CCX(I, A): | ||
222 | sinfo = CTINFO(CT_NUM, CTF_UNSIGNED); | ||
223 | ssize = CTSIZE_PTR; | ||
224 | st = IRT_UINTP; | ||
225 | goto conv_I_I; | ||
226 | |||
227 | /* Destination is a floating-point number. */ | ||
228 | case CCX(F, B): | ||
229 | case CCX(F, I): | ||
230 | conv_F_I: | ||
231 | if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; | ||
232 | sp = emitconv(sp, dt, ssize < 4 ? IRT_INT : st, 0); | ||
233 | goto xstore; | ||
234 | case CCX(F, C): | ||
235 | sp = emitir(IRT(IR_XLOAD, st), sp, 0); /* Load re. */ | ||
236 | /* fallthrough */ | ||
237 | case CCX(F, F): | ||
238 | conv_F_F: | ||
239 | if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; | ||
240 | if (dt != st) sp = emitconv(sp, dt, st, 0); | ||
241 | goto xstore; | ||
242 | |||
243 | /* Destination is a complex number. */ | ||
244 | case CCX(C, I): | ||
245 | case CCX(C, F): | ||
246 | { /* Clear im. */ | ||
247 | TRef ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, (dsize >> 1))); | ||
248 | emitir(IRT(IR_XSTORE, dt), ptr, lj_ir_knum(J, 0)); | ||
249 | } | ||
250 | /* Convert to re. */ | ||
251 | if ((sinfo & CTF_FP)) goto conv_F_F; else goto conv_F_I; | ||
252 | |||
253 | case CCX(C, C): | ||
254 | if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; | ||
255 | { | ||
256 | TRef re, im, ptr; | ||
257 | re = emitir(IRT(IR_XLOAD, st), sp, 0); | ||
258 | ptr = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, (ssize >> 1))); | ||
259 | im = emitir(IRT(IR_XLOAD, st), ptr, 0); | ||
260 | if (dt != st) { | ||
261 | re = emitconv(re, dt, st, 0); | ||
262 | im = emitconv(im, dt, st, 0); | ||
263 | } | ||
264 | emitir(IRT(IR_XSTORE, dt), dp, re); | ||
265 | ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, (dsize >> 1))); | ||
266 | emitir(IRT(IR_XSTORE, dt), ptr, im); | ||
267 | } | ||
268 | break; | ||
269 | |||
270 | /* Destination is a vector. */ | ||
271 | case CCX(V, I): | ||
272 | case CCX(V, F): | ||
273 | case CCX(V, C): | ||
274 | case CCX(V, V): | ||
275 | goto err_nyi; | ||
276 | |||
277 | /* Destination is a pointer. */ | ||
278 | case CCX(P, P): | ||
279 | case CCX(P, A): | ||
280 | case CCX(P, S): | ||
281 | /* There are only 32 bit pointers/addresses on 32 bit machines. | ||
282 | ** Also ok on x64, since all 32 bit ops clear the upper part of the reg. | ||
283 | */ | ||
284 | goto xstore; | ||
285 | case CCX(P, I): | ||
286 | if (st == IRT_CDATA) goto err_nyi; | ||
287 | if (!LJ_64 && ssize == 8) /* Truncate from 64 bit integer. */ | ||
288 | sp = emitconv(sp, IRT_U32, st, 0); | ||
289 | goto xstore; | ||
290 | case CCX(P, F): | ||
291 | if (st == IRT_CDATA) goto err_nyi; | ||
292 | /* The signed conversion is cheaper. x64 really has 47 bit pointers. */ | ||
293 | sp = emitconv(sp, (LJ_64 && dsize == 8) ? IRT_I64 : IRT_U32, | ||
294 | st, IRCONV_TRUNC|IRCONV_ANY); | ||
295 | goto xstore; | ||
296 | |||
297 | /* Destination is an array. */ | ||
298 | case CCX(A, A): | ||
299 | goto err_nyi; | ||
300 | |||
301 | /* Destination is a struct/union. */ | ||
302 | case CCX(S, S): | ||
303 | goto err_nyi; | ||
304 | |||
305 | default: | ||
306 | err_conv: | ||
307 | err_nyi: | ||
308 | lj_trace_err(J, LJ_TRERR_NYICONV); | ||
309 | break; | ||
310 | } | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | /* -- Convert C type to TValue (load) ------------------------------------- */ | ||
315 | |||
316 | static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp) | ||
317 | { | ||
318 | CTState *cts = ctype_ctsG(J2G(J)); | ||
319 | CTInfo sinfo = s->info; | ||
320 | lua_assert(!ctype_isenum(sinfo)); | ||
321 | if (ctype_isnum(sinfo)) { | ||
322 | IRType t = crec_ct2irt(s); | ||
323 | TRef tr; | ||
324 | if (t == IRT_CDATA) | ||
325 | goto err_nyi; /* NYI: copyval of >64 bit integers. */ | ||
326 | tr = emitir(IRT(IR_XLOAD, t), sp, 0); | ||
327 | if (t == IRT_FLOAT || t == IRT_U32) { /* Keep uint32_t/float as numbers. */ | ||
328 | return emitconv(tr, IRT_NUM, t, 0); | ||
329 | } else if (t == IRT_I64 || t == IRT_U64) { /* Box 64 bit integer. */ | ||
330 | sp = tr; | ||
331 | lj_needsplit(J); | ||
332 | } else if ((sinfo & CTF_BOOL)) { | ||
333 | /* Assume not equal to zero. Fixup and emit pending guard later. */ | ||
334 | lj_ir_set(J, IRTGI(IR_NE), tr, lj_ir_kint(J, 0)); | ||
335 | J->postproc = LJ_POST_FIXGUARD; | ||
336 | return TREF_TRUE; | ||
337 | } else { | ||
338 | return tr; | ||
339 | } | ||
340 | } else if (ctype_isptr(sinfo)) { | ||
341 | IRType t = (LJ_64 && s->size == 8) ? IRT_P64 : IRT_P32; | ||
342 | sp = emitir(IRT(IR_XLOAD, t), sp, 0); | ||
343 | } else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) { | ||
344 | cts->L = J->L; | ||
345 | sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */ | ||
346 | } else if (ctype_iscomplex(sinfo)) { /* Unbox/box complex. */ | ||
347 | IRType t = s->size == 2*sizeof(double) ? IRT_NUM : IRT_FLOAT; | ||
348 | ptrdiff_t esz = (ptrdiff_t)(s->size >> 1); | ||
349 | TRef ptr, tr1, tr2, dp; | ||
350 | dp = emitir(IRTG(IR_CNEW, IRT_CDATA), lj_ir_kint(J, sid), TREF_NIL); | ||
351 | tr1 = emitir(IRT(IR_XLOAD, t), sp, 0); | ||
352 | ptr = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, esz)); | ||
353 | tr2 = emitir(IRT(IR_XLOAD, t), ptr, 0); | ||
354 | ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, sizeof(GCcdata))); | ||
355 | emitir(IRT(IR_XSTORE, t), ptr, tr1); | ||
356 | ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, sizeof(GCcdata)+esz)); | ||
357 | emitir(IRT(IR_XSTORE, t), ptr, tr2); | ||
358 | return dp; | ||
359 | } else { | ||
360 | /* NYI: copyval of vectors. */ | ||
361 | err_nyi: | ||
362 | lj_trace_err(J, LJ_TRERR_NYICONV); | ||
363 | } | ||
364 | /* Box pointer, ref or 64 bit integer. */ | ||
365 | return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, sid), sp); | ||
366 | } | ||
367 | |||
368 | /* -- Convert TValue to C type (store) ------------------------------------ */ | ||
369 | |||
370 | static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval) | ||
371 | { | ||
372 | CTState *cts = ctype_ctsG(J2G(J)); | ||
373 | CTypeID sid = CTID_P_VOID; | ||
374 | void *svisnz = 0; | ||
375 | CType *s; | ||
376 | if (LJ_LIKELY(tref_isinteger(sp))) { | ||
377 | sid = CTID_INT32; | ||
378 | svisnz = (void *)(intptr_t)(tvisint(sval)?(intV(sval)!=0):!tviszero(sval)); | ||
379 | } else if (tref_isnum(sp)) { | ||
380 | sid = CTID_DOUBLE; | ||
381 | svisnz = (void *)(intptr_t)(tvisint(sval)?(intV(sval)!=0):!tviszero(sval)); | ||
382 | } else if (tref_isbool(sp)) { | ||
383 | sp = lj_ir_kint(J, tref_istrue(sp) ? 1 : 0); | ||
384 | sid = CTID_BOOL; | ||
385 | } else if (tref_isnil(sp)) { | ||
386 | sp = lj_ir_kptr(J, NULL); | ||
387 | } else if (tref_isudata(sp)) { | ||
388 | sp = emitir(IRT(IR_ADD, IRT_P32), sp, lj_ir_kint(J, sizeof(GCudata))); | ||
389 | } else if (tref_isstr(sp)) { | ||
390 | if (ctype_isenum(d->info)) { /* Match string against enum constant. */ | ||
391 | GCstr *str = strV(sval); | ||
392 | CTSize ofs; | ||
393 | CType *cct = lj_ctype_getfield(cts, d, str, &ofs); | ||
394 | /* Specialize to the name of the enum constant. */ | ||
395 | emitir(IRTG(IR_EQ, IRT_STR), sp, lj_ir_kstr(J, str)); | ||
396 | if (cct && ctype_isconstval(cct->info)) { | ||
397 | lua_assert(ctype_child(cts, cct)->size == 4); | ||
398 | svisnz = (void *)(intptr_t)(cct->size != 0); | ||
399 | sp = lj_ir_kint(J, (int32_t)cct->size); | ||
400 | sid = ctype_cid(cct->info); | ||
401 | } /* else: interpreter will throw. */ | ||
402 | } else if (ctype_isrefarray(d->info)) { /* Copy string to array. */ | ||
403 | lj_trace_err(J, LJ_TRERR_BADTYPE); /* NYI */ | ||
404 | } else { /* Otherwise pass the string data as a const char[]. */ | ||
405 | sp = emitir(IRT(IR_STRREF, IRT_P32), sp, lj_ir_kint(J, 0)); | ||
406 | sid = CTID_A_CCHAR; | ||
407 | } | ||
408 | } else { /* NYI: tref_istab(sp), tref_islightud(sp). */ | ||
409 | sid = argv2cdata(J, sp, sval)->typeid; | ||
410 | s = ctype_raw(cts, sid); | ||
411 | svisnz = cdataptr(cdataV(sval)); | ||
412 | if (ctype_isptr(s->info)) { | ||
413 | IRType t = (LJ_64 && s->size == 8) ? IRT_P64 : IRT_P32; | ||
414 | sp = emitir(IRT(IR_FLOAD, t), sp, IRFL_CDATA_PTR); | ||
415 | if (ctype_isref(s->info)) { | ||
416 | svisnz = *(void **)svisnz; | ||
417 | s = ctype_rawchild(cts, s); | ||
418 | } else { | ||
419 | goto doconv; /* The pointer value was loaded, don't load number. */ | ||
420 | } | ||
421 | } else if (ctype_isinteger(s->info) && s->size == 8) { | ||
422 | IRType t = (s->info & CTF_UNSIGNED) ? IRT_U64 : IRT_I64; | ||
423 | sp = emitir(IRT(IR_FLOAD, t), sp, IRFL_CDATA_INT64); | ||
424 | lj_needsplit(J); | ||
425 | goto doconv; | ||
426 | } else { | ||
427 | sp = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, sizeof(GCcdata))); | ||
428 | } | ||
429 | if (ctype_isenum(s->info)) s = ctype_child(cts, s); | ||
430 | if (ctype_isnum(s->info)) { /* Load number value. */ | ||
431 | IRType t = crec_ct2irt(s); | ||
432 | if (t != IRT_CDATA) { | ||
433 | sp = emitir(IRT(IR_XLOAD, t), sp, 0); | ||
434 | if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J); | ||
435 | } | ||
436 | } | ||
437 | goto doconv; | ||
438 | } | ||
439 | s = ctype_get(cts, sid); | ||
440 | doconv: | ||
441 | if (ctype_isenum(d->info)) d = ctype_child(cts, d); | ||
442 | return crec_ct_ct(J, d, s, dp, sp, svisnz); | ||
443 | } | ||
444 | |||
445 | /* -- C data metamethods -------------------------------------------------- */ | ||
446 | |||
447 | /* This would be rather difficult in FOLD, so do it here: | ||
448 | ** (base+k)+(idx*sz)+ofs ==> (base+idx*sz)+(ofs+k) | ||
449 | ** (base+(idx+k)*sz)+ofs ==> (base+idx*sz)+(ofs+k*sz) | ||
450 | */ | ||
451 | static TRef crec_reassoc_ofs(jit_State *J, TRef tr, ptrdiff_t *ofsp, MSize sz) | ||
452 | { | ||
453 | IRIns *ir = IR(tref_ref(tr)); | ||
454 | if (LJ_LIKELY(J->flags & JIT_F_OPT_FOLD) && irref_isk(ir->op2) && | ||
455 | (ir->o == IR_ADD || ir->o == IR_ADDOV || ir->o == IR_SUBOV)) { | ||
456 | IRIns *irk = IR(ir->op2); | ||
457 | ptrdiff_t k; | ||
458 | if (LJ_64 && irk->o == IR_KINT64) | ||
459 | k = (ptrdiff_t)ir_kint64(irk)->u64 * sz; | ||
460 | else | ||
461 | k = (ptrdiff_t)irk->i * sz; | ||
462 | if (ir->o == IR_SUBOV) *ofsp -= k; else *ofsp += k; | ||
463 | tr = ir->op1; /* Not a TRef, but the caller doesn't care. */ | ||
464 | } | ||
465 | return tr; | ||
466 | } | ||
467 | |||
468 | /* Record ctype __index/__newindex metamethods. */ | ||
469 | static void crec_index_meta(jit_State *J, CTState *cts, CType *ct, | ||
470 | RecordFFData *rd) | ||
471 | { | ||
472 | CTypeID id = ctype_typeid(cts, ct); | ||
473 | cTValue *tv = lj_ctype_meta(cts, id, rd->data ? MM_newindex : MM_index); | ||
474 | if (!tv) | ||
475 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
476 | if (tvisfunc(tv)) { | ||
477 | J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME; | ||
478 | rd->nres = -1; /* Pending tailcall. */ | ||
479 | } else if (rd->data == 0 && tvistab(tv) && tref_isstr(J->base[1])) { | ||
480 | /* Specialize to result of __index lookup. */ | ||
481 | cTValue *o = lj_tab_get(J->L, tabV(tv), &rd->argv[1]); | ||
482 | IRType t = itype2irt(o); | ||
483 | if (tvisgcv(o)) | ||
484 | J->base[0] = lj_ir_kgc(J, gcV(o), t); | ||
485 | else if (tvisint(o)) | ||
486 | J->base[0] = lj_ir_kint(J, intV(o)); | ||
487 | else if (tvisnum(o)) | ||
488 | J->base[0] = lj_ir_knumint(J, numV(o)); | ||
489 | else if (tvisbool(o)) | ||
490 | J->base[0] = TREF_PRI(t); | ||
491 | else | ||
492 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
493 | /* Always specialize to the key. */ | ||
494 | emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, strV(&rd->argv[1]))); | ||
495 | } else { | ||
496 | /* NYI: resolving of non-function metamethods. */ | ||
497 | /* NYI: non-string keys for __index table. */ | ||
498 | /* NYI: stores to __newindex table. */ | ||
499 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | void LJ_FASTCALL recff_cdata_index(jit_State *J, RecordFFData *rd) | ||
504 | { | ||
505 | TRef idx, ptr = J->base[0]; | ||
506 | ptrdiff_t ofs = sizeof(GCcdata); | ||
507 | GCcdata *cd = argv2cdata(J, ptr, &rd->argv[0]); | ||
508 | CTState *cts = ctype_ctsG(J2G(J)); | ||
509 | CType *ct = ctype_raw(cts, cd->typeid); | ||
510 | CTypeID sid = 0; | ||
511 | |||
512 | /* Resolve pointer or reference for cdata object. */ | ||
513 | if (ctype_isptr(ct->info)) { | ||
514 | IRType t = (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32; | ||
515 | if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct); | ||
516 | ptr = emitir(IRT(IR_FLOAD, t), ptr, IRFL_CDATA_PTR); | ||
517 | ofs = 0; | ||
518 | ptr = crec_reassoc_ofs(J, ptr, &ofs, 1); | ||
519 | } | ||
520 | |||
521 | again: | ||
522 | idx = J->base[1]; | ||
523 | if (tref_isnumber(idx)) { | ||
524 | idx = lj_opt_narrow_cindex(J, idx); | ||
525 | if (ctype_ispointer(ct->info)) { | ||
526 | CTSize sz; | ||
527 | integer_key: | ||
528 | if ((ct->info & CTF_COMPLEX)) | ||
529 | idx = emitir(IRT(IR_BAND, IRT_INTP), idx, lj_ir_kintp(J, 1)); | ||
530 | sz = lj_ctype_size(cts, (sid = ctype_cid(ct->info))); | ||
531 | idx = crec_reassoc_ofs(J, idx, &ofs, sz); | ||
532 | #if LJ_TARGET_ARM || LJ_TARGET_PPC | ||
533 | /* Hoist base add to allow fusion of index/shift into operands. */ | ||
534 | if (LJ_LIKELY(J->flags & JIT_F_OPT_LOOP) && ofs | ||
535 | #if LJ_TARGET_ARM | ||
536 | && (sz == 1 || sz == 4) | ||
537 | #endif | ||
538 | ) { | ||
539 | ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs)); | ||
540 | ofs = 0; | ||
541 | } | ||
542 | #endif | ||
543 | idx = emitir(IRT(IR_MUL, IRT_INTP), idx, lj_ir_kintp(J, sz)); | ||
544 | ptr = emitir(IRT(IR_ADD, IRT_PTR), idx, ptr); | ||
545 | } | ||
546 | } else if (tref_iscdata(idx)) { | ||
547 | GCcdata *cdk = cdataV(&rd->argv[1]); | ||
548 | CType *ctk = ctype_raw(cts, cdk->typeid); | ||
549 | IRType t; | ||
550 | if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk); | ||
551 | if (ctype_ispointer(ct->info) && | ||
552 | ctype_isinteger(ctk->info) && (t = crec_ct2irt(ctk)) != IRT_CDATA) { | ||
553 | if (ctk->size == 8) { | ||
554 | idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64); | ||
555 | } else { | ||
556 | idx = emitir(IRT(IR_ADD, IRT_PTR), idx, | ||
557 | lj_ir_kintp(J, sizeof(GCcdata))); | ||
558 | idx = emitir(IRT(IR_XLOAD, t), idx, 0); | ||
559 | } | ||
560 | if (LJ_64 && ctk->size < sizeof(intptr_t) && !(ctk->info & CTF_UNSIGNED)) | ||
561 | idx = emitconv(idx, IRT_INTP, IRT_INT, IRCONV_SEXT); | ||
562 | if (!LJ_64 && ctk->size > sizeof(intptr_t)) { | ||
563 | idx = emitconv(idx, IRT_INTP, t, 0); | ||
564 | lj_needsplit(J); | ||
565 | } | ||
566 | goto integer_key; | ||
567 | } | ||
568 | } else if (tref_isstr(idx)) { | ||
569 | GCstr *name = strV(&rd->argv[1]); | ||
570 | if (cd->typeid == CTID_CTYPEID) | ||
571 | ct = ctype_raw(cts, crec_constructor(J, cd, ptr)); | ||
572 | if (ctype_isstruct(ct->info)) { | ||
573 | CTSize fofs; | ||
574 | CType *fct; | ||
575 | fct = lj_ctype_getfield(cts, ct, name, &fofs); | ||
576 | if (fct) { | ||
577 | /* Always specialize to the field name. */ | ||
578 | emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name)); | ||
579 | if (ctype_isconstval(fct->info)) { | ||
580 | if (fct->size >= 0x80000000u && | ||
581 | (ctype_child(cts, fct)->info & CTF_UNSIGNED)) { | ||
582 | J->base[0] = lj_ir_knum(J, (lua_Number)(uint32_t)fct->size); | ||
583 | return; | ||
584 | } | ||
585 | J->base[0] = lj_ir_kint(J, (int32_t)fct->size); | ||
586 | return; /* Interpreter will throw for newindex. */ | ||
587 | } else if (ctype_isbitfield(fct->info)) { | ||
588 | lj_trace_err(J, LJ_TRERR_NYICONV); | ||
589 | } else { | ||
590 | lua_assert(ctype_isfield(fct->info)); | ||
591 | sid = ctype_cid(fct->info); | ||
592 | } | ||
593 | ofs += (ptrdiff_t)fofs; | ||
594 | } | ||
595 | } else if (ctype_iscomplex(ct->info)) { | ||
596 | if (name->len == 2 && | ||
597 | ((strdata(name)[0] == 'r' && strdata(name)[1] == 'e') || | ||
598 | (strdata(name)[0] == 'i' && strdata(name)[1] == 'm'))) { | ||
599 | /* Always specialize to the field name. */ | ||
600 | emitir(IRTG(IR_EQ, IRT_STR), idx, lj_ir_kstr(J, name)); | ||
601 | if (strdata(name)[0] == 'i') ofs += (ct->size >> 1); | ||
602 | sid = ctype_cid(ct->info); | ||
603 | } | ||
604 | } | ||
605 | } | ||
606 | if (!sid) { | ||
607 | if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */ | ||
608 | CType *cct = ctype_rawchild(cts, ct); | ||
609 | if (ctype_isstruct(cct->info)) { | ||
610 | ct = cct; | ||
611 | if (tref_isstr(idx)) goto again; | ||
612 | } | ||
613 | } | ||
614 | crec_index_meta(J, cts, ct, rd); | ||
615 | return; | ||
616 | } | ||
617 | |||
618 | if (ofs) | ||
619 | ptr = emitir(IRT(IR_ADD, IRT_PTR), ptr, lj_ir_kintp(J, ofs)); | ||
620 | |||
621 | /* Resolve reference for field. */ | ||
622 | ct = ctype_get(cts, sid); | ||
623 | if (ctype_isref(ct->info)) | ||
624 | ptr = emitir(IRT(IR_XLOAD, IRT_PTR), ptr, 0); | ||
625 | |||
626 | while (ctype_isattrib(ct->info)) | ||
627 | ct = ctype_child(cts, ct); /* Skip attributes. */ | ||
628 | |||
629 | if (rd->data == 0) { /* __index metamethod. */ | ||
630 | if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); /* Skip enums. */ | ||
631 | J->base[0] = crec_tv_ct(J, ct, sid, ptr); | ||
632 | } else { /* __newindex metamethod. */ | ||
633 | rd->nres = 0; | ||
634 | J->needsnap = 1; | ||
635 | crec_ct_tv(J, ct, ptr, J->base[2], &rd->argv[2]); | ||
636 | } | ||
637 | } | ||
638 | |||
639 | /* Record cdata allocation. */ | ||
640 | static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id) | ||
641 | { | ||
642 | CTState *cts = ctype_ctsG(J2G(J)); | ||
643 | CTSize sz; | ||
644 | CTInfo info = lj_ctype_info(cts, id, &sz); | ||
645 | CType *d = ctype_raw(cts, id); | ||
646 | TRef trid; | ||
647 | if (sz == 0 || sz > 64 || (info & CTF_VLA) || ctype_align(info) > CT_MEMALIGN) | ||
648 | lj_trace_err(J, LJ_TRERR_NYICONV); /* NYI: large/special allocations. */ | ||
649 | trid = lj_ir_kint(J, id); | ||
650 | /* Use special instruction to box pointer or 64 bit integer. */ | ||
651 | if (ctype_isptr(info) || (ctype_isinteger(info) && sz == 8)) { | ||
652 | TRef sp = J->base[1] ? crec_ct_tv(J, d, 0, J->base[1], &rd->argv[1]) : | ||
653 | ctype_isptr(info) ? lj_ir_kptr(J, NULL) : | ||
654 | (lj_needsplit(J), lj_ir_kint64(J, 0)); | ||
655 | J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, sp); | ||
656 | } else { | ||
657 | TRef trcd = emitir(IRTG(IR_CNEW, IRT_CDATA), trid, TREF_NIL); | ||
658 | cTValue *fin; | ||
659 | J->base[0] = trcd; | ||
660 | if (J->base[1] && !J->base[2] && !lj_cconv_multi_init(d, &rd->argv[1])) { | ||
661 | goto single_init; | ||
662 | } else if (ctype_isarray(d->info)) { | ||
663 | CType *dc = ctype_rawchild(cts, d); /* Array element type. */ | ||
664 | CTSize ofs, esize = dc->size; | ||
665 | TRef sp = 0; | ||
666 | TValue tv; | ||
667 | TValue *sval = &tv; | ||
668 | MSize i; | ||
669 | tv.u64 = 0; | ||
670 | if (!(ctype_isnum(dc->info) || ctype_isptr(dc->info))) | ||
671 | lj_trace_err(J, LJ_TRERR_NYICONV); /* NYI: init array of aggregates. */ | ||
672 | for (i = 1, ofs = 0; ofs < sz; ofs += esize) { | ||
673 | TRef dp = emitir(IRT(IR_ADD, IRT_PTR), trcd, | ||
674 | lj_ir_kintp(J, ofs + sizeof(GCcdata))); | ||
675 | if (J->base[i]) { | ||
676 | sp = J->base[i]; | ||
677 | sval = &rd->argv[i]; | ||
678 | i++; | ||
679 | } else if (i != 2) { | ||
680 | sp = ctype_isnum(dc->info) ? lj_ir_kint(J, 0) : TREF_NIL; | ||
681 | } | ||
682 | crec_ct_tv(J, dc, dp, sp, sval); | ||
683 | } | ||
684 | } else if (ctype_isstruct(d->info)) { | ||
685 | CTypeID fid = d->sib; | ||
686 | MSize i = 1; | ||
687 | while (fid) { | ||
688 | CType *df = ctype_get(cts, fid); | ||
689 | fid = df->sib; | ||
690 | if (ctype_isfield(df->info)) { | ||
691 | CType *dc; | ||
692 | TRef sp, dp; | ||
693 | TValue tv; | ||
694 | TValue *sval = &tv; | ||
695 | setintV(&tv, 0); | ||
696 | if (!gcref(df->name)) continue; /* Ignore unnamed fields. */ | ||
697 | dc = ctype_rawchild(cts, df); /* Field type. */ | ||
698 | if (!(ctype_isnum(dc->info) || ctype_isptr(dc->info))) | ||
699 | lj_trace_err(J, LJ_TRERR_NYICONV); /* NYI: init aggregates. */ | ||
700 | if (J->base[i]) { | ||
701 | sp = J->base[i]; | ||
702 | sval = &rd->argv[i]; | ||
703 | i++; | ||
704 | } else { | ||
705 | sp = ctype_isnum(dc->info) ? lj_ir_kint(J, 0) : TREF_NIL; | ||
706 | } | ||
707 | dp = emitir(IRT(IR_ADD, IRT_PTR), trcd, | ||
708 | lj_ir_kintp(J, df->size + sizeof(GCcdata))); | ||
709 | crec_ct_tv(J, dc, dp, sp, sval); | ||
710 | } else if (!ctype_isconstval(df->info)) { | ||
711 | /* NYI: init bitfields and sub-structures. */ | ||
712 | lj_trace_err(J, LJ_TRERR_NYICONV); | ||
713 | } | ||
714 | } | ||
715 | } else { | ||
716 | TRef dp; | ||
717 | single_init: | ||
718 | dp = emitir(IRT(IR_ADD, IRT_PTR), trcd, lj_ir_kintp(J, sizeof(GCcdata))); | ||
719 | if (J->base[1]) { | ||
720 | crec_ct_tv(J, d, dp, J->base[1], &rd->argv[1]); | ||
721 | } else { | ||
722 | TValue tv; | ||
723 | tv.u64 = 0; | ||
724 | crec_ct_tv(J, d, dp, lj_ir_kint(J, 0), &tv); | ||
725 | } | ||
726 | } | ||
727 | /* Handle __gc metamethod. */ | ||
728 | fin = lj_ctype_meta(cts, id, MM_gc); | ||
729 | if (fin) { | ||
730 | TRef trlo = lj_ir_call(J, IRCALL_lj_cdata_setfin, trcd); | ||
731 | TRef trhi = emitir(IRT(IR_ADD, IRT_P32), trlo, lj_ir_kint(J, 4)); | ||
732 | if (LJ_BE) { TRef tmp = trlo; trlo = trhi; trhi = tmp; } | ||
733 | if (tvisfunc(fin)) { | ||
734 | emitir(IRT(IR_XSTORE, IRT_P32), trlo, lj_ir_kfunc(J, funcV(fin))); | ||
735 | emitir(IRTI(IR_XSTORE), trhi, lj_ir_kint(J, LJ_TFUNC)); | ||
736 | } else if (tviscdata(fin)) { | ||
737 | emitir(IRT(IR_XSTORE, IRT_P32), trlo, | ||
738 | lj_ir_kgc(J, obj2gco(cdataV(fin)), IRT_CDATA)); | ||
739 | emitir(IRTI(IR_XSTORE), trhi, lj_ir_kint(J, LJ_TCDATA)); | ||
740 | } else { | ||
741 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
742 | } | ||
743 | J->needsnap = 1; | ||
744 | } | ||
745 | } | ||
746 | } | ||
747 | |||
748 | /* Record argument conversions. */ | ||
749 | static TRef crec_call_args(jit_State *J, RecordFFData *rd, | ||
750 | CTState *cts, CType *ct) | ||
751 | { | ||
752 | TRef args[CCI_NARGS_MAX]; | ||
753 | CTypeID fid; | ||
754 | MSize i, n; | ||
755 | TRef tr, *base; | ||
756 | cTValue *o; | ||
757 | #if LJ_TARGET_X86 | ||
758 | #if LJ_ABI_WIN | ||
759 | TRef *arg0 = NULL, *arg1 = NULL; | ||
760 | #endif | ||
761 | int ngpr = 0; | ||
762 | if (ctype_cconv(ct->info) == CTCC_THISCALL) | ||
763 | ngpr = 1; | ||
764 | else if (ctype_cconv(ct->info) == CTCC_FASTCALL) | ||
765 | ngpr = 2; | ||
766 | #endif | ||
767 | |||
768 | /* Skip initial attributes. */ | ||
769 | fid = ct->sib; | ||
770 | while (fid) { | ||
771 | CType *ctf = ctype_get(cts, fid); | ||
772 | if (!ctype_isattrib(ctf->info)) break; | ||
773 | fid = ctf->sib; | ||
774 | } | ||
775 | args[0] = TREF_NIL; | ||
776 | for (n = 0, base = J->base+1, o = rd->argv+1; *base; n++, base++, o++) { | ||
777 | CTypeID did; | ||
778 | CType *d; | ||
779 | |||
780 | if (n >= CCI_NARGS_MAX) | ||
781 | lj_trace_err(J, LJ_TRERR_NYICALL); | ||
782 | |||
783 | if (fid) { /* Get argument type from field. */ | ||
784 | CType *ctf = ctype_get(cts, fid); | ||
785 | fid = ctf->sib; | ||
786 | lua_assert(ctype_isfield(ctf->info)); | ||
787 | did = ctype_cid(ctf->info); | ||
788 | } else { | ||
789 | if (!(ct->info & CTF_VARARG)) | ||
790 | lj_trace_err(J, LJ_TRERR_NYICALL); /* Too many arguments. */ | ||
791 | did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */ | ||
792 | } | ||
793 | d = ctype_raw(cts, did); | ||
794 | if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || | ||
795 | ctype_isenum(d->info))) | ||
796 | lj_trace_err(J, LJ_TRERR_NYICALL); | ||
797 | tr = crec_ct_tv(J, d, 0, *base, o); | ||
798 | if (ctype_isinteger_or_bool(d->info)) { | ||
799 | if (d->size < 4) { | ||
800 | if ((d->info & CTF_UNSIGNED)) | ||
801 | tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_U8 : IRT_U16, 0); | ||
802 | else | ||
803 | tr = emitconv(tr, IRT_INT, d->size==1 ? IRT_I8 : IRT_I16,IRCONV_SEXT); | ||
804 | } | ||
805 | } | ||
806 | #if LJ_TARGET_X86 | ||
807 | /* 64 bit args must not end up in registers for fastcall/thiscall. */ | ||
808 | #if LJ_ABI_WIN | ||
809 | if (!ctype_isfp(d->info)) { | ||
810 | /* Sigh, the Windows/x86 ABI allows reordering across 64 bit args. */ | ||
811 | if (tref_typerange(tr, IRT_I64, IRT_U64)) { | ||
812 | if (ngpr) { | ||
813 | arg0 = &args[n]; args[n++] = TREF_NIL; ngpr--; | ||
814 | if (ngpr) { | ||
815 | arg1 = &args[n]; args[n++] = TREF_NIL; ngpr--; | ||
816 | } | ||
817 | } | ||
818 | } else { | ||
819 | if (arg0) { *arg0 = tr; arg0 = NULL; n--; continue; } | ||
820 | if (arg1) { *arg1 = tr; arg1 = NULL; n--; continue; } | ||
821 | if (ngpr) ngpr--; | ||
822 | } | ||
823 | } | ||
824 | #else | ||
825 | if (!ctype_isfp(d->info) && ngpr) { | ||
826 | if (tref_typerange(tr, IRT_I64, IRT_U64)) { | ||
827 | /* No reordering for other x86 ABIs. Simply add alignment args. */ | ||
828 | do { args[n++] = TREF_NIL; } while (--ngpr); | ||
829 | } else { | ||
830 | ngpr--; | ||
831 | } | ||
832 | } | ||
833 | #endif | ||
834 | #endif | ||
835 | args[n] = tr; | ||
836 | } | ||
837 | tr = args[0]; | ||
838 | for (i = 1; i < n; i++) | ||
839 | tr = emitir(IRT(IR_CARG, IRT_NIL), tr, args[i]); | ||
840 | return tr; | ||
841 | } | ||
842 | |||
843 | /* Create a snapshot for the caller, simulating a 'false' return value. */ | ||
844 | static void crec_snap_caller(jit_State *J) | ||
845 | { | ||
846 | lua_State *L = J->L; | ||
847 | TValue *base = L->base, *top = L->top; | ||
848 | const BCIns *pc = J->pc; | ||
849 | TRef ftr = J->base[-1]; | ||
850 | ptrdiff_t delta; | ||
851 | if (!frame_islua(base-1)) | ||
852 | lj_trace_err(J, LJ_TRERR_NYICALL); | ||
853 | J->pc = frame_pc(base-1); delta = 1+bc_a(J->pc[-1]); | ||
854 | L->top = base; L->base = base - delta; | ||
855 | J->base[-1] = TREF_FALSE; | ||
856 | J->base -= delta; J->baseslot -= (BCReg)delta; | ||
857 | J->maxslot = (BCReg)delta; J->framedepth--; | ||
858 | lj_snap_add(J); | ||
859 | L->base = base; L->top = top; | ||
860 | J->framedepth++; J->maxslot = 1; | ||
861 | J->base += delta; J->baseslot += (BCReg)delta; | ||
862 | J->base[-1] = ftr; J->pc = pc; | ||
863 | } | ||
864 | |||
865 | /* Record function call. */ | ||
866 | static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd) | ||
867 | { | ||
868 | CTState *cts = ctype_ctsG(J2G(J)); | ||
869 | CType *ct = ctype_raw(cts, cd->typeid); | ||
870 | IRType tp = IRT_PTR; | ||
871 | if (ctype_isptr(ct->info)) { | ||
872 | tp = (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32; | ||
873 | ct = ctype_rawchild(cts, ct); | ||
874 | } | ||
875 | if (ctype_isfunc(ct->info)) { | ||
876 | TRef func = emitir(IRT(IR_FLOAD, tp), J->base[0], IRFL_CDATA_PTR); | ||
877 | CType *ctr = ctype_rawchild(cts, ct); | ||
878 | IRType t = crec_ct2irt(ctr); | ||
879 | TRef tr; | ||
880 | TValue tv; | ||
881 | /* Check for blacklisted C functions that might call a callback. */ | ||
882 | setlightudV(&tv, | ||
883 | cdata_getptr(cdataptr(cd), (LJ_64 && tp == IRT_P64) ? 8 : 4)); | ||
884 | if (tvistrue(lj_tab_get(J->L, cts->miscmap, &tv))) | ||
885 | lj_trace_err(J, LJ_TRERR_BLACKL); | ||
886 | if (ctype_isvoid(ctr->info)) { | ||
887 | t = IRT_NIL; | ||
888 | rd->nres = 0; | ||
889 | } else if (ctype_isenum(ctr->info)) { | ||
890 | ctr = ctype_child(cts, ctr); | ||
891 | } | ||
892 | if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info) || | ||
893 | ctype_isvoid(ctr->info)) || t == IRT_CDATA) | ||
894 | lj_trace_err(J, LJ_TRERR_NYICALL); | ||
895 | if ((ct->info & CTF_VARARG) | ||
896 | #if LJ_TARGET_X86 | ||
897 | || ctype_cconv(ct->info) != CTCC_CDECL | ||
898 | #endif | ||
899 | ) | ||
900 | func = emitir(IRT(IR_CARG, IRT_NIL), func, | ||
901 | lj_ir_kint(J, ctype_typeid(cts, ct))); | ||
902 | tr = emitir(IRT(IR_CALLXS, t), crec_call_args(J, rd, cts, ct), func); | ||
903 | if (ctype_isbool(ctr->info)) { | ||
904 | crec_snap_caller(J); | ||
905 | lj_ir_set(J, IRTGI(IR_NE), tr, lj_ir_kint(J, 0)); | ||
906 | J->postproc = LJ_POST_FIXGUARDSNAP; | ||
907 | tr = TREF_TRUE; | ||
908 | } else if (t == IRT_FLOAT || t == IRT_U32) { | ||
909 | tr = emitconv(tr, IRT_NUM, t, 0); | ||
910 | } else if (t == IRT_I8 || t == IRT_I16) { | ||
911 | tr = emitconv(tr, IRT_INT, t, IRCONV_SEXT); | ||
912 | } else if (t == IRT_U8 || t == IRT_U16) { | ||
913 | tr = emitconv(tr, IRT_INT, t, 0); | ||
914 | } else if (t == IRT_PTR || (LJ_64 && t == IRT_P32) || | ||
915 | (t == IRT_I64 || t == IRT_U64)) { | ||
916 | TRef trid = lj_ir_kint(J, ctype_cid(ct->info)); | ||
917 | tr = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, tr); | ||
918 | if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J); | ||
919 | } | ||
920 | J->base[0] = tr; | ||
921 | J->needsnap = 1; | ||
922 | return 1; | ||
923 | } | ||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | /* Record ctype call metamethod. */ | ||
928 | static void crec_call_meta(jit_State *J, RecordFFData *rd, CTypeID id) | ||
929 | { | ||
930 | CTState *cts = ctype_ctsG(J2G(J)); | ||
931 | CType *ct = ctype_raw(cts, id); | ||
932 | cTValue *tv; | ||
933 | if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); | ||
934 | tv = lj_ctype_meta(cts, id, MM_call); | ||
935 | if (tv && tvisfunc(tv)) { | ||
936 | J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME; | ||
937 | rd->nres = -1; /* Pending tailcall. */ | ||
938 | } else { | ||
939 | /* NYI: non-function metamethods. */ | ||
940 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
941 | } | ||
942 | } | ||
943 | |||
944 | void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd) | ||
945 | { | ||
946 | GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]); | ||
947 | if (cd->typeid == CTID_CTYPEID) | ||
948 | crec_alloc(J, rd, crec_constructor(J, cd, J->base[0])); | ||
949 | else if (!crec_call(J, rd, cd)) | ||
950 | crec_call_meta(J, rd, cd->typeid); | ||
951 | } | ||
952 | |||
953 | static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm) | ||
954 | { | ||
955 | if (ctype_isnum(s[0]->info) && ctype_isnum(s[1]->info)) { | ||
956 | IRType dt; | ||
957 | CTypeID id; | ||
958 | TRef tr; | ||
959 | MSize i; | ||
960 | lj_needsplit(J); | ||
961 | if (((s[0]->info & CTF_UNSIGNED) && s[0]->size == 8) || | ||
962 | ((s[1]->info & CTF_UNSIGNED) && s[1]->size == 8)) { | ||
963 | dt = IRT_U64; id = CTID_UINT64; | ||
964 | } else { | ||
965 | dt = IRT_I64; id = CTID_INT64; | ||
966 | } | ||
967 | for (i = 0; i < 2; i++) { | ||
968 | IRType st = tref_type(sp[i]); | ||
969 | if (st == IRT_NUM || st == IRT_FLOAT) | ||
970 | sp[i] = emitconv(sp[i], dt, st, IRCONV_TRUNC|IRCONV_ANY); | ||
971 | else if (!(st == IRT_I64 || st == IRT_U64)) | ||
972 | sp[i] = emitconv(sp[i], dt, IRT_INT, | ||
973 | ((st - IRT_I8) & 1) ? 0 : IRCONV_SEXT); | ||
974 | } | ||
975 | if (mm < MM_add) { | ||
976 | /* Assume true comparison. Fixup and emit pending guard later. */ | ||
977 | IROp op; | ||
978 | if (mm == MM_eq) { | ||
979 | op = IR_EQ; | ||
980 | } else { | ||
981 | op = mm == MM_lt ? IR_LT : IR_LE; | ||
982 | if (dt == IRT_U64) | ||
983 | op += (IR_ULT-IR_LT); | ||
984 | } | ||
985 | lj_ir_set(J, IRTG(op, dt), sp[0], sp[1]); | ||
986 | J->postproc = LJ_POST_FIXGUARD; | ||
987 | return TREF_TRUE; | ||
988 | } else { | ||
989 | tr = emitir(IRT(mm+(int)IR_ADD-(int)MM_add, dt), sp[0], sp[1]); | ||
990 | } | ||
991 | return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); | ||
992 | } | ||
993 | return 0; | ||
994 | } | ||
995 | |||
996 | static TRef crec_arith_ptr(jit_State *J, TRef *sp, CType **s, MMS mm) | ||
997 | { | ||
998 | CTState *cts = ctype_ctsG(J2G(J)); | ||
999 | CType *ctp = s[0]; | ||
1000 | if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) { | ||
1001 | if ((mm == MM_sub || mm == MM_eq || mm == MM_lt || mm == MM_le) && | ||
1002 | (ctype_isptr(s[1]->info) || ctype_isrefarray(s[1]->info))) { | ||
1003 | if (mm == MM_sub) { /* Pointer difference. */ | ||
1004 | TRef tr; | ||
1005 | CTSize sz = lj_ctype_size(cts, ctype_cid(ctp->info)); | ||
1006 | if (sz == 0 || (sz & (sz-1)) != 0) | ||
1007 | return 0; /* NYI: integer division. */ | ||
1008 | tr = emitir(IRT(IR_SUB, IRT_PTR), sp[0], sp[1]); | ||
1009 | tr = emitir(IRT(IR_BSAR, IRT_INTP), tr, lj_ir_kint(J, lj_fls(sz))); | ||
1010 | #if LJ_64 | ||
1011 | tr = emitconv(tr, IRT_NUM, IRT_INTP, 0); | ||
1012 | #endif | ||
1013 | return tr; | ||
1014 | } else { /* Pointer comparison (unsigned). */ | ||
1015 | /* Assume true comparison. Fixup and emit pending guard later. */ | ||
1016 | IROp op = mm == MM_eq ? IR_EQ : mm == MM_lt ? IR_ULT : IR_ULE; | ||
1017 | lj_ir_set(J, IRTG(op, IRT_PTR), sp[0], sp[1]); | ||
1018 | J->postproc = LJ_POST_FIXGUARD; | ||
1019 | return TREF_TRUE; | ||
1020 | } | ||
1021 | } | ||
1022 | if (!((mm == MM_add || mm == MM_sub) && ctype_isnum(s[1]->info))) | ||
1023 | return 0; | ||
1024 | } else if (mm == MM_add && ctype_isnum(ctp->info) && | ||
1025 | (ctype_isptr(s[1]->info) || ctype_isrefarray(s[1]->info))) { | ||
1026 | TRef tr = sp[0]; sp[0] = sp[1]; sp[1] = tr; /* Swap pointer and index. */ | ||
1027 | ctp = s[1]; | ||
1028 | } else { | ||
1029 | return 0; | ||
1030 | } | ||
1031 | { | ||
1032 | TRef tr = sp[1]; | ||
1033 | IRType t = tref_type(tr); | ||
1034 | CTSize sz = lj_ctype_size(cts, ctype_cid(ctp->info)); | ||
1035 | CTypeID id; | ||
1036 | #if LJ_64 | ||
1037 | if (t == IRT_NUM || t == IRT_FLOAT) | ||
1038 | tr = emitconv(tr, IRT_INTP, t, IRCONV_TRUNC|IRCONV_ANY); | ||
1039 | else if (!(t == IRT_I64 || t == IRT_U64)) | ||
1040 | tr = emitconv(tr, IRT_INTP, IRT_INT, | ||
1041 | ((t - IRT_I8) & 1) ? 0 : IRCONV_SEXT); | ||
1042 | #else | ||
1043 | if (!tref_typerange(sp[1], IRT_I8, IRT_U32)) { | ||
1044 | tr = emitconv(tr, IRT_INTP, t, | ||
1045 | (t == IRT_NUM || t == IRT_FLOAT) ? | ||
1046 | IRCONV_TRUNC|IRCONV_ANY : 0); | ||
1047 | } | ||
1048 | #endif | ||
1049 | tr = emitir(IRT(IR_MUL, IRT_INTP), tr, lj_ir_kintp(J, sz)); | ||
1050 | tr = emitir(IRT(mm+(int)IR_ADD-(int)MM_add, IRT_PTR), sp[0], tr); | ||
1051 | id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)), | ||
1052 | CTSIZE_PTR); | ||
1053 | return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); | ||
1054 | } | ||
1055 | } | ||
1056 | |||
1057 | /* Record ctype arithmetic metamethods. */ | ||
1058 | static void crec_arith_meta(jit_State *J, CTState *cts, RecordFFData *rd) | ||
1059 | { | ||
1060 | cTValue *tv = NULL; | ||
1061 | if (J->base[0]) { | ||
1062 | if (tviscdata(&rd->argv[0])) | ||
1063 | tv = lj_ctype_meta(cts, argv2cdata(J, J->base[0], &rd->argv[0])->typeid, | ||
1064 | (MMS)rd->data); | ||
1065 | if (!tv && J->base[1] && tviscdata(&rd->argv[1])) | ||
1066 | tv = lj_ctype_meta(cts, argv2cdata(J, J->base[1], &rd->argv[1])->typeid, | ||
1067 | (MMS)rd->data); | ||
1068 | } | ||
1069 | if (tv && tvisfunc(tv)) { | ||
1070 | J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME; | ||
1071 | rd->nres = -1; /* Pending tailcall. */ | ||
1072 | } else { | ||
1073 | /* NYI: non-function metamethods. */ | ||
1074 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd) | ||
1079 | { | ||
1080 | CTState *cts = ctype_ctsG(J2G(J)); | ||
1081 | TRef sp[2]; | ||
1082 | CType *s[2]; | ||
1083 | MSize i; | ||
1084 | for (i = 0; i < 2; i++) { | ||
1085 | TRef tr = J->base[i]; | ||
1086 | CType *ct = ctype_get(cts, CTID_DOUBLE); | ||
1087 | if (!tr) { | ||
1088 | goto trymeta; | ||
1089 | } else if (tref_iscdata(tr)) { | ||
1090 | CTypeID id = argv2cdata(J, tr, &rd->argv[i])->typeid; | ||
1091 | ct = ctype_raw(cts, id); | ||
1092 | if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */ | ||
1093 | IRType t = (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32; | ||
1094 | if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct); | ||
1095 | tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_PTR); | ||
1096 | } else if (ctype_isinteger(ct->info) && ct->size == 8) { | ||
1097 | IRType t = (ct->info & CTF_UNSIGNED) ? IRT_U64 : IRT_I64; | ||
1098 | tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_INT64); | ||
1099 | lj_needsplit(J); | ||
1100 | goto ok; | ||
1101 | } else if (ctype_isfunc(ct->info)) { | ||
1102 | tr = emitir(IRT(IR_FLOAD, IRT_PTR), tr, IRFL_CDATA_PTR); | ||
1103 | ct = ctype_get(cts, | ||
1104 | lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR)); | ||
1105 | } else { | ||
1106 | tr = emitir(IRT(IR_ADD, IRT_PTR), tr, lj_ir_kintp(J, sizeof(GCcdata))); | ||
1107 | } | ||
1108 | if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); | ||
1109 | if (ctype_isnum(ct->info)) { | ||
1110 | IRType t = crec_ct2irt(ct); | ||
1111 | if (t == IRT_CDATA) goto trymeta; | ||
1112 | if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J); | ||
1113 | tr = emitir(IRT(IR_XLOAD, t), tr, 0); | ||
1114 | } else if (!(ctype_isptr(ct->info) || ctype_isrefarray(ct->info))) { | ||
1115 | goto trymeta; | ||
1116 | } | ||
1117 | } else if (tref_isnil(tr)) { | ||
1118 | tr = lj_ir_kptr(J, NULL); | ||
1119 | ct = ctype_get(cts, CTID_P_VOID); | ||
1120 | } else if (tref_isinteger(tr)) { | ||
1121 | ct = ctype_get(cts, CTID_INT32); | ||
1122 | } else if (!tref_isnum(tr)) { | ||
1123 | goto trymeta; | ||
1124 | } | ||
1125 | ok: | ||
1126 | s[i] = ct; | ||
1127 | sp[i] = tr; | ||
1128 | } | ||
1129 | { | ||
1130 | TRef tr; | ||
1131 | if ((tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) || | ||
1132 | (tr = crec_arith_ptr(J, sp, s, (MMS)rd->data))) { | ||
1133 | J->base[0] = tr; | ||
1134 | /* Fixup cdata comparisons, too. Avoids some cdata escapes. */ | ||
1135 | if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1) && | ||
1136 | !irt_isguard(J->guardemit)) { | ||
1137 | const BCIns *pc = frame_contpc(J->L->base-1) - 1; | ||
1138 | if (bc_op(*pc) <= BC_ISNEP) { | ||
1139 | setframe_pc(&J2G(J)->tmptv, pc); | ||
1140 | J2G(J)->tmptv.u32.lo = ((tref_istrue(tr) ^ bc_op(*pc)) & 1); | ||
1141 | J->postproc = LJ_POST_FIXCOMP; | ||
1142 | } | ||
1143 | } | ||
1144 | } else { | ||
1145 | trymeta: | ||
1146 | crec_arith_meta(J, cts, rd); | ||
1147 | } | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | /* -- C library namespace metamethods ------------------------------------- */ | ||
1152 | |||
1153 | void LJ_FASTCALL recff_clib_index(jit_State *J, RecordFFData *rd) | ||
1154 | { | ||
1155 | CTState *cts = ctype_ctsG(J2G(J)); | ||
1156 | if (tref_isudata(J->base[0]) && tref_isstr(J->base[1]) && | ||
1157 | udataV(&rd->argv[0])->udtype == UDTYPE_FFI_CLIB) { | ||
1158 | CLibrary *cl = (CLibrary *)uddata(udataV(&rd->argv[0])); | ||
1159 | GCstr *name = strV(&rd->argv[1]); | ||
1160 | CType *ct; | ||
1161 | CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX); | ||
1162 | cTValue *tv = lj_tab_getstr(cl->cache, name); | ||
1163 | rd->nres = rd->data; | ||
1164 | if (id && tv && !tvisnil(tv)) { | ||
1165 | /* Specialize to the symbol name and make the result a constant. */ | ||
1166 | emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, name)); | ||
1167 | if (ctype_isconstval(ct->info)) { | ||
1168 | if (ct->size >= 0x80000000u && | ||
1169 | (ctype_child(cts, ct)->info & CTF_UNSIGNED)) | ||
1170 | J->base[0] = lj_ir_knum(J, (lua_Number)(uint32_t)ct->size); | ||
1171 | else | ||
1172 | J->base[0] = lj_ir_kint(J, (int32_t)ct->size); | ||
1173 | } else if (ctype_isextern(ct->info)) { | ||
1174 | CTypeID sid = ctype_cid(ct->info); | ||
1175 | void *sp = *(void **)cdataptr(cdataV(tv)); | ||
1176 | TRef ptr; | ||
1177 | ct = ctype_raw(cts, sid); | ||
1178 | if (rd->data && ctype_isenum(ct->info)) ct = ctype_child(cts, ct); | ||
1179 | if (LJ_64 && !checkptr32(sp)) | ||
1180 | ptr = lj_ir_kintp(J, (uintptr_t)sp); | ||
1181 | else | ||
1182 | ptr = lj_ir_kptr(J, sp); | ||
1183 | if (rd->data) { | ||
1184 | J->base[0] = crec_tv_ct(J, ct, sid, ptr); | ||
1185 | } else { | ||
1186 | J->needsnap = 1; | ||
1187 | crec_ct_tv(J, ct, ptr, J->base[2], &rd->argv[2]); | ||
1188 | } | ||
1189 | } else { | ||
1190 | J->base[0] = lj_ir_kgc(J, obj2gco(cdataV(tv)), IRT_CDATA); | ||
1191 | } | ||
1192 | } else { | ||
1193 | lj_trace_err(J, LJ_TRERR_NOCACHE); | ||
1194 | } | ||
1195 | } /* else: interpreter will throw. */ | ||
1196 | } | ||
1197 | |||
1198 | /* -- FFI library functions ----------------------------------------------- */ | ||
1199 | |||
1200 | static TRef crec_toint(jit_State *J, CTState *cts, TRef sp, TValue *sval) | ||
1201 | { | ||
1202 | return crec_ct_tv(J, ctype_get(cts, CTID_INT32), 0, sp, sval); | ||
1203 | } | ||
1204 | |||
1205 | void LJ_FASTCALL recff_ffi_new(jit_State *J, RecordFFData *rd) | ||
1206 | { | ||
1207 | crec_alloc(J, rd, argv2ctype(J, J->base[0], &rd->argv[0])); | ||
1208 | } | ||
1209 | |||
1210 | void LJ_FASTCALL recff_ffi_errno(jit_State *J, RecordFFData *rd) | ||
1211 | { | ||
1212 | UNUSED(rd); | ||
1213 | if (J->base[0]) | ||
1214 | lj_trace_err(J, LJ_TRERR_NYICALL); | ||
1215 | J->base[0] = lj_ir_call(J, IRCALL_lj_vm_errno); | ||
1216 | } | ||
1217 | |||
1218 | void LJ_FASTCALL recff_ffi_string(jit_State *J, RecordFFData *rd) | ||
1219 | { | ||
1220 | CTState *cts = ctype_ctsG(J2G(J)); | ||
1221 | TRef tr = J->base[0]; | ||
1222 | if (tr) { | ||
1223 | TRef trlen = J->base[1]; | ||
1224 | if (trlen) { | ||
1225 | trlen = crec_toint(J, cts, trlen, &rd->argv[1]); | ||
1226 | tr = crec_ct_tv(J, ctype_get(cts, CTID_P_CVOID), 0, tr, &rd->argv[0]); | ||
1227 | } else { | ||
1228 | tr = crec_ct_tv(J, ctype_get(cts, CTID_P_CCHAR), 0, tr, &rd->argv[0]); | ||
1229 | trlen = lj_ir_call(J, IRCALL_strlen, tr); | ||
1230 | } | ||
1231 | J->base[0] = emitir(IRT(IR_XSNEW, IRT_STR), tr, trlen); | ||
1232 | } /* else: interpreter will throw. */ | ||
1233 | } | ||
1234 | |||
1235 | void LJ_FASTCALL recff_ffi_copy(jit_State *J, RecordFFData *rd) | ||
1236 | { | ||
1237 | CTState *cts = ctype_ctsG(J2G(J)); | ||
1238 | TRef trdst = J->base[0], trsrc = J->base[1], trlen = J->base[2]; | ||
1239 | if (trdst && trsrc && (trlen || tref_isstr(trsrc))) { | ||
1240 | trdst = crec_ct_tv(J, ctype_get(cts, CTID_P_VOID), 0, trdst, &rd->argv[0]); | ||
1241 | trsrc = crec_ct_tv(J, ctype_get(cts, CTID_P_CVOID), 0, trsrc, &rd->argv[1]); | ||
1242 | if (trlen) { | ||
1243 | trlen = crec_toint(J, cts, trlen, &rd->argv[2]); | ||
1244 | } else { | ||
1245 | trlen = emitir(IRTI(IR_FLOAD), J->base[1], IRFL_STR_LEN); | ||
1246 | trlen = emitir(IRTI(IR_ADD), trlen, lj_ir_kint(J, 1)); | ||
1247 | } | ||
1248 | lj_ir_call(J, IRCALL_memcpy, trdst, trsrc, trlen); | ||
1249 | emitir(IRT(IR_XBAR, IRT_NIL), 0, 0); | ||
1250 | rd->nres = 0; | ||
1251 | } /* else: interpreter will throw. */ | ||
1252 | } | ||
1253 | |||
1254 | void LJ_FASTCALL recff_ffi_fill(jit_State *J, RecordFFData *rd) | ||
1255 | { | ||
1256 | CTState *cts = ctype_ctsG(J2G(J)); | ||
1257 | TRef tr = J->base[0], trlen = J->base[1], trfill = J->base[2]; | ||
1258 | if (tr && trlen) { | ||
1259 | tr = crec_ct_tv(J, ctype_get(cts, CTID_P_VOID), 0, tr, &rd->argv[0]); | ||
1260 | trlen = crec_toint(J, cts, trlen, &rd->argv[1]); | ||
1261 | if (trfill) | ||
1262 | trfill = crec_toint(J, cts, trfill, &rd->argv[2]); | ||
1263 | else | ||
1264 | trfill = lj_ir_kint(J, 0); | ||
1265 | lj_ir_call(J, IRCALL_memset, tr, trfill, trlen); | ||
1266 | emitir(IRT(IR_XBAR, IRT_NIL), 0, 0); | ||
1267 | rd->nres = 0; | ||
1268 | } /* else: interpreter will throw. */ | ||
1269 | } | ||
1270 | |||
1271 | void LJ_FASTCALL recff_ffi_istype(jit_State *J, RecordFFData *rd) | ||
1272 | { | ||
1273 | argv2ctype(J, J->base[0], &rd->argv[0]); | ||
1274 | if (tref_iscdata(J->base[1])) { | ||
1275 | argv2ctype(J, J->base[1], &rd->argv[1]); | ||
1276 | J->postproc = LJ_POST_FIXBOOL; | ||
1277 | J->base[0] = TREF_TRUE; | ||
1278 | } else { | ||
1279 | J->base[0] = TREF_FALSE; | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | void LJ_FASTCALL recff_ffi_abi(jit_State *J, RecordFFData *rd) | ||
1284 | { | ||
1285 | if (tref_isstr(J->base[0])) { | ||
1286 | /* Specialize to the ABI string to make the boolean result a constant. */ | ||
1287 | emitir(IRTG(IR_EQ, IRT_STR), J->base[0], lj_ir_kstr(J, strV(&rd->argv[0]))); | ||
1288 | J->postproc = LJ_POST_FIXBOOL; | ||
1289 | J->base[0] = TREF_TRUE; | ||
1290 | } /* else: interpreter will throw. */ | ||
1291 | } | ||
1292 | |||
1293 | /* -- Miscellaneous library functions ------------------------------------- */ | ||
1294 | |||
1295 | void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd) | ||
1296 | { | ||
1297 | CTState *cts = ctype_ctsG(J2G(J)); | ||
1298 | CType *d, *ct = lj_ctype_rawref(cts, cdataV(&rd->argv[0])->typeid); | ||
1299 | if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); | ||
1300 | if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) { | ||
1301 | if (ctype_isinteger_or_bool(ct->info) && ct->size <= 4 && | ||
1302 | !(ct->size == 4 && (ct->info & CTF_UNSIGNED))) | ||
1303 | d = ctype_get(cts, CTID_INT32); | ||
1304 | else | ||
1305 | d = ctype_get(cts, CTID_DOUBLE); | ||
1306 | J->base[0] = crec_ct_tv(J, d, 0, J->base[0], &rd->argv[0]); | ||
1307 | } else { | ||
1308 | J->base[0] = TREF_NIL; | ||
1309 | } | ||
1310 | } | ||
1311 | |||
1312 | #undef IR | ||
1313 | #undef emitir | ||
1314 | #undef emitconv | ||
1315 | |||
1316 | #endif | ||