3 ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
17 #include "lj_dispatch.h"
20 #include "lj_bcdump.h"
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. */
34 /* -- Output buffer handling ---------------------------------------------- */
36 /* Resize buffer if needed. */
37 static LJ_NOINLINE
void bcwrite_resize(BCWriteCtx
*ctx
, MSize len
)
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
);
44 /* Need a certain amount of buffer space. */
45 static LJ_AINLINE
void bcwrite_need(BCWriteCtx
*ctx
, MSize len
)
47 if (LJ_UNLIKELY(ctx
->sb
.n
+ len
> ctx
->sb
.sz
))
48 bcwrite_resize(ctx
, len
);
51 /* Add memory block to buffer. */
52 static void bcwrite_block(BCWriteCtx
*ctx
, const void *p
, MSize len
)
54 uint8_t *q
= (uint8_t *)(ctx
->sb
.buf
+ ctx
->sb
.n
);
57 for (i
= 0; i
< len
; i
++) q
[i
] = ((uint8_t *)p
)[i
];
60 /* Add byte to buffer. */
61 static LJ_AINLINE
void bcwrite_byte(BCWriteCtx
*ctx
, uint8_t b
)
63 ctx
->sb
.buf
[ctx
->sb
.n
++] = b
;
66 /* Add ULEB128 value to buffer. */
67 static void bcwrite_uleb128(BCWriteCtx
*ctx
, uint32_t v
)
70 uint8_t *p
= (uint8_t *)ctx
->sb
.buf
;
71 for (; v
>= 0x80; v
>>= 7)
72 p
[n
++] = (uint8_t)((v
& 0x7f) | 0x80);
77 /* -- Bytecode writer ----------------------------------------------------- */
79 /* Write a single constant key/value of a template table. */
80 static void bcwrite_ktabk(BCWriteCtx
*ctx
, cTValue
*o
, int narrow
)
82 bcwrite_need(ctx
, 1+10);
84 const GCstr
*str
= strV(o
);
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
);
102 bcwrite_byte(ctx
, BCDUMP_KTAB_NUM
);
103 bcwrite_uleb128(ctx
, o
->u32
.lo
);
104 bcwrite_uleb128(ctx
, o
->u32
.hi
);
106 lua_assert(tvispri(o
));
107 bcwrite_byte(ctx
, BCDUMP_KTAB_NIL
+~itype(o
));
111 /* Write a template table. */
112 static void bcwrite_ktab(BCWriteCtx
*ctx
, const GCtab
*t
)
114 MSize narray
= 0, nhash
= 0;
115 if (t
->asize
> 0) { /* Determine max. length of array part. */
117 TValue
*array
= tvref(t
->array
);
118 for (i
= (ptrdiff_t)t
->asize
-1; i
>= 0; i
--)
119 if (!tvisnil(&array
[i
]))
121 narray
= (MSize
)(i
+1);
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
);
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). */
134 TValue
*o
= tvref(t
->array
);
135 for (i
= 0; i
< narray
; i
++, o
++)
136 bcwrite_ktabk(ctx
, o
, 1);
138 if (nhash
) { /* Write hash entries. */
140 Node
*node
= noderef(t
->node
) + t
->hmask
;
142 if (!tvisnil(&node
->val
)) {
143 bcwrite_ktabk(ctx
, &node
->key
, 0);
144 bcwrite_ktabk(ctx
, &node
->val
, 1);
150 /* Write GC constants of a prototype. */
151 static void bcwrite_kgc(BCWriteCtx
*ctx
, GCproto
*pt
)
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
);
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
;
166 } else if (o
->gch
.gct
== ~LJ_TCDATA
) {
167 CTypeID id
= gco2cd(o
)->typeid;
169 if (id
== CTID_INT64
) {
171 } else if (id
== CTID_UINT64
) {
174 lua_assert(id
== CTID_COMPLEX_DOUBLE
);
175 tp
= BCDUMP_KGC_COMPLEX
;
179 lua_assert(o
->gch
.gct
== ~LJ_TTAB
);
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
));
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
);
204 /* Write number constants of a prototype. */
205 static void bcwrite_knum(BCWriteCtx
*ctx
, GCproto
*pt
)
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
++) {
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
);
220 if (num
== (lua_Number
)k
) { /* -0 is never a constant. */
222 bcwrite_uleb128(ctx
, 2*(uint32_t)k
);
223 if (k
< 0) ctx
->sb
.buf
[ctx
->sb
.n
-1] |= 0x10;
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
);
234 /* Write bytecode instructions. */
235 static void bcwrite_bytecode(BCWriteCtx
*ctx
, GCproto
*pt
)
237 MSize nbc
= pt
->sizebc
-1; /* Omit the [JI]FUNC* header. */
239 uint8_t *p
= (uint8_t *)&ctx
->sb
.buf
[ctx
->sb
.n
];
241 bcwrite_block(ctx
, proto_bc(pt
)+1, nbc
*(MSize
)sizeof(BCIns
));
243 /* Unpatch modified bytecode containing ILOOP/JLOOP etc. */
244 if ((pt
->flags
& PROTO_ILOOP
) || pt
->trace
) {
245 jit_State
*J
= L2J(ctx
->L
);
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
||
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
);
264 /* Write prototype. */
265 static void bcwrite_proto(BCWriteCtx
*ctx
, GCproto
*pt
)
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
));
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);
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);
294 if (proto_lineinfo(pt
))
295 sizedbg
= pt
->sizept
- (MSize
)((char *)proto_lineinfo(pt
) - (char *)pt
);
296 bcwrite_uleb128(ctx
, sizedbg
);
298 bcwrite_uleb128(ctx
, pt
->firstline
);
299 bcwrite_uleb128(ctx
, pt
->numline
);
303 /* Write bytecode instructions and upvalue refs. */
304 bcwrite_bytecode(ctx
, pt
);
305 bcwrite_block(ctx
, proto_uv(pt
), pt
->sizeuv
*2);
307 /* Write constants. */
308 bcwrite_kgc(ctx
, pt
);
309 bcwrite_knum(ctx
, pt
);
311 /* Write debug info, if not stripped. */
313 bcwrite_need(ctx
, sizedbg
);
314 bcwrite_block(ctx
, proto_lineinfo(pt
), sizedbg
);
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;
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
);
328 /* Write header of bytecode dump. */
329 static void bcwrite_header(BCWriteCtx
*ctx
)
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));
344 bcwrite_uleb128(ctx
, len
);
345 bcwrite_block(ctx
, name
, len
);
347 ctx
->status
= ctx
->wfunc(ctx
->L
, ctx
->sb
.buf
, ctx
->sb
.n
, ctx
->wdata
);
350 /* Write footer of bytecode dump. */
351 static void bcwrite_footer(BCWriteCtx
*ctx
)
353 if (ctx
->status
== 0) {
355 ctx
->status
= ctx
->wfunc(ctx
->L
, &zero
, 1, ctx
->wdata
);
359 /* Protected callback for bytecode writer. */
360 static TValue
*cpwriter(lua_State
*L
, lua_CFunction dummy
, void *ud
)
362 BCWriteCtx
*ctx
= (BCWriteCtx
*)ud
;
364 lj_str_resizebuf(L
, &ctx
->sb
, 1024); /* Avoids resize for most prototypes. */
366 bcwrite_proto(ctx
, ctx
->pt
);
371 /* Write bytecode for a prototype. */
372 int lj_bcwrite(lua_State
*L
, GCproto
*pt
, lua_Writer writer
, void *data
,
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
);