3 ** Copyright (C) 2005-2023 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 memcpy(p
, &traceref(J
, rd
)->startins
, 4);
268 /* Write prototype. */
269 static void bcwrite_proto(BCWriteCtx
*ctx
, GCproto
*pt
)
273 /* Recursively write children of prototype. */
274 if ((pt
->flags
& PROTO_CHILD
)) {
275 ptrdiff_t i
, n
= pt
->sizekgc
;
276 GCRef
*kr
= mref(pt
->k
, GCRef
) - 1;
277 for (i
= 0; i
< n
; i
++, kr
--) {
278 GCobj
*o
= gcref(*kr
);
279 if (o
->gch
.gct
== ~LJ_TPROTO
)
280 bcwrite_proto(ctx
, gco2pt(o
));
284 /* Start writing the prototype info to a buffer. */
285 lj_str_resetbuf(&ctx
->sb
);
286 ctx
->sb
.n
= 5; /* Leave room for final size. */
287 bcwrite_need(ctx
, 4+6*5+(pt
->sizebc
-1)*(MSize
)sizeof(BCIns
)+pt
->sizeuv
*2);
289 /* Write prototype header. */
290 bcwrite_byte(ctx
, (pt
->flags
& (PROTO_CHILD
|PROTO_VARARG
|PROTO_FFI
)));
291 bcwrite_byte(ctx
, pt
->numparams
);
292 bcwrite_byte(ctx
, pt
->framesize
);
293 bcwrite_byte(ctx
, pt
->sizeuv
);
294 bcwrite_uleb128(ctx
, pt
->sizekgc
);
295 bcwrite_uleb128(ctx
, pt
->sizekn
);
296 bcwrite_uleb128(ctx
, pt
->sizebc
-1);
298 if (proto_lineinfo(pt
))
299 sizedbg
= pt
->sizept
- (MSize
)((char *)proto_lineinfo(pt
) - (char *)pt
);
300 bcwrite_uleb128(ctx
, sizedbg
);
302 bcwrite_uleb128(ctx
, pt
->firstline
);
303 bcwrite_uleb128(ctx
, pt
->numline
);
307 /* Write bytecode instructions and upvalue refs. */
308 bcwrite_bytecode(ctx
, pt
);
309 bcwrite_block(ctx
, proto_uv(pt
), pt
->sizeuv
*2);
311 /* Write constants. */
312 bcwrite_kgc(ctx
, pt
);
313 bcwrite_knum(ctx
, pt
);
315 /* Write debug info, if not stripped. */
317 bcwrite_need(ctx
, sizedbg
);
318 bcwrite_block(ctx
, proto_lineinfo(pt
), sizedbg
);
321 /* Pass buffer to writer function. */
322 if (ctx
->status
== 0) {
323 MSize n
= ctx
->sb
.n
- 5;
324 MSize nn
= (lj_fls(n
)+8)*9 >> 6;
326 bcwrite_uleb128(ctx
, n
); /* Fill in final size. */
327 lua_assert(ctx
->sb
.n
== 5);
328 ctx
->status
= ctx
->wfunc(ctx
->L
, ctx
->sb
.buf
+5-nn
, nn
+n
, ctx
->wdata
);
332 /* Write header of bytecode dump. */
333 static void bcwrite_header(BCWriteCtx
*ctx
)
335 GCstr
*chunkname
= proto_chunkname(ctx
->pt
);
336 const char *name
= strdata(chunkname
);
337 MSize len
= chunkname
->len
;
338 lj_str_resetbuf(&ctx
->sb
);
339 bcwrite_need(ctx
, 5+5+len
);
340 bcwrite_byte(ctx
, BCDUMP_HEAD1
);
341 bcwrite_byte(ctx
, BCDUMP_HEAD2
);
342 bcwrite_byte(ctx
, BCDUMP_HEAD3
);
343 bcwrite_byte(ctx
, BCDUMP_VERSION
);
344 bcwrite_byte(ctx
, (ctx
->strip
? BCDUMP_F_STRIP
: 0) +
345 (LJ_BE
? BCDUMP_F_BE
: 0) +
346 ((ctx
->pt
->flags
& PROTO_FFI
) ? BCDUMP_F_FFI
: 0));
348 bcwrite_uleb128(ctx
, len
);
349 bcwrite_block(ctx
, name
, len
);
351 ctx
->status
= ctx
->wfunc(ctx
->L
, ctx
->sb
.buf
, ctx
->sb
.n
, ctx
->wdata
);
354 /* Write footer of bytecode dump. */
355 static void bcwrite_footer(BCWriteCtx
*ctx
)
357 if (ctx
->status
== 0) {
359 ctx
->status
= ctx
->wfunc(ctx
->L
, &zero
, 1, ctx
->wdata
);
363 /* Protected callback for bytecode writer. */
364 static TValue
*cpwriter(lua_State
*L
, lua_CFunction dummy
, void *ud
)
366 BCWriteCtx
*ctx
= (BCWriteCtx
*)ud
;
368 lj_str_resizebuf(L
, &ctx
->sb
, 1024); /* Avoids resize for most prototypes. */
370 bcwrite_proto(ctx
, ctx
->pt
);
375 /* Write bytecode for a prototype. */
376 int lj_bcwrite(lua_State
*L
, GCproto
*pt
, lua_Writer writer
, void *data
,
387 lj_str_initbuf(&ctx
.sb
);
388 status
= lj_vm_cpcall(L
, NULL
, &ctx
, cpwriter
);
389 if (status
== 0) status
= ctx
.status
;
390 lj_str_freebuf(G(ctx
.L
), &ctx
.sb
);