diff options
Diffstat (limited to 'libraries/luajit-2.0/src/lj_bcwrite.c')
-rw-r--r-- | libraries/luajit-2.0/src/lj_bcwrite.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/libraries/luajit-2.0/src/lj_bcwrite.c b/libraries/luajit-2.0/src/lj_bcwrite.c new file mode 100644 index 0000000..de9b4cf --- /dev/null +++ b/libraries/luajit-2.0/src/lj_bcwrite.c | |||
@@ -0,0 +1,389 @@ | |||
1 | /* | ||
2 | ** Bytecode writer. | ||
3 | ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | #define lj_bcwrite_c | ||
7 | #define LUA_CORE | ||
8 | |||
9 | #include "lj_obj.h" | ||
10 | #include "lj_gc.h" | ||
11 | #include "lj_str.h" | ||
12 | #include "lj_bc.h" | ||
13 | #if LJ_HASFFI | ||
14 | #include "lj_ctype.h" | ||
15 | #endif | ||
16 | #if LJ_HASJIT | ||
17 | #include "lj_dispatch.h" | ||
18 | #include "lj_jit.h" | ||
19 | #endif | ||
20 | #include "lj_bcdump.h" | ||
21 | #include "lj_vm.h" | ||
22 | |||
23 | /* Context for bytecode writer. */ | ||
24 | typedef struct BCWriteCtx { | ||
25 | SBuf sb; /* Output buffer. */ | ||
26 | lua_State *L; /* Lua state. */ | ||
27 | GCproto *pt; /* Root prototype. */ | ||
28 | lua_Writer wfunc; /* Writer callback. */ | ||
29 | void *wdata; /* Writer callback data. */ | ||
30 | int strip; /* Strip debug info. */ | ||
31 | int status; /* Status from writer callback. */ | ||
32 | } BCWriteCtx; | ||
33 | |||
34 | /* -- Output buffer handling ---------------------------------------------- */ | ||
35 | |||
36 | /* Resize buffer if needed. */ | ||
37 | static LJ_NOINLINE void bcwrite_resize(BCWriteCtx *ctx, MSize len) | ||
38 | { | ||
39 | MSize sz = ctx->sb.sz * 2; | ||
40 | while (ctx->sb.n + len > sz) sz = sz * 2; | ||
41 | lj_str_resizebuf(ctx->L, &ctx->sb, sz); | ||
42 | } | ||
43 | |||
44 | /* Need a certain amount of buffer space. */ | ||
45 | static LJ_AINLINE void bcwrite_need(BCWriteCtx *ctx, MSize len) | ||
46 | { | ||
47 | if (LJ_UNLIKELY(ctx->sb.n + len > ctx->sb.sz)) | ||
48 | bcwrite_resize(ctx, len); | ||
49 | } | ||
50 | |||
51 | /* Add memory block to buffer. */ | ||
52 | static void bcwrite_block(BCWriteCtx *ctx, const void *p, MSize len) | ||
53 | { | ||
54 | uint8_t *q = (uint8_t *)(ctx->sb.buf + ctx->sb.n); | ||
55 | MSize i; | ||
56 | ctx->sb.n += len; | ||
57 | for (i = 0; i < len; i++) q[i] = ((uint8_t *)p)[i]; | ||
58 | } | ||
59 | |||
60 | /* Add byte to buffer. */ | ||
61 | static LJ_AINLINE void bcwrite_byte(BCWriteCtx *ctx, uint8_t b) | ||
62 | { | ||
63 | ctx->sb.buf[ctx->sb.n++] = b; | ||
64 | } | ||
65 | |||
66 | /* Add ULEB128 value to buffer. */ | ||
67 | static void bcwrite_uleb128(BCWriteCtx *ctx, uint32_t v) | ||
68 | { | ||
69 | MSize n = ctx->sb.n; | ||
70 | uint8_t *p = (uint8_t *)ctx->sb.buf; | ||
71 | for (; v >= 0x80; v >>= 7) | ||
72 | p[n++] = (uint8_t)((v & 0x7f) | 0x80); | ||
73 | p[n++] = (uint8_t)v; | ||
74 | ctx->sb.n = n; | ||
75 | } | ||
76 | |||
77 | /* -- Bytecode writer ----------------------------------------------------- */ | ||
78 | |||
79 | /* Write a single constant key/value of a template table. */ | ||
80 | static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow) | ||
81 | { | ||
82 | bcwrite_need(ctx, 1+10); | ||
83 | if (tvisstr(o)) { | ||
84 | const GCstr *str = strV(o); | ||
85 | MSize len = str->len; | ||
86 | bcwrite_need(ctx, 5+len); | ||
87 | bcwrite_uleb128(ctx, BCDUMP_KTAB_STR+len); | ||
88 | bcwrite_block(ctx, strdata(str), len); | ||
89 | } else if (tvisint(o)) { | ||
90 | bcwrite_byte(ctx, BCDUMP_KTAB_INT); | ||
91 | bcwrite_uleb128(ctx, intV(o)); | ||
92 | } else if (tvisnum(o)) { | ||
93 | if (!LJ_DUALNUM && narrow) { /* Narrow number constants to integers. */ | ||
94 | lua_Number num = numV(o); | ||
95 | int32_t k = lj_num2int(num); | ||
96 | if (num == (lua_Number)k) { /* -0 is never a constant. */ | ||
97 | bcwrite_byte(ctx, BCDUMP_KTAB_INT); | ||
98 | bcwrite_uleb128(ctx, k); | ||
99 | return; | ||
100 | } | ||
101 | } | ||
102 | bcwrite_byte(ctx, BCDUMP_KTAB_NUM); | ||
103 | bcwrite_uleb128(ctx, o->u32.lo); | ||
104 | bcwrite_uleb128(ctx, o->u32.hi); | ||
105 | } else { | ||
106 | lua_assert(tvispri(o)); | ||
107 | bcwrite_byte(ctx, BCDUMP_KTAB_NIL+~itype(o)); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /* Write a template table. */ | ||
112 | static void bcwrite_ktab(BCWriteCtx *ctx, const GCtab *t) | ||
113 | { | ||
114 | MSize narray = 0, nhash = 0; | ||
115 | if (t->asize > 0) { /* Determine max. length of array part. */ | ||
116 | ptrdiff_t i; | ||
117 | TValue *array = tvref(t->array); | ||
118 | for (i = (ptrdiff_t)t->asize-1; i >= 0; i--) | ||
119 | if (!tvisnil(&array[i])) | ||
120 | break; | ||
121 | narray = (MSize)(i+1); | ||
122 | } | ||
123 | if (t->hmask > 0) { /* Count number of used hash slots. */ | ||
124 | MSize i, hmask = t->hmask; | ||
125 | Node *node = noderef(t->node); | ||
126 | for (i = 0; i <= hmask; i++) | ||
127 | nhash += !tvisnil(&node[i].val); | ||
128 | } | ||
129 | /* Write number of array slots and hash slots. */ | ||
130 | bcwrite_uleb128(ctx, narray); | ||
131 | bcwrite_uleb128(ctx, nhash); | ||
132 | if (narray) { /* Write array entries (may contain nil). */ | ||
133 | MSize i; | ||
134 | TValue *o = tvref(t->array); | ||
135 | for (i = 0; i < narray; i++, o++) | ||
136 | bcwrite_ktabk(ctx, o, 1); | ||
137 | } | ||
138 | if (nhash) { /* Write hash entries. */ | ||
139 | MSize i = nhash; | ||
140 | Node *node = noderef(t->node) + t->hmask; | ||
141 | for (;; node--) | ||
142 | if (!tvisnil(&node->val)) { | ||
143 | bcwrite_ktabk(ctx, &node->key, 0); | ||
144 | bcwrite_ktabk(ctx, &node->val, 1); | ||
145 | if (--i == 0) break; | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /* Write GC constants of a prototype. */ | ||
151 | static void bcwrite_kgc(BCWriteCtx *ctx, GCproto *pt) | ||
152 | { | ||
153 | MSize i, sizekgc = pt->sizekgc; | ||
154 | GCRef *kr = mref(pt->k, GCRef) - (ptrdiff_t)sizekgc; | ||
155 | for (i = 0; i < sizekgc; i++, kr++) { | ||
156 | GCobj *o = gcref(*kr); | ||
157 | MSize tp, need = 1; | ||
158 | /* Determine constant type and needed size. */ | ||
159 | if (o->gch.gct == ~LJ_TSTR) { | ||
160 | tp = BCDUMP_KGC_STR + gco2str(o)->len; | ||
161 | need = 5+gco2str(o)->len; | ||
162 | } else if (o->gch.gct == ~LJ_TPROTO) { | ||
163 | lua_assert((pt->flags & PROTO_CHILD)); | ||
164 | tp = BCDUMP_KGC_CHILD; | ||
165 | #if LJ_HASFFI | ||
166 | } else if (o->gch.gct == ~LJ_TCDATA) { | ||
167 | CTypeID id = gco2cd(o)->typeid; | ||
168 | need = 1+4*5; | ||
169 | if (id == CTID_INT64) { | ||
170 | tp = BCDUMP_KGC_I64; | ||
171 | } else if (id == CTID_UINT64) { | ||
172 | tp = BCDUMP_KGC_U64; | ||
173 | } else { | ||
174 | lua_assert(id == CTID_COMPLEX_DOUBLE); | ||
175 | tp = BCDUMP_KGC_COMPLEX; | ||
176 | } | ||
177 | #endif | ||
178 | } else { | ||
179 | lua_assert(o->gch.gct == ~LJ_TTAB); | ||
180 | tp = BCDUMP_KGC_TAB; | ||
181 | } | ||
182 | /* Write constant type. */ | ||
183 | bcwrite_need(ctx, need); | ||
184 | bcwrite_uleb128(ctx, tp); | ||
185 | /* Write constant data (if any). */ | ||
186 | if (tp >= BCDUMP_KGC_STR) { | ||
187 | bcwrite_block(ctx, strdata(gco2str(o)), gco2str(o)->len); | ||
188 | } else if (tp == BCDUMP_KGC_TAB) { | ||
189 | bcwrite_ktab(ctx, gco2tab(o)); | ||
190 | #if LJ_HASFFI | ||
191 | } else if (tp != BCDUMP_KGC_CHILD) { | ||
192 | cTValue *p = (TValue *)cdataptr(gco2cd(o)); | ||
193 | bcwrite_uleb128(ctx, p[0].u32.lo); | ||
194 | bcwrite_uleb128(ctx, p[0].u32.hi); | ||
195 | if (tp == BCDUMP_KGC_COMPLEX) { | ||
196 | bcwrite_uleb128(ctx, p[1].u32.lo); | ||
197 | bcwrite_uleb128(ctx, p[1].u32.hi); | ||
198 | } | ||
199 | #endif | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /* Write number constants of a prototype. */ | ||
205 | static void bcwrite_knum(BCWriteCtx *ctx, GCproto *pt) | ||
206 | { | ||
207 | MSize i, sizekn = pt->sizekn; | ||
208 | cTValue *o = mref(pt->k, TValue); | ||
209 | bcwrite_need(ctx, 10*sizekn); | ||
210 | for (i = 0; i < sizekn; i++, o++) { | ||
211 | int32_t k; | ||
212 | if (tvisint(o)) { | ||
213 | k = intV(o); | ||
214 | goto save_int; | ||
215 | } else { | ||
216 | /* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */ | ||
217 | if (!LJ_DUALNUM) { /* Narrow number constants to integers. */ | ||
218 | lua_Number num = numV(o); | ||
219 | k = lj_num2int(num); | ||
220 | if (num == (lua_Number)k) { /* -0 is never a constant. */ | ||
221 | save_int: | ||
222 | bcwrite_uleb128(ctx, 2*(uint32_t)k); | ||
223 | if (k < 0) ctx->sb.buf[ctx->sb.n-1] |= 0x10; | ||
224 | continue; | ||
225 | } | ||
226 | } | ||
227 | bcwrite_uleb128(ctx, 1+2*o->u32.lo); | ||
228 | if (o->u32.lo >= 0x80000000u) ctx->sb.buf[ctx->sb.n-1] |= 0x10; | ||
229 | bcwrite_uleb128(ctx, o->u32.hi); | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /* Write bytecode instructions. */ | ||
235 | static void bcwrite_bytecode(BCWriteCtx *ctx, GCproto *pt) | ||
236 | { | ||
237 | MSize nbc = pt->sizebc-1; /* Omit the [JI]FUNC* header. */ | ||
238 | #if LJ_HASJIT | ||
239 | uint8_t *p = (uint8_t *)&ctx->sb.buf[ctx->sb.n]; | ||
240 | #endif | ||
241 | bcwrite_block(ctx, proto_bc(pt)+1, nbc*(MSize)sizeof(BCIns)); | ||
242 | #if LJ_HASJIT | ||
243 | /* Unpatch modified bytecode containing ILOOP/JLOOP etc. */ | ||
244 | if ((pt->flags & PROTO_ILOOP) || pt->trace) { | ||
245 | jit_State *J = L2J(ctx->L); | ||
246 | MSize i; | ||
247 | for (i = 0; i < nbc; i++, p += sizeof(BCIns)) { | ||
248 | BCOp op = (BCOp)p[LJ_ENDIAN_SELECT(0, 3)]; | ||
249 | if (op == BC_IFORL || op == BC_IITERL || op == BC_ILOOP || | ||
250 | op == BC_JFORI) { | ||
251 | p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_IFORL+BC_FORL); | ||
252 | } else if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) { | ||
253 | BCReg rd = p[LJ_ENDIAN_SELECT(2, 1)] + (p[LJ_ENDIAN_SELECT(3, 0)] << 8); | ||
254 | BCIns ins = traceref(J, rd)->startins; | ||
255 | p[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op-BC_JFORL+BC_FORL); | ||
256 | p[LJ_ENDIAN_SELECT(2, 1)] = bc_c(ins); | ||
257 | p[LJ_ENDIAN_SELECT(3, 0)] = bc_b(ins); | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | #endif | ||
262 | } | ||
263 | |||
264 | /* Write prototype. */ | ||
265 | static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt) | ||
266 | { | ||
267 | MSize sizedbg = 0; | ||
268 | |||
269 | /* Recursively write children of prototype. */ | ||
270 | if ((pt->flags & PROTO_CHILD)) { | ||
271 | ptrdiff_t i, n = pt->sizekgc; | ||
272 | GCRef *kr = mref(pt->k, GCRef) - 1; | ||
273 | for (i = 0; i < n; i++, kr--) { | ||
274 | GCobj *o = gcref(*kr); | ||
275 | if (o->gch.gct == ~LJ_TPROTO) | ||
276 | bcwrite_proto(ctx, gco2pt(o)); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | /* Start writing the prototype info to a buffer. */ | ||
281 | lj_str_resetbuf(&ctx->sb); | ||
282 | ctx->sb.n = 5; /* Leave room for final size. */ | ||
283 | bcwrite_need(ctx, 4+6*5+(pt->sizebc-1)*(MSize)sizeof(BCIns)+pt->sizeuv*2); | ||
284 | |||
285 | /* Write prototype header. */ | ||
286 | bcwrite_byte(ctx, (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI))); | ||
287 | bcwrite_byte(ctx, pt->numparams); | ||
288 | bcwrite_byte(ctx, pt->framesize); | ||
289 | bcwrite_byte(ctx, pt->sizeuv); | ||
290 | bcwrite_uleb128(ctx, pt->sizekgc); | ||
291 | bcwrite_uleb128(ctx, pt->sizekn); | ||
292 | bcwrite_uleb128(ctx, pt->sizebc-1); | ||
293 | if (!ctx->strip) { | ||
294 | if (proto_lineinfo(pt)) | ||
295 | sizedbg = pt->sizept - (MSize)((char *)proto_lineinfo(pt) - (char *)pt); | ||
296 | bcwrite_uleb128(ctx, sizedbg); | ||
297 | if (sizedbg) { | ||
298 | bcwrite_uleb128(ctx, pt->firstline); | ||
299 | bcwrite_uleb128(ctx, pt->numline); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | /* Write bytecode instructions and upvalue refs. */ | ||
304 | bcwrite_bytecode(ctx, pt); | ||
305 | bcwrite_block(ctx, proto_uv(pt), pt->sizeuv*2); | ||
306 | |||
307 | /* Write constants. */ | ||
308 | bcwrite_kgc(ctx, pt); | ||
309 | bcwrite_knum(ctx, pt); | ||
310 | |||
311 | /* Write debug info, if not stripped. */ | ||
312 | if (sizedbg) { | ||
313 | bcwrite_need(ctx, sizedbg); | ||
314 | bcwrite_block(ctx, proto_lineinfo(pt), sizedbg); | ||
315 | } | ||
316 | |||
317 | /* Pass buffer to writer function. */ | ||
318 | if (ctx->status == 0) { | ||
319 | MSize n = ctx->sb.n - 5; | ||
320 | MSize nn = 1 + lj_fls(n)/7; | ||
321 | ctx->sb.n = 5 - nn; | ||
322 | bcwrite_uleb128(ctx, n); /* Fill in final size. */ | ||
323 | lua_assert(ctx->sb.n == 5); | ||
324 | ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf+5-nn, nn+n, ctx->wdata); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | /* Write header of bytecode dump. */ | ||
329 | static void bcwrite_header(BCWriteCtx *ctx) | ||
330 | { | ||
331 | GCstr *chunkname = proto_chunkname(ctx->pt); | ||
332 | const char *name = strdata(chunkname); | ||
333 | MSize len = chunkname->len; | ||
334 | lj_str_resetbuf(&ctx->sb); | ||
335 | bcwrite_need(ctx, 5+5+len); | ||
336 | bcwrite_byte(ctx, BCDUMP_HEAD1); | ||
337 | bcwrite_byte(ctx, BCDUMP_HEAD2); | ||
338 | bcwrite_byte(ctx, BCDUMP_HEAD3); | ||
339 | bcwrite_byte(ctx, BCDUMP_VERSION); | ||
340 | bcwrite_byte(ctx, (ctx->strip ? BCDUMP_F_STRIP : 0) + | ||
341 | (LJ_BE ? BCDUMP_F_BE : 0) + | ||
342 | ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0)); | ||
343 | if (!ctx->strip) { | ||
344 | bcwrite_uleb128(ctx, len); | ||
345 | bcwrite_block(ctx, name, len); | ||
346 | } | ||
347 | ctx->status = ctx->wfunc(ctx->L, ctx->sb.buf, ctx->sb.n, ctx->wdata); | ||
348 | } | ||
349 | |||
350 | /* Write footer of bytecode dump. */ | ||
351 | static void bcwrite_footer(BCWriteCtx *ctx) | ||
352 | { | ||
353 | if (ctx->status == 0) { | ||
354 | uint8_t zero = 0; | ||
355 | ctx->status = ctx->wfunc(ctx->L, &zero, 1, ctx->wdata); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | /* Protected callback for bytecode writer. */ | ||
360 | static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud) | ||
361 | { | ||
362 | BCWriteCtx *ctx = (BCWriteCtx *)ud; | ||
363 | UNUSED(dummy); | ||
364 | lj_str_resizebuf(L, &ctx->sb, 1024); /* Avoids resize for most prototypes. */ | ||
365 | bcwrite_header(ctx); | ||
366 | bcwrite_proto(ctx, ctx->pt); | ||
367 | bcwrite_footer(ctx); | ||
368 | return NULL; | ||
369 | } | ||
370 | |||
371 | /* Write bytecode for a prototype. */ | ||
372 | int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data, | ||
373 | int strip) | ||
374 | { | ||
375 | BCWriteCtx ctx; | ||
376 | int status; | ||
377 | ctx.L = L; | ||
378 | ctx.pt = pt; | ||
379 | ctx.wfunc = writer; | ||
380 | ctx.wdata = data; | ||
381 | ctx.strip = strip; | ||
382 | ctx.status = 0; | ||
383 | lj_str_initbuf(&ctx.sb); | ||
384 | status = lj_vm_cpcall(L, NULL, &ctx, cpwriter); | ||
385 | if (status == 0) status = ctx.status; | ||
386 | lj_str_freebuf(G(ctx.L), &ctx.sb); | ||
387 | return status; | ||
388 | } | ||
389 | |||