3 ** Copyright (C) 2005-2012 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
)->ctypeid
;
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
);
183 /* Write constant type. */
184 bcwrite_need(ctx
, need
);
185 bcwrite_uleb128(ctx
, tp
);
186 /* Write constant data (if any). */
187 if (tp
>= BCDUMP_KGC_STR
) {
188 bcwrite_block(ctx
, strdata(gco2str(o
)), gco2str(o
)->len
);
189 } else if (tp
== BCDUMP_KGC_TAB
) {
190 bcwrite_ktab(ctx
, gco2tab(o
));
192 } else if (tp
!= BCDUMP_KGC_CHILD
) {
193 cTValue
*p
= (TValue
*)cdataptr(gco2cd(o
));
194 bcwrite_uleb128(ctx
, p
[0].u32
.lo
);
195 bcwrite_uleb128(ctx
, p
[0].u32
.hi
);
196 if (tp
== BCDUMP_KGC_COMPLEX
) {
197 bcwrite_uleb128(ctx
, p
[1].u32
.lo
);
198 bcwrite_uleb128(ctx
, p
[1].u32
.hi
);
205 /* Write number constants of a prototype. */
206 static void bcwrite_knum(BCWriteCtx
*ctx
, GCproto
*pt
)
208 MSize i
, sizekn
= pt
->sizekn
;
209 cTValue
*o
= mref(pt
->k
, TValue
);
210 bcwrite_need(ctx
, 10*sizekn
);
211 for (i
= 0; i
< sizekn
; i
++, o
++) {
217 /* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */
218 if (!LJ_DUALNUM
) { /* Narrow number constants to integers. */
219 lua_Number num
= numV(o
);
221 if (num
== (lua_Number
)k
) { /* -0 is never a constant. */
223 bcwrite_uleb128(ctx
, 2*(uint32_t)k
| ((uint32_t)k
& 0x80000000u
));
225 char *p
= &ctx
->sb
.buf
[ctx
->sb
.n
-1];
226 *p
= (*p
& 7) | ((k
>>27) & 0x18);
231 bcwrite_uleb128(ctx
, 1+(2*o
->u32
.lo
| (o
->u32
.lo
& 0x80000000u
)));
232 if (o
->u32
.lo
>= 0x80000000u
) {
233 char *p
= &ctx
->sb
.buf
[ctx
->sb
.n
-1];
234 *p
= (*p
& 7) | ((o
->u32
.lo
>>27) & 0x18);
236 bcwrite_uleb128(ctx
, o
->u32
.hi
);
241 /* Write bytecode instructions. */
242 static void bcwrite_bytecode(BCWriteCtx
*ctx
, GCproto
*pt
)
244 MSize nbc
= pt
->sizebc
-1; /* Omit the [JI]FUNC* header. */
246 uint8_t *p
= (uint8_t *)&ctx
->sb
.buf
[ctx
->sb
.n
];
248 bcwrite_block(ctx
, proto_bc(pt
)+1, nbc
*(MSize
)sizeof(BCIns
));
250 /* Unpatch modified bytecode containing ILOOP/JLOOP etc. */
251 if ((pt
->flags
& PROTO_ILOOP
) || pt
->trace
) {
252 jit_State
*J
= L2J(ctx
->L
);
254 for (i
= 0; i
< nbc
; i
++, p
+= sizeof(BCIns
)) {
255 BCOp op
= (BCOp
)p
[LJ_ENDIAN_SELECT(0, 3)];
256 if (op
== BC_IFORL
|| op
== BC_IITERL
|| op
== BC_ILOOP
||
258 p
[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op
-BC_IFORL
+BC_FORL
);
259 } else if (op
== BC_JFORL
|| op
== BC_JITERL
|| op
== BC_JLOOP
) {
260 BCReg rd
= p
[LJ_ENDIAN_SELECT(2, 1)] + (p
[LJ_ENDIAN_SELECT(3, 0)] << 8);
261 BCIns ins
= traceref(J
, rd
)->startins
;
262 p
[LJ_ENDIAN_SELECT(0, 3)] = (uint8_t)(op
-BC_JFORL
+BC_FORL
);
263 p
[LJ_ENDIAN_SELECT(2, 1)] = bc_c(ins
);
264 p
[LJ_ENDIAN_SELECT(3, 0)] = bc_b(ins
);
271 /* Write prototype. */
272 static void bcwrite_proto(BCWriteCtx
*ctx
, GCproto
*pt
)
276 /* Recursively write children of prototype. */
277 if ((pt
->flags
& PROTO_CHILD
)) {
278 ptrdiff_t i
, n
= pt
->sizekgc
;
279 GCRef
*kr
= mref(pt
->k
, GCRef
) - 1;
280 for (i
= 0; i
< n
; i
++, kr
--) {
281 GCobj
*o
= gcref(*kr
);
282 if (o
->gch
.gct
== ~LJ_TPROTO
)
283 bcwrite_proto(ctx
, gco2pt(o
));
287 /* Start writing the prototype info to a buffer. */
288 lj_str_resetbuf(&ctx
->sb
);
289 ctx
->sb
.n
= 5; /* Leave room for final size. */
290 bcwrite_need(ctx
, 4+6*5+(pt
->sizebc
-1)*(MSize
)sizeof(BCIns
)+pt
->sizeuv
*2);
292 /* Write prototype header. */
293 bcwrite_byte(ctx
, (pt
->flags
& (PROTO_CHILD
|PROTO_VARARG
|PROTO_FFI
)));
294 bcwrite_byte(ctx
, pt
->numparams
);
295 bcwrite_byte(ctx
, pt
->framesize
);
296 bcwrite_byte(ctx
, pt
->sizeuv
);
297 bcwrite_uleb128(ctx
, pt
->sizekgc
);
298 bcwrite_uleb128(ctx
, pt
->sizekn
);
299 bcwrite_uleb128(ctx
, pt
->sizebc
-1);
301 if (proto_lineinfo(pt
))
302 sizedbg
= pt
->sizept
- (MSize
)((char *)proto_lineinfo(pt
) - (char *)pt
);
303 bcwrite_uleb128(ctx
, sizedbg
);
305 bcwrite_uleb128(ctx
, pt
->firstline
);
306 bcwrite_uleb128(ctx
, pt
->numline
);
310 /* Write bytecode instructions and upvalue refs. */
311 bcwrite_bytecode(ctx
, pt
);
312 bcwrite_block(ctx
, proto_uv(pt
), pt
->sizeuv
*2);
314 /* Write constants. */
315 bcwrite_kgc(ctx
, pt
);
316 bcwrite_knum(ctx
, pt
);
318 /* Write debug info, if not stripped. */
320 bcwrite_need(ctx
, sizedbg
);
321 bcwrite_block(ctx
, proto_lineinfo(pt
), sizedbg
);
324 /* Pass buffer to writer function. */
325 if (ctx
->status
== 0) {
326 MSize n
= ctx
->sb
.n
- 5;
327 MSize nn
= 1 + lj_fls(n
)/7;
329 bcwrite_uleb128(ctx
, n
); /* Fill in final size. */
330 lua_assert(ctx
->sb
.n
== 5);
331 ctx
->status
= ctx
->wfunc(ctx
->L
, ctx
->sb
.buf
+5-nn
, nn
+n
, ctx
->wdata
);
335 /* Write header of bytecode dump. */
336 static void bcwrite_header(BCWriteCtx
*ctx
)
338 GCstr
*chunkname
= proto_chunkname(ctx
->pt
);
339 const char *name
= strdata(chunkname
);
340 MSize len
= chunkname
->len
;
341 lj_str_resetbuf(&ctx
->sb
);
342 bcwrite_need(ctx
, 5+5+len
);
343 bcwrite_byte(ctx
, BCDUMP_HEAD1
);
344 bcwrite_byte(ctx
, BCDUMP_HEAD2
);
345 bcwrite_byte(ctx
, BCDUMP_HEAD3
);
346 bcwrite_byte(ctx
, BCDUMP_VERSION
);
347 bcwrite_byte(ctx
, (ctx
->strip
? BCDUMP_F_STRIP
: 0) +
348 (LJ_BE
? BCDUMP_F_BE
: 0) +
349 ((ctx
->pt
->flags
& PROTO_FFI
) ? BCDUMP_F_FFI
: 0));
351 bcwrite_uleb128(ctx
, len
);
352 bcwrite_block(ctx
, name
, len
);
354 ctx
->status
= ctx
->wfunc(ctx
->L
, ctx
->sb
.buf
, ctx
->sb
.n
, ctx
->wdata
);
357 /* Write footer of bytecode dump. */
358 static void bcwrite_footer(BCWriteCtx
*ctx
)
360 if (ctx
->status
== 0) {
362 ctx
->status
= ctx
->wfunc(ctx
->L
, &zero
, 1, ctx
->wdata
);
366 /* Protected callback for bytecode writer. */
367 static TValue
*cpwriter(lua_State
*L
, lua_CFunction dummy
, void *ud
)
369 BCWriteCtx
*ctx
= (BCWriteCtx
*)ud
;
371 lj_str_resizebuf(L
, &ctx
->sb
, 1024); /* Avoids resize for most prototypes. */
373 bcwrite_proto(ctx
, ctx
->pt
);
378 /* Write bytecode for a prototype. */
379 int lj_bcwrite(lua_State
*L
, GCproto
*pt
, lua_Writer writer
, void *data
,
390 lj_str_initbuf(&ctx
.sb
);
391 status
= lj_vm_cpcall(L
, NULL
, &ctx
, cpwriter
);
392 if (status
== 0) status
= ctx
.status
;
393 lj_str_freebuf(G(ctx
.L
), &ctx
.sb
);