aboutsummaryrefslogtreecommitdiff
path: root/src/vm_arm64.dasc
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm_arm64.dasc')
-rw-r--r--src/vm_arm64.dasc3988
1 files changed, 3988 insertions, 0 deletions
diff --git a/src/vm_arm64.dasc b/src/vm_arm64.dasc
new file mode 100644
index 00000000..edceb549
--- /dev/null
+++ b/src/vm_arm64.dasc
@@ -0,0 +1,3988 @@
1|// Low-level VM code for ARM64 CPUs.
2|// Bytecode interpreter, fast functions and helper functions.
3|// Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h
4|
5|.arch arm64
6|.section code_op, code_sub
7|
8|.actionlist build_actionlist
9|.globals GLOB_
10|.globalnames globnames
11|.externnames extnames
12|
13|// Note: The ragged indentation of the instructions is intentional.
14|// The starting columns indicate data dependencies.
15|
16|//-----------------------------------------------------------------------
17|
18|// ARM64 registers and the AAPCS64 ABI 1.0 at a glance:
19|//
20|// x0-x17 temp, x19-x28 callee-saved, x29 fp, x30 lr
21|// x18 is reserved on most platforms. Don't use it, save it or restore it.
22|// x31 doesn't exist. Register number 31 either means xzr/wzr (zero) or sp,
23|// depending on the instruction.
24|// v0-v7 temp, v8-v15 callee-saved (only d8-d15 preserved), v16-v31 temp
25|//
26|// x0-x7/v0-v7 hold parameters and results.
27|
28|// Fixed register assignments for the interpreter.
29|
30|// The following must be C callee-save.
31|.define BASE, x19 // Base of current Lua stack frame.
32|.define KBASE, x20 // Constants of current Lua function.
33|.define PC, x21 // Next PC.
34|.define GLREG, x22 // Global state.
35|.define LREG, x23 // Register holding lua_State (also in SAVE_L).
36|.define TISNUM, x24 // Constant LJ_TISNUM << 47.
37|.define TISNUMhi, x25 // Constant LJ_TISNUM << 15.
38|.define TISNIL, x26 // Constant -1LL.
39|.define fp, x29 // Yes, we have to maintain a frame pointer.
40|
41|.define ST_INTERP, w26 // Constant -1.
42|
43|// The following temporaries are not saved across C calls, except for RA/RC.
44|.define RA, x27
45|.define RC, x28
46|.define RB, x17
47|.define RAw, w27
48|.define RCw, w28
49|.define RBw, w17
50|.define INS, x16
51|.define INSw, w16
52|.define ITYPE, x15
53|.define TMP0, x8
54|.define TMP1, x9
55|.define TMP2, x10
56|.define TMP3, x11
57|.define TMP0w, w8
58|.define TMP1w, w9
59|.define TMP2w, w10
60|.define TMP3w, w11
61|
62|// Calling conventions. Also used as temporaries.
63|.define CARG1, x0
64|.define CARG2, x1
65|.define CARG3, x2
66|.define CARG4, x3
67|.define CARG5, x4
68|.define CARG1w, w0
69|.define CARG2w, w1
70|.define CARG3w, w2
71|.define CARG4w, w3
72|.define CARG5w, w4
73|
74|.define FARG1, d0
75|.define FARG2, d1
76|
77|.define CRET1, x0
78|.define CRET1w, w0
79|
80|// Stack layout while in interpreter. Must match with lj_frame.h.
81|
82|.define CFRAME_SPACE, 208
83|//----- 16 byte aligned, <-- sp entering interpreter
84|// Unused [sp, #204] // 32 bit values
85|.define SAVE_NRES, [sp, #200]
86|.define SAVE_ERRF, [sp, #196]
87|.define SAVE_MULTRES, [sp, #192]
88|.define TMPD, [sp, #184] // 64 bit values
89|.define SAVE_L, [sp, #176]
90|.define SAVE_PC, [sp, #168]
91|.define SAVE_CFRAME, [sp, #160]
92|.define SAVE_FPR_, 96 // 96+8*8: 64 bit FPR saves
93|.define SAVE_GPR_, 16 // 16+10*8: 64 bit GPR saves
94|.define SAVE_LR, [sp, #8]
95|.define SAVE_FP, [sp]
96|//----- 16 byte aligned, <-- sp while in interpreter.
97|
98|.define TMPDofs, #184
99|
100|.macro save_, gpr1, gpr2, fpr1, fpr2
101| stp d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(fpr1-8)*8]
102| stp x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(gpr1-19)*8]
103|.endmacro
104|.macro rest_, gpr1, gpr2, fpr1, fpr2
105| ldp d..fpr1, d..fpr2, [sp, # SAVE_FPR_+(fpr1-8)*8]
106| ldp x..gpr1, x..gpr2, [sp, # SAVE_GPR_+(gpr1-19)*8]
107|.endmacro
108|
109|.macro saveregs
110| stp fp, lr, [sp, #-CFRAME_SPACE]!
111| add fp, sp, #0
112| stp x19, x20, [sp, # SAVE_GPR_]
113| save_ 21, 22, 8, 9
114| save_ 23, 24, 10, 11
115| save_ 25, 26, 12, 13
116| save_ 27, 28, 14, 15
117|.endmacro
118|.macro restoreregs
119| ldp x19, x20, [sp, # SAVE_GPR_]
120| rest_ 21, 22, 8, 9
121| rest_ 23, 24, 10, 11
122| rest_ 25, 26, 12, 13
123| rest_ 27, 28, 14, 15
124| ldp fp, lr, [sp], # CFRAME_SPACE
125|.endmacro
126|
127|// Type definitions. Some of these are only used for documentation.
128|.type L, lua_State, LREG
129|.type GL, global_State, GLREG
130|.type TVALUE, TValue
131|.type GCOBJ, GCobj
132|.type STR, GCstr
133|.type TAB, GCtab
134|.type LFUNC, GCfuncL
135|.type CFUNC, GCfuncC
136|.type PROTO, GCproto
137|.type UPVAL, GCupval
138|.type NODE, Node
139|.type NARGS8, int
140|.type TRACE, GCtrace
141|.type SBUF, SBuf
142|
143|//-----------------------------------------------------------------------
144|
145|// Trap for not-yet-implemented parts.
146|.macro NYI; brk; .endmacro
147|
148|//-----------------------------------------------------------------------
149|
150|// Access to frame relative to BASE.
151|.define FRAME_FUNC, #-16
152|.define FRAME_PC, #-8
153|
154|// Endian-specific defines.
155|.if ENDIAN_LE
156|.define LO, 0
157|.define OFS_RD, 2
158|.define OFS_RB, 3
159|.define OFS_RA, 1
160|.define OFS_OP, 0
161|.else
162|.define LO, 4
163|.define OFS_RD, 0
164|.define OFS_RB, 0
165|.define OFS_RA, 2
166|.define OFS_OP, 3
167|.endif
168|
169|.macro decode_RA, dst, ins; ubfx dst, ins, #8, #8; .endmacro
170|.macro decode_RB, dst, ins; ubfx dst, ins, #24, #8; .endmacro
171|.macro decode_RC, dst, ins; ubfx dst, ins, #16, #8; .endmacro
172|.macro decode_RD, dst, ins; ubfx dst, ins, #16, #16; .endmacro
173|.macro decode_RC8RD, dst, src; ubfiz dst, src, #3, #8; .endmacro
174|
175|// Instruction decode+dispatch.
176|.macro ins_NEXT
177| ldr INSw, [PC], #4
178| add TMP1, GL, INS, uxtb #3
179| decode_RA RA, INS
180| ldr TMP0, [TMP1, #GG_G2DISP]
181| decode_RD RC, INS
182| br TMP0
183|.endmacro
184|
185|// Instruction footer.
186|.if 1
187| // Replicated dispatch. Less unpredictable branches, but higher I-Cache use.
188| .define ins_next, ins_NEXT
189| .define ins_next_, ins_NEXT
190|.else
191| // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch.
192| // Affects only certain kinds of benchmarks (and only with -j off).
193| .macro ins_next
194| b ->ins_next
195| .endmacro
196| .macro ins_next_
197| ->ins_next:
198| ins_NEXT
199| .endmacro
200|.endif
201|
202|// Call decode and dispatch.
203|.macro ins_callt
204| // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC
205| ldr PC, LFUNC:CARG3->pc
206| ldr INSw, [PC], #4
207| add TMP1, GL, INS, uxtb #3
208| decode_RA RA, INS
209| ldr TMP0, [TMP1, #GG_G2DISP]
210| add RA, BASE, RA, lsl #3
211| br TMP0
212|.endmacro
213|
214|.macro ins_call
215| // BASE = new base, CARG3 = LFUNC/CFUNC, RC = nargs*8, PC = caller PC
216| str PC, [BASE, FRAME_PC]
217| ins_callt
218|.endmacro
219|
220|//-----------------------------------------------------------------------
221|
222|// Macros to check the TValue type and extract the GCobj. Branch on failure.
223|.macro checktp, reg, tp, target
224| asr ITYPE, reg, #47
225| cmn ITYPE, #-tp
226| and reg, reg, #LJ_GCVMASK
227| bne target
228|.endmacro
229|.macro checktp, dst, reg, tp, target
230| asr ITYPE, reg, #47
231| cmn ITYPE, #-tp
232| and dst, reg, #LJ_GCVMASK
233| bne target
234|.endmacro
235|.macro checkstr, reg, target; checktp reg, LJ_TSTR, target; .endmacro
236|.macro checktab, reg, target; checktp reg, LJ_TTAB, target; .endmacro
237|.macro checkfunc, reg, target; checktp reg, LJ_TFUNC, target; .endmacro
238|.macro checkint, reg, target
239| cmp TISNUMhi, reg, lsr #32
240| bne target
241|.endmacro
242|.macro checknum, reg, target
243| cmp TISNUMhi, reg, lsr #32
244| bls target
245|.endmacro
246|.macro checknumber, reg, target
247| cmp TISNUMhi, reg, lsr #32
248| blo target
249|.endmacro
250|
251|.macro mov_false, reg; movn reg, #0x8000, lsl #32; .endmacro
252|.macro mov_true, reg; movn reg, #0x0001, lsl #48; .endmacro
253|
254#define GL_J(field) (GG_G2J + (int)offsetof(jit_State, field))
255|
256#define PC2PROTO(field) ((int)offsetof(GCproto, field)-(int)sizeof(GCproto))
257|
258|.macro hotcheck, delta
259| lsr CARG1, PC, #1
260| and CARG1, CARG1, #126
261| add CARG1, CARG1, #GG_G2DISP+GG_DISP2HOT
262| ldrh CARG2w, [GL, CARG1]
263| subs CARG2, CARG2, #delta
264| strh CARG2w, [GL, CARG1]
265|.endmacro
266|
267|.macro hotloop
268| hotcheck HOTCOUNT_LOOP
269| blo ->vm_hotloop
270|.endmacro
271|
272|.macro hotcall
273| hotcheck HOTCOUNT_CALL
274| blo ->vm_hotcall
275|.endmacro
276|
277|// Set current VM state.
278|.macro mv_vmstate, reg, st; movn reg, #LJ_VMST_..st; .endmacro
279|.macro st_vmstate, reg; str reg, GL->vmstate; .endmacro
280|
281|// Move table write barrier back. Overwrites mark and tmp.
282|.macro barrierback, tab, mark, tmp
283| ldr tmp, GL->gc.grayagain
284| and mark, mark, #~LJ_GC_BLACK // black2gray(tab)
285| str tab, GL->gc.grayagain
286| strb mark, tab->marked
287| str tmp, tab->gclist
288|.endmacro
289|
290|//-----------------------------------------------------------------------
291
292#if !LJ_DUALNUM
293#error "Only dual-number mode supported for ARM64 target"
294#endif
295
296/* Generate subroutines used by opcodes and other parts of the VM. */
297/* The .code_sub section should be last to help static branch prediction. */
298static void build_subroutines(BuildCtx *ctx)
299{
300 |.code_sub
301 |
302 |//-----------------------------------------------------------------------
303 |//-- Return handling ----------------------------------------------------
304 |//-----------------------------------------------------------------------
305 |
306 |->vm_returnp:
307 | // See vm_return. Also: RB = previous base.
308 | tbz PC, #2, ->cont_dispatch // (PC & FRAME_P) == 0?
309 |
310 | // Return from pcall or xpcall fast func.
311 | ldr PC, [RB, FRAME_PC] // Fetch PC of previous frame.
312 | mov_true TMP0
313 | mov BASE, RB
314 | // Prepending may overwrite the pcall frame, so do it at the end.
315 | str TMP0, [RA, #-8]! // Prepend true to results.
316 |
317 |->vm_returnc:
318 | adds RC, RC, #8 // RC = (nresults+1)*8.
319 | mov CRET1, #LUA_YIELD
320 | beq ->vm_unwind_c_eh
321 | str RCw, SAVE_MULTRES
322 | ands CARG1, PC, #FRAME_TYPE
323 | beq ->BC_RET_Z // Handle regular return to Lua.
324 |
325 |->vm_return:
326 | // BASE = base, RA = resultptr, RC/MULTRES = (nresults+1)*8, PC = return
327 | // CARG1 = PC & FRAME_TYPE
328 | and RB, PC, #~FRAME_TYPEP
329 | cmp CARG1, #FRAME_C
330 | sub RB, BASE, RB // RB = previous base.
331 | bne ->vm_returnp
332 |
333 | str RB, L->base
334 | ldrsw CARG2, SAVE_NRES // CARG2 = nresults+1.
335 | mv_vmstate TMP0w, C
336 | sub BASE, BASE, #16
337 | subs TMP2, RC, #8
338 | st_vmstate TMP0w
339 | beq >2
340 |1:
341 | subs TMP2, TMP2, #8
342 | ldr TMP0, [RA], #8
343 | str TMP0, [BASE], #8
344 | bne <1
345 |2:
346 | cmp RC, CARG2, lsl #3 // More/less results wanted?
347 | bne >6
348 |3:
349 | str BASE, L->top // Store new top.
350 |
351 |->vm_leave_cp:
352 | ldr RC, SAVE_CFRAME // Restore previous C frame.
353 | mov CRET1, #0 // Ok return status for vm_pcall.
354 | str RC, L->cframe
355 |
356 |->vm_leave_unw:
357 | restoreregs
358 | ret
359 |
360 |6:
361 | bgt >7 // Less results wanted?
362 | // More results wanted. Check stack size and fill up results with nil.
363 | ldr CARG3, L->maxstack
364 | cmp BASE, CARG3
365 | bhs >8
366 | str TISNIL, [BASE], #8
367 | add RC, RC, #8
368 | b <2
369 |
370 |7: // Less results wanted.
371 | cbz CARG2, <3 // LUA_MULTRET+1 case?
372 | sub CARG1, RC, CARG2, lsl #3
373 | sub BASE, BASE, CARG1 // Shrink top.
374 | b <3
375 |
376 |8: // Corner case: need to grow stack for filling up results.
377 | // This can happen if:
378 | // - A C function grows the stack (a lot).
379 | // - The GC shrinks the stack in between.
380 | // - A return back from a lua_call() with (high) nresults adjustment.
381 | str BASE, L->top // Save current top held in BASE (yes).
382 | mov CARG1, L
383 | bl extern lj_state_growstack // (lua_State *L, int n)
384 | ldr BASE, L->top // Need the (realloced) L->top in BASE.
385 | ldrsw CARG2, SAVE_NRES
386 | b <2
387 |
388 |->vm_unwind_c: // Unwind C stack, return from vm_pcall.
389 | // (void *cframe, int errcode)
390 | mov sp, CARG1
391 | mov CRET1, CARG2
392 |->vm_unwind_c_eh: // Landing pad for external unwinder.
393 | ldr L, SAVE_L
394 | mv_vmstate TMP0w, C
395 | ldr GL, L->glref
396 | st_vmstate TMP0w
397 | b ->vm_leave_unw
398 |
399 |->vm_unwind_ff: // Unwind C stack, return from ff pcall.
400 | // (void *cframe)
401 | and sp, CARG1, #CFRAME_RAWMASK
402 |->vm_unwind_ff_eh: // Landing pad for external unwinder.
403 | ldr L, SAVE_L
404 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
405 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
406 | movn TISNIL, #0
407 | mov RC, #16 // 2 results: false + error message.
408 | ldr BASE, L->base
409 | ldr GL, L->glref // Setup pointer to global state.
410 | mov_false TMP0
411 | sub RA, BASE, #8 // Results start at BASE-8.
412 | ldr PC, [BASE, FRAME_PC] // Fetch PC of previous frame.
413 | str TMP0, [BASE, #-8] // Prepend false to error message.
414 | st_vmstate ST_INTERP
415 | b ->vm_returnc
416 |
417 |//-----------------------------------------------------------------------
418 |//-- Grow stack for calls -----------------------------------------------
419 |//-----------------------------------------------------------------------
420 |
421 |->vm_growstack_c: // Grow stack for C function.
422 | // CARG1 = L
423 | mov CARG2, #LUA_MINSTACK
424 | b >2
425 |
426 |->vm_growstack_l: // Grow stack for Lua function.
427 | // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC
428 | add RC, BASE, RC
429 | sub RA, RA, BASE
430 | mov CARG1, L
431 | stp BASE, RC, L->base
432 | add PC, PC, #4 // Must point after first instruction.
433 | lsr CARG2, RA, #3
434 |2:
435 | // L->base = new base, L->top = top
436 | str PC, SAVE_PC
437 | bl extern lj_state_growstack // (lua_State *L, int n)
438 | ldp BASE, RC, L->base
439 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
440 | sub NARGS8:RC, RC, BASE
441 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
442 | // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC
443 | ins_callt // Just retry the call.
444 |
445 |//-----------------------------------------------------------------------
446 |//-- Entry points into the assembler VM ---------------------------------
447 |//-----------------------------------------------------------------------
448 |
449 |->vm_resume: // Setup C frame and resume thread.
450 | // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0)
451 | saveregs
452 | mov L, CARG1
453 | ldr GL, L->glref // Setup pointer to global state.
454 | mov BASE, CARG2
455 | str L, SAVE_L
456 | mov PC, #FRAME_CP
457 | str wzr, SAVE_NRES
458 | add TMP0, sp, #CFRAME_RESUME
459 | ldrb TMP1w, L->status
460 | str wzr, SAVE_ERRF
461 | str L, SAVE_PC // Any value outside of bytecode is ok.
462 | str xzr, SAVE_CFRAME
463 | str TMP0, L->cframe
464 | cbz TMP1w, >3
465 |
466 | // Resume after yield (like a return).
467 | str L, GL->cur_L
468 | mov RA, BASE
469 | ldp BASE, CARG1, L->base
470 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
471 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
472 | ldr PC, [BASE, FRAME_PC]
473 | strb wzr, L->status
474 | movn TISNIL, #0
475 | sub RC, CARG1, BASE
476 | ands CARG1, PC, #FRAME_TYPE
477 | add RC, RC, #8
478 | st_vmstate ST_INTERP
479 | str RCw, SAVE_MULTRES
480 | beq ->BC_RET_Z
481 | b ->vm_return
482 |
483 |->vm_pcall: // Setup protected C frame and enter VM.
484 | // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef)
485 | saveregs
486 | mov PC, #FRAME_CP
487 | str CARG4w, SAVE_ERRF
488 | b >1
489 |
490 |->vm_call: // Setup C frame and enter VM.
491 | // (lua_State *L, TValue *base, int nres1)
492 | saveregs
493 | mov PC, #FRAME_C
494 |
495 |1: // Entry point for vm_pcall above (PC = ftype).
496 | ldr RC, L:CARG1->cframe
497 | str CARG3w, SAVE_NRES
498 | mov L, CARG1
499 | str CARG1, SAVE_L
500 | ldr GL, L->glref // Setup pointer to global state.
501 | mov BASE, CARG2
502 | str CARG1, SAVE_PC // Any value outside of bytecode is ok.
503 | str RC, SAVE_CFRAME
504 | str fp, L->cframe // Add our C frame to cframe chain.
505 |
506 |3: // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype).
507 | str L, GL->cur_L
508 | ldp RB, CARG1, L->base // RB = old base (for vmeta_call).
509 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
510 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
511 | add PC, PC, BASE
512 | movn TISNIL, #0
513 | sub PC, PC, RB // PC = frame delta + frame type
514 | sub NARGS8:RC, CARG1, BASE
515 | st_vmstate ST_INTERP
516 |
517 |->vm_call_dispatch:
518 | // RB = old base, BASE = new base, RC = nargs*8, PC = caller PC
519 | ldr CARG3, [BASE, FRAME_FUNC]
520 | checkfunc CARG3, ->vmeta_call
521 |
522 |->vm_call_dispatch_f:
523 | ins_call
524 | // BASE = new base, CARG3 = func, RC = nargs*8, PC = caller PC
525 |
526 |->vm_cpcall: // Setup protected C frame, call C.
527 | // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
528 | saveregs
529 | mov L, CARG1
530 | ldr RA, L:CARG1->stack
531 | str CARG1, SAVE_L
532 | ldr GL, L->glref // Setup pointer to global state.
533 | ldr RB, L->top
534 | str CARG1, SAVE_PC // Any value outside of bytecode is ok.
535 | ldr RC, L->cframe
536 | sub RA, RA, RB // Compute -savestack(L, L->top).
537 | str RAw, SAVE_NRES // Neg. delta means cframe w/o frame.
538 | str wzr, SAVE_ERRF // No error function.
539 | str RC, SAVE_CFRAME
540 | str fp, L->cframe // Add our C frame to cframe chain.
541 | str L, GL->cur_L
542 | blr CARG4 // (lua_State *L, lua_CFunction func, void *ud)
543 | mov BASE, CRET1
544 | mov PC, #FRAME_CP
545 | cbnz BASE, <3 // Else continue with the call.
546 | b ->vm_leave_cp // No base? Just remove C frame.
547 |
548 |//-----------------------------------------------------------------------
549 |//-- Metamethod handling ------------------------------------------------
550 |//-----------------------------------------------------------------------
551 |
552 |//-- Continuation dispatch ----------------------------------------------
553 |
554 |->cont_dispatch:
555 | // BASE = meta base, RA = resultptr, RC = (nresults+1)*8
556 | ldr LFUNC:CARG3, [RB, FRAME_FUNC]
557 | ldr CARG1, [BASE, #-32] // Get continuation.
558 | mov CARG4, BASE
559 | mov BASE, RB // Restore caller BASE.
560 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
561 |.if FFI
562 | cmp CARG1, #1
563 |.endif
564 | ldr PC, [CARG4, #-24] // Restore PC from [cont|PC].
565 | ldr CARG3, LFUNC:CARG3->pc
566 | add TMP0, RA, RC
567 | str TISNIL, [TMP0, #-8] // Ensure one valid arg.
568 |.if FFI
569 | bls >1
570 |.endif
571 | ldr KBASE, [CARG3, #PC2PROTO(k)]
572 | // BASE = base, RA = resultptr, CARG4 = meta base
573 | br CARG1
574 |
575 |.if FFI
576 |1:
577 | beq ->cont_ffi_callback // cont = 1: return from FFI callback.
578 | // cont = 0: tailcall from C function.
579 | sub CARG4, CARG4, #32
580 | sub RC, CARG4, BASE
581 | b ->vm_call_tail
582 |.endif
583 |
584 |->cont_cat: // RA = resultptr, CARG4 = meta base
585 | ldr INSw, [PC, #-4]
586 | sub CARG2, CARG4, #32
587 | ldr TMP0, [RA]
588 | str BASE, L->base
589 | decode_RB RB, INS
590 | decode_RA RA, INS
591 | add TMP1, BASE, RB, lsl #3
592 | subs TMP1, CARG2, TMP1
593 | beq >1
594 | str TMP0, [CARG2]
595 | lsr CARG3, TMP1, #3
596 | b ->BC_CAT_Z
597 |
598 |1:
599 | str TMP0, [BASE, RA, lsl #3]
600 | b ->cont_nop
601 |
602 |//-- Table indexing metamethods -----------------------------------------
603 |
604 |->vmeta_tgets1:
605 | movn CARG4, #~LJ_TSTR
606 | add CARG2, BASE, RB, lsl #3
607 | add CARG4, STR:RC, CARG4, lsl #47
608 | b >2
609 |
610 |->vmeta_tgets:
611 | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48
612 | str CARG2, GL->tmptv
613 | add CARG2, GL, #offsetof(global_State, tmptv)
614 |2:
615 | add CARG3, sp, TMPDofs
616 | str CARG4, TMPD
617 | b >1
618 |
619 |->vmeta_tgetb: // RB = table, RC = index
620 | add RC, RC, TISNUM
621 | add CARG2, BASE, RB, lsl #3
622 | add CARG3, sp, TMPDofs
623 | str RC, TMPD
624 | b >1
625 |
626 |->vmeta_tgetv: // RB = table, RC = key
627 | add CARG2, BASE, RB, lsl #3
628 | add CARG3, BASE, RC, lsl #3
629 |1:
630 | str BASE, L->base
631 | mov CARG1, L
632 | str PC, SAVE_PC
633 | bl extern lj_meta_tget // (lua_State *L, TValue *o, TValue *k)
634 | // Returns TValue * (finished) or NULL (metamethod).
635 | cbz CRET1, >3
636 | ldr TMP0, [CRET1]
637 | str TMP0, [BASE, RA, lsl #3]
638 | ins_next
639 |
640 |3: // Call __index metamethod.
641 | // BASE = base, L->top = new base, stack = cont/func/t/k
642 | sub TMP1, BASE, #FRAME_CONT
643 | ldr BASE, L->top
644 | mov NARGS8:RC, #16 // 2 args for func(t, k).
645 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here.
646 | str PC, [BASE, #-24] // [cont|PC]
647 | sub PC, BASE, TMP1
648 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
649 | b ->vm_call_dispatch_f
650 |
651 |->vmeta_tgetr:
652 | sxtw CARG2, TMP1w
653 | bl extern lj_tab_getinth // (GCtab *t, int32_t key)
654 | // Returns cTValue * or NULL.
655 | mov TMP0, TISNIL
656 | cbz CRET1, ->BC_TGETR_Z
657 | ldr TMP0, [CRET1]
658 | b ->BC_TGETR_Z
659 |
660 |//-----------------------------------------------------------------------
661 |
662 |->vmeta_tsets1:
663 | movn CARG4, #~LJ_TSTR
664 | add CARG2, BASE, RB, lsl #3
665 | add CARG4, STR:RC, CARG4, lsl #47
666 | b >2
667 |
668 |->vmeta_tsets:
669 | movk CARG2, #(LJ_TTAB>>1)&0xffff, lsl #48
670 | str CARG2, GL->tmptv
671 | add CARG2, GL, #offsetof(global_State, tmptv)
672 |2:
673 | add CARG3, sp, TMPDofs
674 | str CARG4, TMPD
675 | b >1
676 |
677 |->vmeta_tsetb: // RB = table, RC = index
678 | add RC, RC, TISNUM
679 | add CARG2, BASE, RB, lsl #3
680 | add CARG3, sp, TMPDofs
681 | str RC, TMPD
682 | b >1
683 |
684 |->vmeta_tsetv:
685 | add CARG2, BASE, RB, lsl #3
686 | add CARG3, BASE, RC, lsl #3
687 |1:
688 | str BASE, L->base
689 | mov CARG1, L
690 | str PC, SAVE_PC
691 | bl extern lj_meta_tset // (lua_State *L, TValue *o, TValue *k)
692 | // Returns TValue * (finished) or NULL (metamethod).
693 | ldr TMP0, [BASE, RA, lsl #3]
694 | cbz CRET1, >3
695 | // NOBARRIER: lj_meta_tset ensures the table is not black.
696 | str TMP0, [CRET1]
697 | ins_next
698 |
699 |3: // Call __newindex metamethod.
700 | // BASE = base, L->top = new base, stack = cont/func/t/k/(v)
701 | sub TMP1, BASE, #FRAME_CONT
702 | ldr BASE, L->top
703 | mov NARGS8:RC, #24 // 3 args for func(t, k, v).
704 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here.
705 | str TMP0, [BASE, #16] // Copy value to third argument.
706 | str PC, [BASE, #-24] // [cont|PC]
707 | sub PC, BASE, TMP1
708 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
709 | b ->vm_call_dispatch_f
710 |
711 |->vmeta_tsetr:
712 | sxtw CARG3, TMP1w
713 | str BASE, L->base
714 | str PC, SAVE_PC
715 | bl extern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key)
716 | // Returns TValue *.
717 | b ->BC_TSETR_Z
718 |
719 |//-- Comparison metamethods ---------------------------------------------
720 |
721 |->vmeta_comp:
722 | add CARG2, BASE, RA, lsl #3
723 | sub PC, PC, #4
724 | add CARG3, BASE, RC, lsl #3
725 | str BASE, L->base
726 | mov CARG1, L
727 | str PC, SAVE_PC
728 | uxtb CARG4w, INSw
729 | bl extern lj_meta_comp // (lua_State *L, TValue *o1, *o2, int op)
730 | // Returns 0/1 or TValue * (metamethod).
731 |3:
732 | cmp CRET1, #1
733 | bhi ->vmeta_binop
734 |4:
735 | ldrh RBw, [PC, # OFS_RD]
736 | add PC, PC, #4
737 | add RB, PC, RB, lsl #2
738 | sub RB, RB, #0x20000
739 | csel PC, PC, RB, lo
740 |->cont_nop:
741 | ins_next
742 |
743 |->cont_ra: // RA = resultptr
744 | ldr INSw, [PC, #-4]
745 | ldr TMP0, [RA]
746 | decode_RA TMP1, INS
747 | str TMP0, [BASE, TMP1, lsl #3]
748 | b ->cont_nop
749 |
750 |->cont_condt: // RA = resultptr
751 | ldr TMP0, [RA]
752 | mov_true TMP1
753 | cmp TMP1, TMP0 // Branch if result is true.
754 | b <4
755 |
756 |->cont_condf: // RA = resultptr
757 | ldr TMP0, [RA]
758 | mov_false TMP1
759 | cmp TMP0, TMP1 // Branch if result is false.
760 | b <4
761 |
762 |->vmeta_equal:
763 | // CARG2, CARG3, CARG4 are already set by BC_ISEQV/BC_ISNEV.
764 | and TAB:CARG3, CARG3, #LJ_GCVMASK
765 | sub PC, PC, #4
766 | str BASE, L->base
767 | mov CARG1, L
768 | str PC, SAVE_PC
769 | bl extern lj_meta_equal // (lua_State *L, GCobj *o1, *o2, int ne)
770 | // Returns 0/1 or TValue * (metamethod).
771 | b <3
772 |
773 |->vmeta_equal_cd:
774 |.if FFI
775 | sub PC, PC, #4
776 | str BASE, L->base
777 | mov CARG1, L
778 | mov CARG2, INS
779 | str PC, SAVE_PC
780 | bl extern lj_meta_equal_cd // (lua_State *L, BCIns op)
781 | // Returns 0/1 or TValue * (metamethod).
782 | b <3
783 |.endif
784 |
785 |->vmeta_istype:
786 | sub PC, PC, #4
787 | str BASE, L->base
788 | mov CARG1, L
789 | mov CARG2, RA
790 | mov CARG3, RC
791 | str PC, SAVE_PC
792 | bl extern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp)
793 | b ->cont_nop
794 |
795 |//-- Arithmetic metamethods ---------------------------------------------
796 |
797 |->vmeta_arith_vn:
798 | add CARG3, BASE, RB, lsl #3
799 | add CARG4, KBASE, RC, lsl #3
800 | b >1
801 |
802 |->vmeta_arith_nv:
803 | add CARG4, BASE, RB, lsl #3
804 | add CARG3, KBASE, RC, lsl #3
805 | b >1
806 |
807 |->vmeta_unm:
808 | add CARG3, BASE, RC, lsl #3
809 | mov CARG4, CARG3
810 | b >1
811 |
812 |->vmeta_arith_vv:
813 | add CARG3, BASE, RB, lsl #3
814 | add CARG4, BASE, RC, lsl #3
815 |1:
816 | uxtb CARG5w, INSw
817 | add CARG2, BASE, RA, lsl #3
818 | str BASE, L->base
819 | mov CARG1, L
820 | str PC, SAVE_PC
821 | bl extern lj_meta_arith // (lua_State *L, TValue *ra,*rb,*rc, BCReg op)
822 | // Returns NULL (finished) or TValue * (metamethod).
823 | cbz CRET1, ->cont_nop
824 |
825 | // Call metamethod for binary op.
826 |->vmeta_binop:
827 | // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2
828 | sub TMP1, CRET1, BASE
829 | str PC, [CRET1, #-24] // [cont|PC]
830 | add PC, TMP1, #FRAME_CONT
831 | mov BASE, CRET1
832 | mov NARGS8:RC, #16 // 2 args for func(o1, o2).
833 | b ->vm_call_dispatch
834 |
835 |->vmeta_len:
836 | add CARG2, BASE, RC, lsl #3
837#if LJ_52
838 | mov TAB:RC, TAB:CARG1 // Save table (ignored for other types).
839#endif
840 | str BASE, L->base
841 | mov CARG1, L
842 | str PC, SAVE_PC
843 | bl extern lj_meta_len // (lua_State *L, TValue *o)
844 | // Returns NULL (retry) or TValue * (metamethod base).
845#if LJ_52
846 | cbnz CRET1, ->vmeta_binop // Binop call for compatibility.
847 | mov TAB:CARG1, TAB:RC
848 | b ->BC_LEN_Z
849#else
850 | b ->vmeta_binop // Binop call for compatibility.
851#endif
852 |
853 |//-- Call metamethod ----------------------------------------------------
854 |
855 |->vmeta_call: // Resolve and call __call metamethod.
856 | // RB = old base, BASE = new base, RC = nargs*8
857 | mov CARG1, L
858 | str RB, L->base // This is the callers base!
859 | sub CARG2, BASE, #16
860 | str PC, SAVE_PC
861 | add CARG3, BASE, NARGS8:RC
862 | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
863 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Guaranteed to be a function here.
864 | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now.
865 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
866 | ins_call
867 |
868 |->vmeta_callt: // Resolve __call for BC_CALLT.
869 | // BASE = old base, RA = new base, RC = nargs*8
870 | mov CARG1, L
871 | str BASE, L->base
872 | sub CARG2, RA, #16
873 | str PC, SAVE_PC
874 | add CARG3, RA, NARGS8:RC
875 | bl extern lj_meta_call // (lua_State *L, TValue *func, TValue *top)
876 | ldr TMP1, [RA, FRAME_FUNC] // Guaranteed to be a function here.
877 | ldr PC, [BASE, FRAME_PC]
878 | add NARGS8:RC, NARGS8:RC, #8 // Got one more argument now.
879 | and LFUNC:CARG3, TMP1, #LJ_GCVMASK
880 | b ->BC_CALLT2_Z
881 |
882 |//-- Argument coercion for 'for' statement ------------------------------
883 |
884 |->vmeta_for:
885 | mov CARG1, L
886 | str BASE, L->base
887 | mov CARG2, RA
888 | str PC, SAVE_PC
889 | bl extern lj_meta_for // (lua_State *L, TValue *base)
890 | ldr INSw, [PC, #-4]
891 |.if JIT
892 | uxtb TMP0w, INSw
893 |.endif
894 | decode_RA RA, INS
895 | decode_RD RC, INS
896 |.if JIT
897 | cmp TMP0, #BC_JFORI
898 | beq =>BC_JFORI
899 |.endif
900 | b =>BC_FORI
901 |
902 |//-----------------------------------------------------------------------
903 |//-- Fast functions -----------------------------------------------------
904 |//-----------------------------------------------------------------------
905 |
906 |.macro .ffunc, name
907 |->ff_ .. name:
908 |.endmacro
909 |
910 |.macro .ffunc_1, name
911 |->ff_ .. name:
912 | ldr CARG1, [BASE]
913 | cmp NARGS8:RC, #8
914 | blo ->fff_fallback
915 |.endmacro
916 |
917 |.macro .ffunc_2, name
918 |->ff_ .. name:
919 | ldp CARG1, CARG2, [BASE]
920 | cmp NARGS8:RC, #16
921 | blo ->fff_fallback
922 |.endmacro
923 |
924 |.macro .ffunc_n, name
925 | .ffunc name
926 | ldr CARG1, [BASE]
927 | cmp NARGS8:RC, #8
928 | ldr FARG1, [BASE]
929 | blo ->fff_fallback
930 | checknum CARG1, ->fff_fallback
931 |.endmacro
932 |
933 |.macro .ffunc_nn, name
934 | .ffunc name
935 | ldp CARG1, CARG2, [BASE]
936 | cmp NARGS8:RC, #16
937 | ldp FARG1, FARG2, [BASE]
938 | blo ->fff_fallback
939 | checknum CARG1, ->fff_fallback
940 | checknum CARG2, ->fff_fallback
941 |.endmacro
942 |
943 |// Inlined GC threshold check. Caveat: uses CARG1 and CARG2.
944 |.macro ffgccheck
945 | ldp CARG1, CARG2, GL->gc.total // Assumes threshold follows total.
946 | cmp CARG1, CARG2
947 | blt >1
948 | bl ->fff_gcstep
949 |1:
950 |.endmacro
951 |
952 |//-- Base library: checks -----------------------------------------------
953 |
954 |.ffunc_1 assert
955 | ldr PC, [BASE, FRAME_PC]
956 | mov_false TMP1
957 | cmp CARG1, TMP1
958 | bhs ->fff_fallback
959 | str CARG1, [BASE, #-16]
960 | sub RB, BASE, #8
961 | subs RA, NARGS8:RC, #8
962 | add RC, NARGS8:RC, #8 // Compute (nresults+1)*8.
963 | cbz RA, ->fff_res // Done if exactly 1 argument.
964 |1:
965 | ldr CARG1, [RB, #16]
966 | sub RA, RA, #8
967 | str CARG1, [RB], #8
968 | cbnz RA, <1
969 | b ->fff_res
970 |
971 |.ffunc_1 type
972 | mov TMP0, #~LJ_TISNUM
973 | asr ITYPE, CARG1, #47
974 | cmn ITYPE, #~LJ_TISNUM
975 | csinv TMP1, TMP0, ITYPE, lo
976 | add TMP1, TMP1, #offsetof(GCfuncC, upvalue)/8
977 | ldr CARG1, [CFUNC:CARG3, TMP1, lsl #3]
978 | b ->fff_restv
979 |
980 |//-- Base library: getters and setters ---------------------------------
981 |
982 |.ffunc_1 getmetatable
983 | asr ITYPE, CARG1, #47
984 | cmn ITYPE, #-LJ_TTAB
985 | ccmn ITYPE, #-LJ_TUDATA, #4, ne
986 | and TAB:CARG1, CARG1, #LJ_GCVMASK
987 | bne >6
988 |1: // Field metatable must be at same offset for GCtab and GCudata!
989 | ldr TAB:RB, TAB:CARG1->metatable
990 |2:
991 | mov CARG1, TISNIL
992 | ldr STR:RC, GL->gcroot[GCROOT_MMNAME+MM_metatable]
993 | cbz TAB:RB, ->fff_restv
994 | ldr TMP1w, TAB:RB->hmask
995 | ldr TMP2w, STR:RC->hash
996 | ldr NODE:CARG3, TAB:RB->node
997 | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask
998 | add TMP1, TMP1, TMP1, lsl #1
999 | movn CARG4, #~LJ_TSTR
1000 | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8
1001 | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for.
1002 |3: // Rearranged logic, because we expect _not_ to find the key.
1003 | ldp CARG1, TMP0, NODE:CARG3->val
1004 | ldr NODE:CARG3, NODE:CARG3->next
1005 | cmp TMP0, CARG4
1006 | beq >5
1007 | cbnz NODE:CARG3, <3
1008 |4:
1009 | mov CARG1, RB // Use metatable as default result.
1010 | movk CARG1, #(LJ_TTAB>>1)&0xffff, lsl #48
1011 | b ->fff_restv
1012 |5:
1013 | cmp TMP0, TISNIL
1014 | bne ->fff_restv
1015 | b <4
1016 |
1017 |6:
1018 | movn TMP0, #~LJ_TISNUM
1019 | cmp ITYPE, TMP0
1020 | csel ITYPE, ITYPE, TMP0, hs
1021 | sub TMP1, GL, ITYPE, lsl #3
1022 | ldr TAB:RB, [TMP1, #offsetof(global_State, gcroot[GCROOT_BASEMT])-8]
1023 | b <2
1024 |
1025 |.ffunc_2 setmetatable
1026 | // Fast path: no mt for table yet and not clearing the mt.
1027 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback
1028 | ldr TAB:TMP0, TAB:TMP1->metatable
1029 | asr ITYPE, CARG2, #47
1030 | ldrb TMP2w, TAB:TMP1->marked
1031 | cmn ITYPE, #-LJ_TTAB
1032 | and TAB:CARG2, CARG2, #LJ_GCVMASK
1033 | ccmp TAB:TMP0, #0, #0, eq
1034 | bne ->fff_fallback
1035 | str TAB:CARG2, TAB:TMP1->metatable
1036 | tbz TMP2w, #2, ->fff_restv // isblack(table)
1037 | barrierback TAB:TMP1, TMP2w, TMP0
1038 | b ->fff_restv
1039 |
1040 |.ffunc rawget
1041 | ldr CARG2, [BASE]
1042 | cmp NARGS8:RC, #16
1043 | blo ->fff_fallback
1044 | checktab CARG2, ->fff_fallback
1045 | mov CARG1, L
1046 | add CARG3, BASE, #8
1047 | bl extern lj_tab_get // (lua_State *L, GCtab *t, cTValue *key)
1048 | // Returns cTValue *.
1049 | ldr CARG1, [CRET1]
1050 | b ->fff_restv
1051 |
1052 |//-- Base library: conversions ------------------------------------------
1053 |
1054 |.ffunc tonumber
1055 | // Only handles the number case inline (without a base argument).
1056 | ldr CARG1, [BASE]
1057 | cmp NARGS8:RC, #8
1058 | bne ->fff_fallback
1059 | checknumber CARG1, ->fff_fallback
1060 | b ->fff_restv
1061 |
1062 |.ffunc_1 tostring
1063 | // Only handles the string or number case inline.
1064 | asr ITYPE, CARG1, #47
1065 | cmn ITYPE, #-LJ_TSTR
1066 | // A __tostring method in the string base metatable is ignored.
1067 | beq ->fff_restv
1068 | // Handle numbers inline, unless a number base metatable is present.
1069 | ldr TMP1, GL->gcroot[GCROOT_BASEMT_NUM]
1070 | str BASE, L->base
1071 | cmn ITYPE, #-LJ_TISNUM
1072 | ccmp TMP1, #0, #0, ls
1073 | str PC, SAVE_PC // Redundant (but a defined value).
1074 | bne ->fff_fallback
1075 | ffgccheck
1076 | mov CARG1, L
1077 | mov CARG2, BASE
1078 | bl extern lj_strfmt_number // (lua_State *L, cTValue *o)
1079 | // Returns GCstr *.
1080 | movn TMP1, #~LJ_TSTR
1081 | ldr BASE, L->base
1082 | add CARG1, CARG1, TMP1, lsl #47
1083 | b ->fff_restv
1084 |
1085 |//-- Base library: iterators -------------------------------------------
1086 |
1087 |.ffunc_1 next
1088 | checktp CARG2, CARG1, LJ_TTAB, ->fff_fallback
1089 | str TISNIL, [BASE, NARGS8:RC] // Set missing 2nd arg to nil.
1090 | ldr PC, [BASE, FRAME_PC]
1091 | stp BASE, BASE, L->base // Add frame since C call can throw.
1092 | mov CARG1, L
1093 | add CARG3, BASE, #8
1094 | str PC, SAVE_PC
1095 | bl extern lj_tab_next // (lua_State *L, GCtab *t, TValue *key)
1096 | // Returns 0 at end of traversal.
1097 | str TISNIL, [BASE, #-16]
1098 | cbz CRET1, ->fff_res1 // End of traversal: return nil.
1099 | ldp CARG1, CARG2, [BASE, #8] // Copy key and value to results.
1100 | mov RC, #(2+1)*8
1101 | stp CARG1, CARG2, [BASE, #-16]
1102 | b ->fff_res
1103 |
1104 |.ffunc_1 pairs
1105 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback
1106#if LJ_52
1107 | ldr TAB:CARG2, TAB:TMP1->metatable
1108#endif
1109 | ldr CFUNC:CARG4, CFUNC:CARG3->upvalue[0]
1110 | ldr PC, [BASE, FRAME_PC]
1111#if LJ_52
1112 | cbnz TAB:CARG2, ->fff_fallback
1113#endif
1114 | mov RC, #(3+1)*8
1115 | stp CARG1, TISNIL, [BASE, #-8]
1116 | str CFUNC:CARG4, [BASE, #-16]
1117 | b ->fff_res
1118 |
1119 |.ffunc_2 ipairs_aux
1120 | checktab CARG1, ->fff_fallback
1121 | checkint CARG2, ->fff_fallback
1122 | ldr TMP1w, TAB:CARG1->asize
1123 | ldr CARG3, TAB:CARG1->array
1124 | ldr TMP0w, TAB:CARG1->hmask
1125 | add CARG2w, CARG2w, #1
1126 | cmp CARG2w, TMP1w
1127 | ldr PC, [BASE, FRAME_PC]
1128 | add TMP2, CARG2, TISNUM
1129 | mov RC, #(0+1)*8
1130 | str TMP2, [BASE, #-16]
1131 | bhs >2 // Not in array part?
1132 | ldr TMP0, [CARG3, CARG2, lsl #3]
1133 |1:
1134 | mov TMP1, #(2+1)*8
1135 | cmp TMP0, TISNIL
1136 | str TMP0, [BASE, #-8]
1137 | csel RC, RC, TMP1, eq
1138 | b ->fff_res
1139 |2: // Check for empty hash part first. Otherwise call C function.
1140 | cbz TMP0w, ->fff_res
1141 | bl extern lj_tab_getinth // (GCtab *t, int32_t key)
1142 | // Returns cTValue * or NULL.
1143 | cbz CRET1, ->fff_res
1144 | ldr TMP0, [CRET1]
1145 | b <1
1146 |
1147 |.ffunc_1 ipairs
1148 | checktp TMP1, CARG1, LJ_TTAB, ->fff_fallback
1149#if LJ_52
1150 | ldr TAB:CARG2, TAB:TMP1->metatable
1151#endif
1152 | ldr CFUNC:CARG4, CFUNC:CARG3->upvalue[0]
1153 | ldr PC, [BASE, FRAME_PC]
1154#if LJ_52
1155 | cbnz TAB:CARG2, ->fff_fallback
1156#endif
1157 | mov RC, #(3+1)*8
1158 | stp CARG1, TISNUM, [BASE, #-8]
1159 | str CFUNC:CARG4, [BASE, #-16]
1160 | b ->fff_res
1161 |
1162 |//-- Base library: catch errors ----------------------------------------
1163 |
1164 |.ffunc pcall
1165 | ldrb TMP0w, GL->hookmask
1166 | subs NARGS8:RC, NARGS8:RC, #8
1167 | blo ->fff_fallback
1168 | mov RB, BASE
1169 | add BASE, BASE, #16
1170 | ubfx TMP0w, TMP0w, #HOOK_ACTIVE_SHIFT, #1
1171 | add PC, TMP0, #16+FRAME_PCALL
1172 | beq ->vm_call_dispatch
1173 |1:
1174 | add TMP2, BASE, NARGS8:RC
1175 |2:
1176 | ldr TMP0, [TMP2, #-16]
1177 | str TMP0, [TMP2, #-8]!
1178 | cmp TMP2, BASE
1179 | bne <2
1180 | b ->vm_call_dispatch
1181 |
1182 |.ffunc xpcall
1183 | ldp CARG1, CARG2, [BASE]
1184 | ldrb TMP0w, GL->hookmask
1185 | subs NARGS8:TMP1, NARGS8:RC, #16
1186 | blo ->fff_fallback
1187 | mov RB, BASE
1188 | asr ITYPE, CARG2, #47
1189 | ubfx TMP0w, TMP0w, #HOOK_ACTIVE_SHIFT, #1
1190 | cmn ITYPE, #-LJ_TFUNC
1191 | add PC, TMP0, #24+FRAME_PCALL
1192 | bne ->fff_fallback // Traceback must be a function.
1193 | mov NARGS8:RC, NARGS8:TMP1
1194 | add BASE, BASE, #24
1195 | stp CARG2, CARG1, [RB] // Swap function and traceback.
1196 | cbz NARGS8:RC, ->vm_call_dispatch
1197 | b <1
1198 |
1199 |//-- Coroutine library --------------------------------------------------
1200 |
1201 |.macro coroutine_resume_wrap, resume
1202 |.if resume
1203 |.ffunc_1 coroutine_resume
1204 | checktp CARG1, LJ_TTHREAD, ->fff_fallback
1205 |.else
1206 |.ffunc coroutine_wrap_aux
1207 | ldr L:CARG1, CFUNC:CARG3->upvalue[0].gcr
1208 | and L:CARG1, CARG1, #LJ_GCVMASK
1209 |.endif
1210 | ldr PC, [BASE, FRAME_PC]
1211 | str BASE, L->base
1212 | ldp RB, CARG2, L:CARG1->base
1213 | ldrb TMP1w, L:CARG1->status
1214 | add TMP0, CARG2, TMP1
1215 | str PC, SAVE_PC
1216 | cmp TMP0, RB
1217 | beq ->fff_fallback
1218 | cmp TMP1, #LUA_YIELD
1219 | add TMP0, CARG2, #8
1220 | csel CARG2, CARG2, TMP0, hs
1221 | ldr CARG4, L:CARG1->maxstack
1222 | add CARG3, CARG2, NARGS8:RC
1223 | ldr RB, L:CARG1->cframe
1224 | ccmp CARG3, CARG4, #2, ls
1225 | ccmp RB, #0, #2, ls
1226 | bhi ->fff_fallback
1227 |.if resume
1228 | sub CARG3, CARG3, #8 // Keep resumed thread in stack for GC.
1229 | add BASE, BASE, #8
1230 | sub NARGS8:RC, NARGS8:RC, #8
1231 |.endif
1232 | str CARG3, L:CARG1->top
1233 | str BASE, L->top
1234 | cbz NARGS8:RC, >3
1235 |2: // Move args to coroutine.
1236 | ldr TMP0, [BASE, RB]
1237 | cmp RB, NARGS8:RC
1238 | str TMP0, [CARG2, RB]
1239 | add RB, RB, #8
1240 | bne <2
1241 |3:
1242 | mov CARG3, #0
1243 | mov L:RA, L:CARG1
1244 | mov CARG4, #0
1245 | bl ->vm_resume // (lua_State *L, TValue *base, 0, 0)
1246 | // Returns thread status.
1247 |4:
1248 | ldp CARG3, CARG4, L:RA->base
1249 | cmp CRET1, #LUA_YIELD
1250 | ldr BASE, L->base
1251 | str L, GL->cur_L
1252 | st_vmstate ST_INTERP
1253 | bhi >8
1254 | sub RC, CARG4, CARG3
1255 | ldr CARG1, L->maxstack
1256 | add CARG2, BASE, RC
1257 | cbz RC, >6 // No results?
1258 | cmp CARG2, CARG1
1259 | mov RB, #0
1260 | bhi >9 // Need to grow stack?
1261 |
1262 | sub CARG4, RC, #8
1263 | str CARG3, L:RA->top // Clear coroutine stack.
1264 |5: // Move results from coroutine.
1265 | ldr TMP0, [CARG3, RB]
1266 | cmp RB, CARG4
1267 | str TMP0, [BASE, RB]
1268 | add RB, RB, #8
1269 | bne <5
1270 |6:
1271 |.if resume
1272 | mov_true TMP1
1273 | add RC, RC, #16
1274 |7:
1275 | str TMP1, [BASE, #-8] // Prepend true/false to results.
1276 | sub RA, BASE, #8
1277 |.else
1278 | mov RA, BASE
1279 | add RC, RC, #8
1280 |.endif
1281 | ands CARG1, PC, #FRAME_TYPE
1282 | str PC, SAVE_PC
1283 | str RCw, SAVE_MULTRES
1284 | beq ->BC_RET_Z
1285 | b ->vm_return
1286 |
1287 |8: // Coroutine returned with error (at co->top-1).
1288 |.if resume
1289 | ldr TMP0, [CARG4, #-8]!
1290 | mov_false TMP1
1291 | mov RC, #(2+1)*8
1292 | str CARG4, L:RA->top // Remove error from coroutine stack.
1293 | str TMP0, [BASE] // Copy error message.
1294 | b <7
1295 |.else
1296 | mov CARG1, L
1297 | mov CARG2, L:RA
1298 | bl extern lj_ffh_coroutine_wrap_err // (lua_State *L, lua_State *co)
1299 | // Never returns.
1300 |.endif
1301 |
1302 |9: // Handle stack expansion on return from yield.
1303 | mov CARG1, L
1304 | lsr CARG2, RC, #3
1305 | bl extern lj_state_growstack // (lua_State *L, int n)
1306 | mov CRET1, #0
1307 | b <4
1308 |.endmacro
1309 |
1310 | coroutine_resume_wrap 1 // coroutine.resume
1311 | coroutine_resume_wrap 0 // coroutine.wrap
1312 |
1313 |.ffunc coroutine_yield
1314 | ldr TMP0, L->cframe
1315 | add TMP1, BASE, NARGS8:RC
1316 | mov CRET1, #LUA_YIELD
1317 | stp BASE, TMP1, L->base
1318 | tbz TMP0, #0, ->fff_fallback
1319 | str xzr, L->cframe
1320 | strb CRET1w, L->status
1321 | b ->vm_leave_unw
1322 |
1323 |//-- Math library -------------------------------------------------------
1324 |
1325 |.macro math_round, func, round
1326 | .ffunc math_ .. func
1327 | ldr CARG1, [BASE]
1328 | cmp NARGS8:RC, #8
1329 | ldr d0, [BASE]
1330 | blo ->fff_fallback
1331 | cmp TISNUMhi, CARG1, lsr #32
1332 | beq ->fff_restv
1333 | blo ->fff_fallback
1334 | round d0, d0
1335 | b ->fff_resn
1336 |.endmacro
1337 |
1338 | math_round floor, frintm
1339 | math_round ceil, frintp
1340 |
1341 |.ffunc_1 math_abs
1342 | checknumber CARG1, ->fff_fallback
1343 | and CARG1, CARG1, #U64x(7fffffff,ffffffff)
1344 | bne ->fff_restv
1345 | eor CARG2w, CARG1w, CARG1w, asr #31
1346 | movz CARG3, #0x41e0, lsl #48 // 2^31.
1347 | subs CARG1w, CARG2w, CARG1w, asr #31
1348 | add CARG1, CARG1, TISNUM
1349 | csel CARG1, CARG1, CARG3, pl
1350 | // Fallthrough.
1351 |
1352 |->fff_restv:
1353 | // CARG1 = TValue result.
1354 | ldr PC, [BASE, FRAME_PC]
1355 | str CARG1, [BASE, #-16]
1356 |->fff_res1:
1357 | // PC = return.
1358 | mov RC, #(1+1)*8
1359 |->fff_res:
1360 | // RC = (nresults+1)*8, PC = return.
1361 | ands CARG1, PC, #FRAME_TYPE
1362 | str RCw, SAVE_MULTRES
1363 | sub RA, BASE, #16
1364 | bne ->vm_return
1365 | ldr INSw, [PC, #-4]
1366 | decode_RB RB, INS
1367 |5:
1368 | cmp RC, RB, lsl #3 // More results expected?
1369 | blo >6
1370 | decode_RA TMP1, INS
1371 | // Adjust BASE. KBASE is assumed to be set for the calling frame.
1372 | sub BASE, RA, TMP1, lsl #3
1373 | ins_next
1374 |
1375 |6: // Fill up results with nil.
1376 | add TMP1, RA, RC
1377 | add RC, RC, #8
1378 | str TISNIL, [TMP1, #-8]
1379 | b <5
1380 |
1381 |.macro math_extern, func
1382 | .ffunc_n math_ .. func
1383 | bl extern func
1384 | b ->fff_resn
1385 |.endmacro
1386 |
1387 |.macro math_extern2, func
1388 | .ffunc_nn math_ .. func
1389 | bl extern func
1390 | b ->fff_resn
1391 |.endmacro
1392 |
1393 |.ffunc_n math_sqrt
1394 | fsqrt d0, d0
1395 |->fff_resn:
1396 | ldr PC, [BASE, FRAME_PC]
1397 | str d0, [BASE, #-16]
1398 | b ->fff_res1
1399 |
1400 |.ffunc math_log
1401 | ldr CARG1, [BASE]
1402 | cmp NARGS8:RC, #8
1403 | ldr FARG1, [BASE]
1404 | bne ->fff_fallback // Need exactly 1 argument.
1405 | checknum CARG1, ->fff_fallback
1406 | bl extern log
1407 | b ->fff_resn
1408 |
1409 | math_extern log10
1410 | math_extern exp
1411 | math_extern sin
1412 | math_extern cos
1413 | math_extern tan
1414 | math_extern asin
1415 | math_extern acos
1416 | math_extern atan
1417 | math_extern sinh
1418 | math_extern cosh
1419 | math_extern tanh
1420 | math_extern2 pow
1421 | math_extern2 atan2
1422 | math_extern2 fmod
1423 |
1424 |.ffunc_2 math_ldexp
1425 | ldr FARG1, [BASE]
1426 | checknum CARG1, ->fff_fallback
1427 | checkint CARG2, ->fff_fallback
1428 | sxtw CARG1, CARG2w
1429 | bl extern ldexp // (double x, int exp)
1430 | b ->fff_resn
1431 |
1432 |.ffunc_n math_frexp
1433 | add CARG1, sp, TMPDofs
1434 | bl extern frexp
1435 | ldr CARG2w, TMPD
1436 | ldr PC, [BASE, FRAME_PC]
1437 | str d0, [BASE, #-16]
1438 | mov RC, #(2+1)*8
1439 | add CARG2, CARG2, TISNUM
1440 | str CARG2, [BASE, #-8]
1441 | b ->fff_res
1442 |
1443 |.ffunc_n math_modf
1444 | sub CARG1, BASE, #16
1445 | ldr PC, [BASE, FRAME_PC]
1446 | bl extern modf
1447 | mov RC, #(2+1)*8
1448 | str d0, [BASE, #-8]
1449 | b ->fff_res
1450 |
1451 |.macro math_minmax, name, cond, fcond
1452 | .ffunc_1 name
1453 | add RB, BASE, RC
1454 | add RA, BASE, #8
1455 | checkint CARG1, >4
1456 |1: // Handle integers.
1457 | ldr CARG2, [RA]
1458 | cmp RA, RB
1459 | bhs ->fff_restv
1460 | checkint CARG2, >3
1461 | cmp CARG1w, CARG2w
1462 | add RA, RA, #8
1463 | csel CARG1, CARG2, CARG1, cond
1464 | b <1
1465 |3: // Convert intermediate result to number and continue below.
1466 | scvtf d0, CARG1w
1467 | blo ->fff_fallback
1468 | ldr d1, [RA]
1469 | b >6
1470 |
1471 |4:
1472 | ldr d0, [BASE]
1473 | blo ->fff_fallback
1474 |5: // Handle numbers.
1475 | ldr CARG2, [RA]
1476 | ldr d1, [RA]
1477 | cmp RA, RB
1478 | bhs ->fff_resn
1479 | checknum CARG2, >7
1480 |6:
1481 | fcmp d0, d1
1482 | add RA, RA, #8
1483 | fcsel d0, d1, d0, fcond
1484 | b <5
1485 |7: // Convert integer to number and continue above.
1486 | scvtf d1, CARG2w
1487 | blo ->fff_fallback
1488 | b <6
1489 |.endmacro
1490 |
1491 | math_minmax math_min, gt, hi
1492 | math_minmax math_max, lt, lo
1493 |
1494 |//-- String library -----------------------------------------------------
1495 |
1496 |.ffunc string_byte // Only handle the 1-arg case here.
1497 | ldp PC, CARG1, [BASE, FRAME_PC]
1498 | cmp NARGS8:RC, #8
1499 | asr ITYPE, CARG1, #47
1500 | ccmn ITYPE, #-LJ_TSTR, #0, eq
1501 | and STR:CARG1, CARG1, #LJ_GCVMASK
1502 | bne ->fff_fallback
1503 | ldrb TMP0w, STR:CARG1[1] // Access is always ok (NUL at end).
1504 | ldr CARG3w, STR:CARG1->len
1505 | add TMP0, TMP0, TISNUM
1506 | str TMP0, [BASE, #-16]
1507 | mov RC, #(0+1)*8
1508 | cbz CARG3, ->fff_res
1509 | b ->fff_res1
1510 |
1511 |.ffunc string_char // Only handle the 1-arg case here.
1512 | ffgccheck
1513 | ldp PC, CARG1, [BASE, FRAME_PC]
1514 | cmp CARG1w, #255
1515 | ccmp NARGS8:RC, #8, #0, ls // Need exactly 1 argument.
1516 | bne ->fff_fallback
1517 | checkint CARG1, ->fff_fallback
1518 | mov CARG3, #1
1519 | // Point to the char inside the integer in the stack slot.
1520 |.if ENDIAN_LE
1521 | mov CARG2, BASE
1522 |.else
1523 | add CARG2, BASE, #7
1524 |.endif
1525 |->fff_newstr:
1526 | // CARG2 = str, CARG3 = len.
1527 | str BASE, L->base
1528 | mov CARG1, L
1529 | str PC, SAVE_PC
1530 | bl extern lj_str_new // (lua_State *L, char *str, size_t l)
1531 |->fff_resstr:
1532 | // Returns GCstr *.
1533 | ldr BASE, L->base
1534 | movn TMP1, #~LJ_TSTR
1535 | add CARG1, CARG1, TMP1, lsl #47
1536 | b ->fff_restv
1537 |
1538 |.ffunc string_sub
1539 | ffgccheck
1540 | ldr CARG1, [BASE]
1541 | ldr CARG3, [BASE, #16]
1542 | cmp NARGS8:RC, #16
1543 | movn RB, #0
1544 | beq >1
1545 | blo ->fff_fallback
1546 | checkint CARG3, ->fff_fallback
1547 | sxtw RB, CARG3w
1548 |1:
1549 | ldr CARG2, [BASE, #8]
1550 | checkstr CARG1, ->fff_fallback
1551 | ldr TMP1w, STR:CARG1->len
1552 | checkint CARG2, ->fff_fallback
1553 | sxtw CARG2, CARG2w
1554 | // CARG1 = str, TMP1 = str->len, CARG2 = start, RB = end
1555 | add TMP2, RB, TMP1
1556 | cmp RB, #0
1557 | add TMP0, CARG2, TMP1
1558 | csinc RB, RB, TMP2, ge // if (end < 0) end += len+1
1559 | cmp CARG2, #0
1560 | csinc CARG2, CARG2, TMP0, ge // if (start < 0) start += len+1
1561 | cmp RB, #0
1562 | csel RB, RB, xzr, ge // if (end < 0) end = 0
1563 | cmp CARG2, #1
1564 | csinc CARG2, CARG2, xzr, ge // if (start < 1) start = 1
1565 | cmp RB, TMP1
1566 | csel RB, RB, TMP1, le // if (end > len) end = len
1567 | add CARG1, STR:CARG1, #sizeof(GCstr)-1
1568 | subs CARG3, RB, CARG2 // len = end - start
1569 | add CARG2, CARG1, CARG2
1570 | add CARG3, CARG3, #1 // len += 1
1571 | bge ->fff_newstr
1572 | add STR:CARG1, GL, #offsetof(global_State, strempty)
1573 | movn TMP1, #~LJ_TSTR
1574 | add CARG1, CARG1, TMP1, lsl #47
1575 | b ->fff_restv
1576 |
1577 |.macro ffstring_op, name
1578 | .ffunc string_ .. name
1579 | ffgccheck
1580 | ldr CARG2, [BASE]
1581 | cmp NARGS8:RC, #8
1582 | asr ITYPE, CARG2, #47
1583 | ccmn ITYPE, #-LJ_TSTR, #0, hs
1584 | and STR:CARG2, CARG2, #LJ_GCVMASK
1585 | bne ->fff_fallback
1586 | ldr TMP0, GL->tmpbuf.b
1587 | add SBUF:CARG1, GL, #offsetof(global_State, tmpbuf)
1588 | str BASE, L->base
1589 | str PC, SAVE_PC
1590 | str L, GL->tmpbuf.L
1591 | str TMP0, GL->tmpbuf.p
1592 | bl extern lj_buf_putstr_ .. name
1593 | bl extern lj_buf_tostr
1594 | b ->fff_resstr
1595 |.endmacro
1596 |
1597 |ffstring_op reverse
1598 |ffstring_op lower
1599 |ffstring_op upper
1600 |
1601 |//-- Bit library --------------------------------------------------------
1602 |
1603 |// FP number to bit conversion for soft-float. Clobbers CARG1-CARG3
1604 |->vm_tobit_fb:
1605 | bls ->fff_fallback
1606 | add CARG2, CARG1, CARG1
1607 | mov CARG3, #1076
1608 | sub CARG3, CARG3, CARG2, lsr #53
1609 | cmp CARG3, #53
1610 | bhi >1
1611 | and CARG2, CARG2, #U64x(001fffff,ffffffff)
1612 | orr CARG2, CARG2, #U64x(00200000,00000000)
1613 | cmp CARG1, #0
1614 | lsr CARG2, CARG2, CARG3
1615 | cneg CARG1w, CARG2w, mi
1616 | br lr
1617 |1:
1618 | mov CARG1w, #0
1619 | br lr
1620 |
1621 |.macro .ffunc_bit, name
1622 | .ffunc_1 bit_..name
1623 | adr lr, >1
1624 | checkint CARG1, ->vm_tobit_fb
1625 |1:
1626 |.endmacro
1627 |
1628 |.macro .ffunc_bit_op, name, ins
1629 | .ffunc_bit name
1630 | mov RA, #8
1631 | mov TMP0w, CARG1w
1632 | adr lr, >2
1633 |1:
1634 | ldr CARG1, [BASE, RA]
1635 | cmp RA, NARGS8:RC
1636 | add RA, RA, #8
1637 | bge >9
1638 | checkint CARG1, ->vm_tobit_fb
1639 |2:
1640 | ins TMP0w, TMP0w, CARG1w
1641 | b <1
1642 |.endmacro
1643 |
1644 |.ffunc_bit_op band, and
1645 |.ffunc_bit_op bor, orr
1646 |.ffunc_bit_op bxor, eor
1647 |
1648 |.ffunc_bit tobit
1649 | mov TMP0w, CARG1w
1650 |9: // Label reused by .ffunc_bit_op users.
1651 | add CARG1, TMP0, TISNUM
1652 | b ->fff_restv
1653 |
1654 |.ffunc_bit bswap
1655 | rev TMP0w, CARG1w
1656 | add CARG1, TMP0, TISNUM
1657 | b ->fff_restv
1658 |
1659 |.ffunc_bit bnot
1660 | mvn TMP0w, CARG1w
1661 | add CARG1, TMP0, TISNUM
1662 | b ->fff_restv
1663 |
1664 |.macro .ffunc_bit_sh, name, ins, shmod
1665 | .ffunc bit_..name
1666 | ldp TMP0, CARG1, [BASE]
1667 | cmp NARGS8:RC, #16
1668 | blo ->fff_fallback
1669 | adr lr, >1
1670 | checkint CARG1, ->vm_tobit_fb
1671 |1:
1672 |.if shmod == 0
1673 | mov TMP1, CARG1
1674 |.else
1675 | neg TMP1, CARG1
1676 |.endif
1677 | mov CARG1, TMP0
1678 | adr lr, >2
1679 | checkint CARG1, ->vm_tobit_fb
1680 |2:
1681 | ins TMP0w, CARG1w, TMP1w
1682 | add CARG1, TMP0, TISNUM
1683 | b ->fff_restv
1684 |.endmacro
1685 |
1686 |.ffunc_bit_sh lshift, lsl, 0
1687 |.ffunc_bit_sh rshift, lsr, 0
1688 |.ffunc_bit_sh arshift, asr, 0
1689 |.ffunc_bit_sh rol, ror, 1
1690 |.ffunc_bit_sh ror, ror, 0
1691 |
1692 |//-----------------------------------------------------------------------
1693 |
1694 |->fff_fallback: // Call fast function fallback handler.
1695 | // BASE = new base, RC = nargs*8
1696 | ldp CFUNC:CARG3, PC, [BASE, FRAME_FUNC] // Fallback may overwrite PC.
1697 | ldr TMP2, L->maxstack
1698 | add TMP1, BASE, NARGS8:RC
1699 | stp BASE, TMP1, L->base
1700 | and CFUNC:CARG3, CARG3, #LJ_GCVMASK
1701 | add TMP1, TMP1, #8*LUA_MINSTACK
1702 | ldr CARG3, CFUNC:CARG3->f
1703 | str PC, SAVE_PC // Redundant (but a defined value).
1704 | cmp TMP1, TMP2
1705 | mov CARG1, L
1706 | bhi >5 // Need to grow stack.
1707 | blr CARG3 // (lua_State *L)
1708 | // Either throws an error, or recovers and returns -1, 0 or nresults+1.
1709 | ldr BASE, L->base
1710 | cmp CRET1w, #0
1711 | lsl RC, CRET1, #3
1712 | sub RA, BASE, #16
1713 | bgt ->fff_res // Returned nresults+1?
1714 |1: // Returned 0 or -1: retry fast path.
1715 | ldr CARG1, L->top
1716 | ldr CFUNC:CARG3, [BASE, FRAME_FUNC]
1717 | sub NARGS8:RC, CARG1, BASE
1718 | bne ->vm_call_tail // Returned -1?
1719 | and CFUNC:CARG3, CARG3, #LJ_GCVMASK
1720 | ins_callt // Returned 0: retry fast path.
1721 |
1722 |// Reconstruct previous base for vmeta_call during tailcall.
1723 |->vm_call_tail:
1724 | ands TMP0, PC, #FRAME_TYPE
1725 | and TMP1, PC, #~FRAME_TYPEP
1726 | bne >3
1727 | ldrb RAw, [PC, #-4+OFS_RA]
1728 | lsl RA, RA, #3
1729 | add TMP1, RA, #16
1730 |3:
1731 | sub RB, BASE, TMP1
1732 | b ->vm_call_dispatch // Resolve again for tailcall.
1733 |
1734 |5: // Grow stack for fallback handler.
1735 | mov CARG2, #LUA_MINSTACK
1736 | bl extern lj_state_growstack // (lua_State *L, int n)
1737 | ldr BASE, L->base
1738 | cmp CARG1, CARG1 // Set zero-flag to force retry.
1739 | b <1
1740 |
1741 |->fff_gcstep: // Call GC step function.
1742 | // BASE = new base, RC = nargs*8
1743 | add CARG2, BASE, NARGS8:RC // Calculate L->top.
1744 | mov RA, lr
1745 | stp BASE, CARG2, L->base
1746 | str PC, SAVE_PC // Redundant (but a defined value).
1747 | mov CARG1, L
1748 | bl extern lj_gc_step // (lua_State *L)
1749 | ldp BASE, CARG2, L->base
1750 | ldr CFUNC:CARG3, [BASE, FRAME_FUNC]
1751 | mov lr, RA // Help return address predictor.
1752 | sub NARGS8:RC, CARG2, BASE // Calculate nargs*8.
1753 | and CFUNC:CARG3, CARG3, #LJ_GCVMASK
1754 | ret
1755 |
1756 |//-----------------------------------------------------------------------
1757 |//-- Special dispatch targets -------------------------------------------
1758 |//-----------------------------------------------------------------------
1759 |
1760 |->vm_record: // Dispatch target for recording phase.
1761 |.if JIT
1762 | ldrb CARG1w, GL->hookmask
1763 | tst CARG1, #HOOK_VMEVENT // No recording while in vmevent.
1764 | bne >5
1765 | // Decrement the hookcount for consistency, but always do the call.
1766 | ldr CARG2w, GL->hookcount
1767 | tst CARG1, #HOOK_ACTIVE
1768 | bne >1
1769 | sub CARG2w, CARG2w, #1
1770 | tst CARG1, #LUA_MASKLINE|LUA_MASKCOUNT
1771 | beq >1
1772 | str CARG2w, GL->hookcount
1773 | b >1
1774 |.endif
1775 |
1776 |->vm_rethook: // Dispatch target for return hooks.
1777 | ldrb TMP2w, GL->hookmask
1778 | tbz TMP2w, #HOOK_ACTIVE_SHIFT, >1 // Hook already active?
1779 |5: // Re-dispatch to static ins.
1780 | ldr TMP0, [TMP1, #GG_G2DISP+GG_DISP2STATIC]
1781 | br TMP0
1782 |
1783 |->vm_inshook: // Dispatch target for instr/line hooks.
1784 | ldrb TMP2w, GL->hookmask
1785 | ldr TMP3w, GL->hookcount
1786 | tbnz TMP2w, #HOOK_ACTIVE_SHIFT, <5 // Hook already active?
1787 | tst TMP2w, #LUA_MASKLINE|LUA_MASKCOUNT
1788 | beq <5
1789 | sub TMP3w, TMP3w, #1
1790 | str TMP3w, GL->hookcount
1791 | cbz TMP3w, >1
1792 | tbz TMP2w, #LUA_HOOKLINE, <5
1793 |1:
1794 | mov CARG1, L
1795 | str BASE, L->base
1796 | mov CARG2, PC
1797 | // SAVE_PC must hold the _previous_ PC. The callee updates it with PC.
1798 | bl extern lj_dispatch_ins // (lua_State *L, const BCIns *pc)
1799 |3:
1800 | ldr BASE, L->base
1801 |4: // Re-dispatch to static ins.
1802 | ldr INSw, [PC, #-4]
1803 | add TMP1, GL, INS, uxtb #3
1804 | decode_RA RA, INS
1805 | ldr TMP0, [TMP1, #GG_G2DISP+GG_DISP2STATIC]
1806 | decode_RD RC, INS
1807 | br TMP0
1808 |
1809 |->cont_hook: // Continue from hook yield.
1810 | ldr CARG1, [CARG4, #-40]
1811 | add PC, PC, #4
1812 | str CARG1w, SAVE_MULTRES // Restore MULTRES for *M ins.
1813 | b <4
1814 |
1815 |->vm_hotloop: // Hot loop counter underflow.
1816 |.if JIT
1817 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC] // Same as curr_topL(L).
1818 | add CARG1, GL, #GG_G2DISP+GG_DISP2J
1819 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
1820 | str PC, SAVE_PC
1821 | ldr CARG3, LFUNC:CARG3->pc
1822 | mov CARG2, PC
1823 | str L, [GL, #GL_J(L)]
1824 | ldrb CARG3w, [CARG3, #PC2PROTO(framesize)]
1825 | str BASE, L->base
1826 | add CARG3, BASE, CARG3, lsl #3
1827 | str CARG3, L->top
1828 | bl extern lj_trace_hot // (jit_State *J, const BCIns *pc)
1829 | b <3
1830 |.endif
1831 |
1832 |->vm_callhook: // Dispatch target for call hooks.
1833 | mov CARG2, PC
1834 |.if JIT
1835 | b >1
1836 |.endif
1837 |
1838 |->vm_hotcall: // Hot call counter underflow.
1839 |.if JIT
1840 | orr CARG2, PC, #1
1841 |1:
1842 |.endif
1843 | add TMP1, BASE, NARGS8:RC
1844 | str PC, SAVE_PC
1845 | mov CARG1, L
1846 | sub RA, RA, BASE
1847 | stp BASE, TMP1, L->base
1848 | bl extern lj_dispatch_call // (lua_State *L, const BCIns *pc)
1849 | // Returns ASMFunction.
1850 | ldp BASE, TMP1, L->base
1851 | str xzr, SAVE_PC // Invalidate for subsequent line hook.
1852 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
1853 | add RA, BASE, RA
1854 | sub NARGS8:RC, TMP1, BASE
1855 | ldr INSw, [PC, #-4]
1856 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
1857 | br CRET1
1858 |
1859 |->cont_stitch: // Trace stitching.
1860 |.if JIT
1861 | // RA = resultptr, CARG4 = meta base
1862 | ldr RBw, SAVE_MULTRES
1863 | ldr INSw, [PC, #-4]
1864 | ldr TRACE:CARG3, [CARG4, #-40] // Save previous trace.
1865 | subs RB, RB, #8
1866 | decode_RA RC, INS // Call base.
1867 | and CARG3, CARG3, #LJ_GCVMASK
1868 | beq >2
1869 |1: // Move results down.
1870 | ldr CARG1, [RA]
1871 | add RA, RA, #8
1872 | subs RB, RB, #8
1873 | str CARG1, [BASE, RC, lsl #3]
1874 | add RC, RC, #1
1875 | bne <1
1876 |2:
1877 | decode_RA RA, INS
1878 | decode_RB RB, INS
1879 | add RA, RA, RB
1880 |3:
1881 | cmp RA, RC
1882 | bhi >9 // More results wanted?
1883 |
1884 | ldrh RAw, TRACE:CARG3->traceno
1885 | ldrh RCw, TRACE:CARG3->link
1886 | cmp RCw, RAw
1887 | beq ->cont_nop // Blacklisted.
1888 | cmp RCw, #0
1889 | bne =>BC_JLOOP // Jump to stitched trace.
1890 |
1891 | // Stitch a new trace to the previous trace.
1892 | mov CARG1, #GL_J(exitno)
1893 | str RAw, [GL, CARG1]
1894 | mov CARG1, #GL_J(L)
1895 | str L, [GL, CARG1]
1896 | str BASE, L->base
1897 | add CARG1, GL, #GG_G2J
1898 | mov CARG2, PC
1899 | bl extern lj_dispatch_stitch // (jit_State *J, const BCIns *pc)
1900 | ldr BASE, L->base
1901 | b ->cont_nop
1902 |
1903 |9: // Fill up results with nil.
1904 | str TISNIL, [BASE, RC, lsl #3]
1905 | add RC, RC, #1
1906 | b <3
1907 |.endif
1908 |
1909 |->vm_profhook: // Dispatch target for profiler hook.
1910#if LJ_HASPROFILE
1911 | mov CARG1, L
1912 | str BASE, L->base
1913 | mov CARG2, PC
1914 | bl extern lj_dispatch_profile // (lua_State *L, const BCIns *pc)
1915 | // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
1916 | ldr BASE, L->base
1917 | sub PC, PC, #4
1918 | b ->cont_nop
1919#endif
1920 |
1921 |//-----------------------------------------------------------------------
1922 |//-- Trace exit handler -------------------------------------------------
1923 |//-----------------------------------------------------------------------
1924 |
1925 |.macro savex_, a, b
1926 | stp d..a, d..b, [sp, #a*8]
1927 | stp x..a, x..b, [sp, #32*8+a*8]
1928 |.endmacro
1929 |
1930 |->vm_exit_handler:
1931 |.if JIT
1932 | sub sp, sp, #(64*8)
1933 | savex_, 0, 1
1934 | savex_, 2, 3
1935 | savex_, 4, 5
1936 | savex_, 6, 7
1937 | savex_, 8, 9
1938 | savex_, 10, 11
1939 | savex_, 12, 13
1940 | savex_, 14, 15
1941 | savex_, 16, 17
1942 | savex_, 18, 19
1943 | savex_, 20, 21
1944 | savex_, 22, 23
1945 | savex_, 24, 25
1946 | savex_, 26, 27
1947 | savex_, 28, 29
1948 | stp d30, d31, [sp, #30*8]
1949 | ldr CARG1, [sp, #64*8] // Load original value of lr.
1950 | add CARG3, sp, #64*8 // Recompute original value of sp.
1951 | mv_vmstate CARG4w, EXIT
1952 | stp xzr, CARG3, [sp, #62*8] // Store 0/sp in RID_LR/RID_SP.
1953 | sub CARG1, CARG1, lr
1954 | ldr L, GL->cur_L
1955 | lsr CARG1, CARG1, #2
1956 | ldr BASE, GL->jit_base
1957 | sub CARG1, CARG1, #2
1958 | ldr CARG2w, [lr] // Load trace number.
1959 | st_vmstate CARG4w
1960 |.if ENDIAN_BE
1961 | rev32 CARG2, CARG2
1962 |.endif
1963 | str BASE, L->base
1964 | ubfx CARG2w, CARG2w, #5, #16
1965 | str CARG1w, [GL, #GL_J(exitno)]
1966 | str CARG2w, [GL, #GL_J(parent)]
1967 | str L, [GL, #GL_J(L)]
1968 | str xzr, GL->jit_base
1969 | add CARG1, GL, #GG_G2J
1970 | mov CARG2, sp
1971 | bl extern lj_trace_exit // (jit_State *J, ExitState *ex)
1972 | // Returns MULTRES (unscaled) or negated error code.
1973 | ldr CARG2, L->cframe
1974 | ldr BASE, L->base
1975 | and sp, CARG2, #CFRAME_RAWMASK
1976 | ldr PC, SAVE_PC // Get SAVE_PC.
1977 | str L, SAVE_L // Set SAVE_L (on-trace resume/yield).
1978 | b >1
1979 |.endif
1980 |
1981 |->vm_exit_interp:
1982 | // CARG1 = MULTRES or negated error code, BASE, PC and GL set.
1983 |.if JIT
1984 | ldr L, SAVE_L
1985 |1:
1986 | cmp CARG1w, #0
1987 | blt >9 // Check for error from exit.
1988 | lsl RC, CARG1, #3
1989 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
1990 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
1991 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
1992 | movn TISNIL, #0
1993 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
1994 | str RCw, SAVE_MULTRES
1995 | str BASE, L->base
1996 | ldr CARG2, LFUNC:CARG2->pc
1997 | str xzr, GL->jit_base
1998 | mv_vmstate CARG4w, INTERP
1999 | ldr KBASE, [CARG2, #PC2PROTO(k)]
2000 | // Modified copy of ins_next which handles function header dispatch, too.
2001 | ldrb RBw, [PC, # OFS_OP]
2002 | ldr INSw, [PC], #4
2003 | st_vmstate CARG4w
2004 | cmp RBw, #BC_FUNCC+2 // Fast function?
2005 | add TMP1, GL, INS, uxtb #3
2006 | bhs >4
2007 |2:
2008 | cmp RBw, #BC_FUNCF // Function header?
2009 | add TMP0, GL, RB, uxtb #3
2010 | ldr RB, [TMP0, #GG_G2DISP]
2011 | decode_RA RA, INS
2012 | lsr TMP0, INS, #16
2013 | csel RC, TMP0, RC, lo
2014 | blo >5
2015 | ldr CARG3, [BASE, FRAME_FUNC]
2016 | sub RC, RC, #8
2017 | add RA, BASE, RA, lsl #3 // Yes: RA = BASE+framesize*8, RC = nargs*8
2018 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
2019 |5:
2020 | br RB
2021 |
2022 |4: // Check frame below fast function.
2023 | ldr CARG1, [BASE, FRAME_PC]
2024 | ands CARG2, CARG1, #FRAME_TYPE
2025 | bne <2 // Trace stitching continuation?
2026 | // Otherwise set KBASE for Lua function below fast function.
2027 | ldr CARG3w, [CARG1, #-4]
2028 | decode_RA CARG1, CARG3
2029 | sub CARG2, BASE, CARG1, lsl #3
2030 | ldr LFUNC:CARG3, [CARG2, #-32]
2031 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
2032 | ldr CARG3, LFUNC:CARG3->pc
2033 | ldr KBASE, [CARG3, #PC2PROTO(k)]
2034 | b <2
2035 |
2036 |9: // Rethrow error from the right C frame.
2037 | neg CARG2, CARG1
2038 | mov CARG1, L
2039 | bl extern lj_err_throw // (lua_State *L, int errcode)
2040 |.endif
2041 |
2042 |//-----------------------------------------------------------------------
2043 |//-- Math helper functions ----------------------------------------------
2044 |//-----------------------------------------------------------------------
2045 |
2046 | // int lj_vm_modi(int dividend, int divisor);
2047 |->vm_modi:
2048 | eor CARG4w, CARG1w, CARG2w
2049 | cmp CARG4w, #0
2050 | eor CARG3w, CARG1w, CARG1w, asr #31
2051 | eor CARG4w, CARG2w, CARG2w, asr #31
2052 | sub CARG3w, CARG3w, CARG1w, asr #31
2053 | sub CARG4w, CARG4w, CARG2w, asr #31
2054 | udiv CARG1w, CARG3w, CARG4w
2055 | msub CARG1w, CARG1w, CARG4w, CARG3w
2056 | ccmp CARG1w, #0, #4, mi
2057 | sub CARG3w, CARG1w, CARG4w
2058 | csel CARG1w, CARG1w, CARG3w, eq
2059 | eor CARG3w, CARG1w, CARG2w
2060 | cmp CARG3w, #0
2061 | cneg CARG1w, CARG1w, mi
2062 | ret
2063 |
2064 |//-----------------------------------------------------------------------
2065 |//-- Miscellaneous functions --------------------------------------------
2066 |//-----------------------------------------------------------------------
2067 |
2068 |//-----------------------------------------------------------------------
2069 |//-- FFI helper functions -----------------------------------------------
2070 |//-----------------------------------------------------------------------
2071 |
2072 |// Handler for callback functions.
2073 |// Saveregs already performed. Callback slot number in [sp], g in r12.
2074 |->vm_ffi_callback:
2075 |.if FFI
2076 |.type CTSTATE, CTState, PC
2077 | saveregs
2078 | ldr CTSTATE, GL:x10->ctype_state
2079 | mov GL, x10
2080 | add x10, sp, # CFRAME_SPACE
2081 | str w9, CTSTATE->cb.slot
2082 | stp x0, x1, CTSTATE->cb.gpr[0]
2083 | stp d0, d1, CTSTATE->cb.fpr[0]
2084 | stp x2, x3, CTSTATE->cb.gpr[2]
2085 | stp d2, d3, CTSTATE->cb.fpr[2]
2086 | stp x4, x5, CTSTATE->cb.gpr[4]
2087 | stp d4, d5, CTSTATE->cb.fpr[4]
2088 | stp x6, x7, CTSTATE->cb.gpr[6]
2089 | stp d6, d7, CTSTATE->cb.fpr[6]
2090 | str x10, CTSTATE->cb.stack
2091 | mov CARG1, CTSTATE
2092 | str CTSTATE, SAVE_PC // Any value outside of bytecode is ok.
2093 | mov CARG2, sp
2094 | bl extern lj_ccallback_enter // (CTState *cts, void *cf)
2095 | // Returns lua_State *.
2096 | ldp BASE, RC, L:CRET1->base
2097 | movz TISNUM, #(LJ_TISNUM>>1)&0xffff, lsl #48
2098 | movz TISNUMhi, #(LJ_TISNUM>>1)&0xffff, lsl #16
2099 | movn TISNIL, #0
2100 | mov L, CRET1
2101 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
2102 | sub RC, RC, BASE
2103 | st_vmstate ST_INTERP
2104 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
2105 | ins_callt
2106 |.endif
2107 |
2108 |->cont_ffi_callback: // Return from FFI callback.
2109 |.if FFI
2110 | ldr CTSTATE, GL->ctype_state
2111 | stp BASE, CARG4, L->base
2112 | str L, CTSTATE->L
2113 | mov CARG1, CTSTATE
2114 | mov CARG2, RA
2115 | bl extern lj_ccallback_leave // (CTState *cts, TValue *o)
2116 | ldp x0, x1, CTSTATE->cb.gpr[0]
2117 | ldp d0, d1, CTSTATE->cb.fpr[0]
2118 | b ->vm_leave_unw
2119 |.endif
2120 |
2121 |->vm_ffi_call: // Call C function via FFI.
2122 | // Caveat: needs special frame unwinding, see below.
2123 |.if FFI
2124 | .type CCSTATE, CCallState, x19
2125 | stp fp, lr, [sp, #-32]!
2126 | add fp, sp, #0
2127 | str CCSTATE, [sp, #16]
2128 | mov CCSTATE, x0
2129 | ldr TMP0w, CCSTATE:x0->spadj
2130 | ldrb TMP1w, CCSTATE->nsp
2131 | add TMP2, CCSTATE, #offsetof(CCallState, stack)
2132 | subs TMP1, TMP1, #1
2133 | ldr TMP3, CCSTATE->func
2134 | sub sp, fp, TMP0
2135 | bmi >2
2136 |1: // Copy stack slots
2137 | ldr TMP0, [TMP2, TMP1, lsl #3]
2138 | str TMP0, [sp, TMP1, lsl #3]
2139 | subs TMP1, TMP1, #1
2140 | bpl <1
2141 |2:
2142 | ldp x0, x1, CCSTATE->gpr[0]
2143 | ldp d0, d1, CCSTATE->fpr[0]
2144 | ldp x2, x3, CCSTATE->gpr[2]
2145 | ldp d2, d3, CCSTATE->fpr[2]
2146 | ldp x4, x5, CCSTATE->gpr[4]
2147 | ldp d4, d5, CCSTATE->fpr[4]
2148 | ldp x6, x7, CCSTATE->gpr[6]
2149 | ldp d6, d7, CCSTATE->fpr[6]
2150 | ldr x8, CCSTATE->retp
2151 | blr TMP3
2152 | mov sp, fp
2153 | stp x0, x1, CCSTATE->gpr[0]
2154 | stp d0, d1, CCSTATE->fpr[0]
2155 | stp d2, d3, CCSTATE->fpr[2]
2156 | ldr CCSTATE, [sp, #16]
2157 | ldp fp, lr, [sp], #32
2158 | ret
2159 |.endif
2160 |// Note: vm_ffi_call must be the last function in this object file!
2161 |
2162 |//-----------------------------------------------------------------------
2163}
2164
2165/* Generate the code for a single instruction. */
2166static void build_ins(BuildCtx *ctx, BCOp op, int defop)
2167{
2168 int vk = 0;
2169 |=>defop:
2170
2171 switch (op) {
2172
2173 /* -- Comparison ops ---------------------------------------------------- */
2174
2175 /* Remember: all ops branch for a true comparison, fall through otherwise. */
2176
2177 case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT:
2178 | // RA = src1, RC = src2, JMP with RC = target
2179 | ldr CARG1, [BASE, RA, lsl #3]
2180 | ldrh RBw, [PC, # OFS_RD]
2181 | ldr CARG2, [BASE, RC, lsl #3]
2182 | add PC, PC, #4
2183 | add RB, PC, RB, lsl #2
2184 | sub RB, RB, #0x20000
2185 | checkint CARG1, >3
2186 | checkint CARG2, >4
2187 | cmp CARG1w, CARG2w
2188 if (op == BC_ISLT) {
2189 | csel PC, RB, PC, lt
2190 } else if (op == BC_ISGE) {
2191 | csel PC, RB, PC, ge
2192 } else if (op == BC_ISLE) {
2193 | csel PC, RB, PC, le
2194 } else {
2195 | csel PC, RB, PC, gt
2196 }
2197 |1:
2198 | ins_next
2199 |
2200 |3: // RA not int.
2201 | ldr FARG1, [BASE, RA, lsl #3]
2202 | blo ->vmeta_comp
2203 | ldr FARG2, [BASE, RC, lsl #3]
2204 | cmp TISNUMhi, CARG2, lsr #32
2205 | bhi >5
2206 | bne ->vmeta_comp
2207 | // RA number, RC int.
2208 | scvtf FARG2, CARG2w
2209 | b >5
2210 |
2211 |4: // RA int, RC not int
2212 | ldr FARG2, [BASE, RC, lsl #3]
2213 | blo ->vmeta_comp
2214 | // RA int, RC number.
2215 | scvtf FARG1, CARG1w
2216 |
2217 |5: // RA number, RC number
2218 | fcmp FARG1, FARG2
2219 | // To preserve NaN semantics GE/GT branch on unordered, but LT/LE don't.
2220 if (op == BC_ISLT) {
2221 | csel PC, RB, PC, lo
2222 } else if (op == BC_ISGE) {
2223 | csel PC, RB, PC, hs
2224 } else if (op == BC_ISLE) {
2225 | csel PC, RB, PC, ls
2226 } else {
2227 | csel PC, RB, PC, hi
2228 }
2229 | b <1
2230 break;
2231
2232 case BC_ISEQV: case BC_ISNEV:
2233 vk = op == BC_ISEQV;
2234 | // RA = src1, RC = src2, JMP with RC = target
2235 | ldr CARG1, [BASE, RA, lsl #3]
2236 | add RC, BASE, RC, lsl #3
2237 | ldrh RBw, [PC, # OFS_RD]
2238 | ldr CARG3, [RC]
2239 | add PC, PC, #4
2240 | add RB, PC, RB, lsl #2
2241 | sub RB, RB, #0x20000
2242 | asr ITYPE, CARG3, #47
2243 | cmn ITYPE, #-LJ_TISNUM
2244 if (vk) {
2245 | bls ->BC_ISEQN_Z
2246 } else {
2247 | bls ->BC_ISNEN_Z
2248 }
2249 | // RC is not a number.
2250 | asr TMP0, CARG1, #47
2251 |.if FFI
2252 | // Check if RC or RA is a cdata.
2253 | cmn ITYPE, #-LJ_TCDATA
2254 | ccmn TMP0, #-LJ_TCDATA, #4, ne
2255 | beq ->vmeta_equal_cd
2256 |.endif
2257 | cmp CARG1, CARG3
2258 | bne >2
2259 | // Tag and value are equal.
2260 if (vk) {
2261 |->BC_ISEQV_Z:
2262 | mov PC, RB // Perform branch.
2263 }
2264 |1:
2265 | ins_next
2266 |
2267 |2: // Check if the tags are the same and it's a table or userdata.
2268 | cmp ITYPE, TMP0
2269 | ccmn ITYPE, #-LJ_TISTABUD, #2, eq
2270 if (vk) {
2271 | bhi <1
2272 } else {
2273 | bhi ->BC_ISEQV_Z // Reuse code from opposite instruction.
2274 }
2275 | // Different tables or userdatas. Need to check __eq metamethod.
2276 | // Field metatable must be at same offset for GCtab and GCudata!
2277 | and TAB:CARG2, CARG1, #LJ_GCVMASK
2278 | ldr TAB:TMP2, TAB:CARG2->metatable
2279 if (vk) {
2280 | cbz TAB:TMP2, <1 // No metatable?
2281 | ldrb TMP1w, TAB:TMP2->nomm
2282 | mov CARG4, #0 // ne = 0
2283 | tbnz TMP1w, #MM_eq, <1 // 'no __eq' flag set: done.
2284 } else {
2285 | cbz TAB:TMP2, ->BC_ISEQV_Z // No metatable?
2286 | ldrb TMP1w, TAB:TMP2->nomm
2287 | mov CARG4, #1 // ne = 1.
2288 | tbnz TMP1w, #MM_eq, ->BC_ISEQV_Z // 'no __eq' flag set: done.
2289 }
2290 | b ->vmeta_equal
2291 break;
2292
2293 case BC_ISEQS: case BC_ISNES:
2294 vk = op == BC_ISEQS;
2295 | // RA = src, RC = str_const (~), JMP with RC = target
2296 | ldr CARG1, [BASE, RA, lsl #3]
2297 | mvn RC, RC
2298 | ldrh RBw, [PC, # OFS_RD]
2299 | ldr CARG2, [KBASE, RC, lsl #3]
2300 | add PC, PC, #4
2301 | movn TMP0, #~LJ_TSTR
2302 |.if FFI
2303 | asr ITYPE, CARG1, #47
2304 |.endif
2305 | add RB, PC, RB, lsl #2
2306 | add CARG2, CARG2, TMP0, lsl #47
2307 | sub RB, RB, #0x20000
2308 |.if FFI
2309 | cmn ITYPE, #-LJ_TCDATA
2310 | beq ->vmeta_equal_cd
2311 |.endif
2312 | cmp CARG1, CARG2
2313 if (vk) {
2314 | csel PC, RB, PC, eq
2315 } else {
2316 | csel PC, RB, PC, ne
2317 }
2318 | ins_next
2319 break;
2320
2321 case BC_ISEQN: case BC_ISNEN:
2322 vk = op == BC_ISEQN;
2323 | // RA = src, RC = num_const (~), JMP with RC = target
2324 | ldr CARG1, [BASE, RA, lsl #3]
2325 | add RC, KBASE, RC, lsl #3
2326 | ldrh RBw, [PC, # OFS_RD]
2327 | ldr CARG3, [RC]
2328 | add PC, PC, #4
2329 | add RB, PC, RB, lsl #2
2330 | sub RB, RB, #0x20000
2331 if (vk) {
2332 |->BC_ISEQN_Z:
2333 } else {
2334 |->BC_ISNEN_Z:
2335 }
2336 | checkint CARG1, >4
2337 | checkint CARG3, >6
2338 | cmp CARG1w, CARG3w
2339 |1:
2340 if (vk) {
2341 | csel PC, RB, PC, eq
2342 |2:
2343 } else {
2344 |2:
2345 | csel PC, RB, PC, ne
2346 }
2347 |3:
2348 | ins_next
2349 |
2350 |4: // RA not int.
2351 |.if FFI
2352 | blo >7
2353 |.else
2354 | blo <2
2355 |.endif
2356 | ldr FARG1, [BASE, RA, lsl #3]
2357 | ldr FARG2, [RC]
2358 | cmp TISNUMhi, CARG3, lsr #32
2359 | bne >5
2360 | // RA number, RC int.
2361 | scvtf FARG2, CARG3w
2362 |5:
2363 | // RA number, RC number.
2364 | fcmp FARG1, FARG2
2365 | b <1
2366 |
2367 |6: // RA int, RC number
2368 | ldr FARG2, [RC]
2369 | scvtf FARG1, CARG1w
2370 | fcmp FARG1, FARG2
2371 | b <1
2372 |
2373 |.if FFI
2374 |7:
2375 | asr ITYPE, CARG1, #47
2376 | cmn ITYPE, #-LJ_TCDATA
2377 | bne <2
2378 | b ->vmeta_equal_cd
2379 |.endif
2380 break;
2381
2382 case BC_ISEQP: case BC_ISNEP:
2383 vk = op == BC_ISEQP;
2384 | // RA = src, RC = primitive_type (~), JMP with RC = target
2385 | ldr TMP0, [BASE, RA, lsl #3]
2386 | ldrh RBw, [PC, # OFS_RD]
2387 | add PC, PC, #4
2388 | add RC, RC, #1
2389 | add RB, PC, RB, lsl #2
2390 |.if FFI
2391 | asr ITYPE, TMP0, #47
2392 | cmn ITYPE, #-LJ_TCDATA
2393 | beq ->vmeta_equal_cd
2394 | cmn RC, ITYPE
2395 |.else
2396 | cmn RC, TMP0, asr #47
2397 |.endif
2398 | sub RB, RB, #0x20000
2399 if (vk) {
2400 | csel PC, RB, PC, eq
2401 } else {
2402 | csel PC, RB, PC, ne
2403 }
2404 | ins_next
2405 break;
2406
2407 /* -- Unary test and copy ops ------------------------------------------- */
2408
2409 case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF:
2410 | // RA = dst or unused, RC = src, JMP with RC = target
2411 | ldrh RBw, [PC, # OFS_RD]
2412 | ldr TMP0, [BASE, RC, lsl #3]
2413 | add PC, PC, #4
2414 | mov_false TMP1
2415 | add RB, PC, RB, lsl #2
2416 | cmp TMP0, TMP1
2417 | sub RB, RB, #0x20000
2418 if (op == BC_ISTC || op == BC_IST) {
2419 if (op == BC_ISTC) {
2420 | csel RA, RA, RC, lo
2421 }
2422 | csel PC, RB, PC, lo
2423 } else {
2424 if (op == BC_ISFC) {
2425 | csel RA, RA, RC, hs
2426 }
2427 | csel PC, RB, PC, hs
2428 }
2429 if (op == BC_ISTC || op == BC_ISFC) {
2430 | str TMP0, [BASE, RA, lsl #3]
2431 }
2432 | ins_next
2433 break;
2434
2435 case BC_ISTYPE:
2436 | // RA = src, RC = -type
2437 | ldr TMP0, [BASE, RA, lsl #3]
2438 | cmn RC, TMP0, asr #47
2439 | bne ->vmeta_istype
2440 | ins_next
2441 break;
2442 case BC_ISNUM:
2443 | // RA = src, RC = -(TISNUM-1)
2444 | ldr TMP0, [BASE, RA]
2445 | checknum TMP0, ->vmeta_istype
2446 | ins_next
2447 break;
2448
2449 /* -- Unary ops --------------------------------------------------------- */
2450
2451 case BC_MOV:
2452 | // RA = dst, RC = src
2453 | ldr TMP0, [BASE, RC, lsl #3]
2454 | str TMP0, [BASE, RA, lsl #3]
2455 | ins_next
2456 break;
2457 case BC_NOT:
2458 | // RA = dst, RC = src
2459 | ldr TMP0, [BASE, RC, lsl #3]
2460 | mov_false TMP1
2461 | mov_true TMP2
2462 | cmp TMP0, TMP1
2463 | csel TMP0, TMP1, TMP2, lo
2464 | str TMP0, [BASE, RA, lsl #3]
2465 | ins_next
2466 break;
2467 case BC_UNM:
2468 | // RA = dst, RC = src
2469 | ldr TMP0, [BASE, RC, lsl #3]
2470 | asr ITYPE, TMP0, #47
2471 | cmn ITYPE, #-LJ_TISNUM
2472 | bhi ->vmeta_unm
2473 | eor TMP0, TMP0, #U64x(80000000,00000000)
2474 | bne >5
2475 | negs TMP0w, TMP0w
2476 | movz CARG3, #0x41e0, lsl #48 // 2^31.
2477 | add TMP0, TMP0, TISNUM
2478 | csel TMP0, TMP0, CARG3, vc
2479 |5:
2480 | str TMP0, [BASE, RA, lsl #3]
2481 | ins_next
2482 break;
2483 case BC_LEN:
2484 | // RA = dst, RC = src
2485 | ldr CARG1, [BASE, RC, lsl #3]
2486 | asr ITYPE, CARG1, #47
2487 | cmn ITYPE, #-LJ_TSTR
2488 | and CARG1, CARG1, #LJ_GCVMASK
2489 | bne >2
2490 | ldr CARG1w, STR:CARG1->len
2491 |1:
2492 | add CARG1, CARG1, TISNUM
2493 | str CARG1, [BASE, RA, lsl #3]
2494 | ins_next
2495 |
2496 |2:
2497 | cmn ITYPE, #-LJ_TTAB
2498 | bne ->vmeta_len
2499#if LJ_52
2500 | ldr TAB:CARG2, TAB:CARG1->metatable
2501 | cbnz TAB:CARG2, >9
2502 |3:
2503#endif
2504 |->BC_LEN_Z:
2505 | bl extern lj_tab_len // (GCtab *t)
2506 | // Returns uint32_t (but less than 2^31).
2507 | b <1
2508 |
2509#if LJ_52
2510 |9:
2511 | ldrb TMP1w, TAB:CARG2->nomm
2512 | tbnz TMP1w, #MM_len, <3 // 'no __len' flag set: done.
2513 | b ->vmeta_len
2514#endif
2515 break;
2516
2517 /* -- Binary ops -------------------------------------------------------- */
2518
2519 |.macro ins_arithcheck_int, target
2520 | checkint CARG1, target
2521 | checkint CARG2, target
2522 |.endmacro
2523 |
2524 |.macro ins_arithcheck_num, target
2525 | checknum CARG1, target
2526 | checknum CARG2, target
2527 |.endmacro
2528 |
2529 |.macro ins_arithcheck_nzdiv, target
2530 | cbz CARG2w, target
2531 |.endmacro
2532 |
2533 |.macro ins_arithhead
2534 ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
2535 ||if (vk == 1) {
2536 | and RC, RC, #255
2537 | decode_RB RB, INS
2538 ||} else {
2539 | decode_RB RB, INS
2540 | and RC, RC, #255
2541 ||}
2542 |.endmacro
2543 |
2544 |.macro ins_arithload, reg1, reg2
2545 | // RA = dst, RB = src1, RC = src2 | num_const
2546 ||switch (vk) {
2547 ||case 0:
2548 | ldr reg1, [BASE, RB, lsl #3]
2549 | ldr reg2, [KBASE, RC, lsl #3]
2550 || break;
2551 ||case 1:
2552 | ldr reg1, [KBASE, RC, lsl #3]
2553 | ldr reg2, [BASE, RB, lsl #3]
2554 || break;
2555 ||default:
2556 | ldr reg1, [BASE, RB, lsl #3]
2557 | ldr reg2, [BASE, RC, lsl #3]
2558 || break;
2559 ||}
2560 |.endmacro
2561 |
2562 |.macro ins_arithfallback, ins
2563 ||switch (vk) {
2564 ||case 0:
2565 | ins ->vmeta_arith_vn
2566 || break;
2567 ||case 1:
2568 | ins ->vmeta_arith_nv
2569 || break;
2570 ||default:
2571 | ins ->vmeta_arith_vv
2572 || break;
2573 ||}
2574 |.endmacro
2575 |
2576 |.macro ins_arithmod, res, reg1, reg2
2577 | fdiv d2, reg1, reg2
2578 | frintm d2, d2
2579 | fmsub res, d2, reg2, reg1
2580 |.endmacro
2581 |
2582 |.macro ins_arithdn, intins, fpins
2583 | ins_arithhead
2584 | ins_arithload CARG1, CARG2
2585 | ins_arithcheck_int >5
2586 |.if "intins" == "smull"
2587 | smull CARG1, CARG1w, CARG2w
2588 | cmp CARG1, CARG1, sxtw
2589 | mov CARG1w, CARG1w
2590 | ins_arithfallback bne
2591 |.elif "intins" == "ins_arithmodi"
2592 | ins_arithfallback ins_arithcheck_nzdiv
2593 | bl ->vm_modi
2594 |.else
2595 | intins CARG1w, CARG1w, CARG2w
2596 | ins_arithfallback bvs
2597 |.endif
2598 | add CARG1, CARG1, TISNUM
2599 | str CARG1, [BASE, RA, lsl #3]
2600 |4:
2601 | ins_next
2602 |
2603 |5: // FP variant.
2604 | ins_arithload FARG1, FARG2
2605 | ins_arithfallback ins_arithcheck_num
2606 | fpins FARG1, FARG1, FARG2
2607 | str FARG1, [BASE, RA, lsl #3]
2608 | b <4
2609 |.endmacro
2610 |
2611 |.macro ins_arithfp, fpins
2612 | ins_arithhead
2613 | ins_arithload CARG1, CARG2
2614 | ins_arithload FARG1, FARG2
2615 | ins_arithfallback ins_arithcheck_num
2616 |.if "fpins" == "fpow"
2617 | bl extern pow
2618 |.else
2619 | fpins FARG1, FARG1, FARG2
2620 |.endif
2621 | str FARG1, [BASE, RA, lsl #3]
2622 | ins_next
2623 |.endmacro
2624
2625 case BC_ADDVN: case BC_ADDNV: case BC_ADDVV:
2626 | ins_arithdn adds, fadd
2627 break;
2628 case BC_SUBVN: case BC_SUBNV: case BC_SUBVV:
2629 | ins_arithdn subs, fsub
2630 break;
2631 case BC_MULVN: case BC_MULNV: case BC_MULVV:
2632 | ins_arithdn smull, fmul
2633 break;
2634 case BC_DIVVN: case BC_DIVNV: case BC_DIVVV:
2635 | ins_arithfp fdiv
2636 break;
2637 case BC_MODVN: case BC_MODNV: case BC_MODVV:
2638 | ins_arithdn ins_arithmodi, ins_arithmod
2639 break;
2640 case BC_POW:
2641 | // NYI: (partial) integer arithmetic.
2642 | ins_arithfp fpow
2643 break;
2644
2645 case BC_CAT:
2646 | decode_RB RB, INS
2647 | and RC, RC, #255
2648 | // RA = dst, RB = src_start, RC = src_end
2649 | str BASE, L->base
2650 | sub CARG3, RC, RB
2651 | add CARG2, BASE, RC, lsl #3
2652 |->BC_CAT_Z:
2653 | // RA = dst, CARG2 = top-1, CARG3 = left
2654 | mov CARG1, L
2655 | str PC, SAVE_PC
2656 | bl extern lj_meta_cat // (lua_State *L, TValue *top, int left)
2657 | // Returns NULL (finished) or TValue * (metamethod).
2658 | ldrb RBw, [PC, #-4+OFS_RB]
2659 | ldr BASE, L->base
2660 | cbnz CRET1, ->vmeta_binop
2661 | ldr TMP0, [BASE, RB, lsl #3]
2662 | str TMP0, [BASE, RA, lsl #3] // Copy result to RA.
2663 | ins_next
2664 break;
2665
2666 /* -- Constant ops ------------------------------------------------------ */
2667
2668 case BC_KSTR:
2669 | // RA = dst, RC = str_const (~)
2670 | mvn RC, RC
2671 | ldr TMP0, [KBASE, RC, lsl #3]
2672 | movn TMP1, #~LJ_TSTR
2673 | add TMP0, TMP0, TMP1, lsl #47
2674 | str TMP0, [BASE, RA, lsl #3]
2675 | ins_next
2676 break;
2677 case BC_KCDATA:
2678 |.if FFI
2679 | // RA = dst, RC = cdata_const (~)
2680 | mvn RC, RC
2681 | ldr TMP0, [KBASE, RC, lsl #3]
2682 | movn TMP1, #~LJ_TCDATA
2683 | add TMP0, TMP0, TMP1, lsl #47
2684 | str TMP0, [BASE, RA, lsl #3]
2685 | ins_next
2686 |.endif
2687 break;
2688 case BC_KSHORT:
2689 | // RA = dst, RC = int16_literal
2690 | sxth RCw, RCw
2691 | add TMP0, RC, TISNUM
2692 | str TMP0, [BASE, RA, lsl #3]
2693 | ins_next
2694 break;
2695 case BC_KNUM:
2696 | // RA = dst, RC = num_const
2697 | ldr TMP0, [KBASE, RC, lsl #3]
2698 | str TMP0, [BASE, RA, lsl #3]
2699 | ins_next
2700 break;
2701 case BC_KPRI:
2702 | // RA = dst, RC = primitive_type (~)
2703 | mvn TMP0, RC, lsl #47
2704 | str TMP0, [BASE, RA, lsl #3]
2705 | ins_next
2706 break;
2707 case BC_KNIL:
2708 | // RA = base, RC = end
2709 | add RA, BASE, RA, lsl #3
2710 | add RC, BASE, RC, lsl #3
2711 | str TISNIL, [RA], #8
2712 |1:
2713 | cmp RA, RC
2714 | str TISNIL, [RA], #8
2715 | blt <1
2716 | ins_next_
2717 break;
2718
2719 /* -- Upvalue and function ops ------------------------------------------ */
2720
2721 case BC_UGET:
2722 | // RA = dst, RC = uvnum
2723 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2724 | add RC, RC, #offsetof(GCfuncL, uvptr)/8
2725 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2726 | ldr UPVAL:CARG2, [LFUNC:CARG2, RC, lsl #3]
2727 | ldr CARG2, UPVAL:CARG2->v
2728 | ldr TMP0, [CARG2]
2729 | str TMP0, [BASE, RA, lsl #3]
2730 | ins_next
2731 break;
2732 case BC_USETV:
2733 | // RA = uvnum, RC = src
2734 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2735 | add RA, RA, #offsetof(GCfuncL, uvptr)/8
2736 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2737 | ldr UPVAL:CARG1, [LFUNC:CARG2, RA, lsl #3]
2738 | ldr CARG3, [BASE, RC, lsl #3]
2739 | ldr CARG2, UPVAL:CARG1->v
2740 | ldrb TMP2w, UPVAL:CARG1->marked
2741 | ldrb TMP0w, UPVAL:CARG1->closed
2742 | asr ITYPE, CARG3, #47
2743 | str CARG3, [CARG2]
2744 | add ITYPE, ITYPE, #-LJ_TISGCV
2745 | tst TMP2w, #LJ_GC_BLACK // isblack(uv)
2746 | ccmp TMP0w, #0, #4, ne // && uv->closed
2747 | ccmn ITYPE, #-(LJ_TNUMX - LJ_TISGCV), #0, ne // && tvisgcv(v)
2748 | bhi >2
2749 |1:
2750 | ins_next
2751 |
2752 |2: // Check if new value is white.
2753 | and GCOBJ:CARG3, CARG3, #LJ_GCVMASK
2754 | ldrb TMP1w, GCOBJ:CARG3->gch.marked
2755 | tst TMP1w, #LJ_GC_WHITES // iswhite(str)
2756 | beq <1
2757 | // Crossed a write barrier. Move the barrier forward.
2758 | mov CARG1, GL
2759 | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv)
2760 | b <1
2761 break;
2762 case BC_USETS:
2763 | // RA = uvnum, RC = str_const (~)
2764 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2765 | add RA, RA, #offsetof(GCfuncL, uvptr)/8
2766 | mvn RC, RC
2767 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2768 | ldr UPVAL:CARG1, [LFUNC:CARG2, RA, lsl #3]
2769 | ldr STR:CARG3, [KBASE, RC, lsl #3]
2770 | movn TMP0, #~LJ_TSTR
2771 | ldr CARG2, UPVAL:CARG1->v
2772 | ldrb TMP2w, UPVAL:CARG1->marked
2773 | add TMP0, STR:CARG3, TMP0, lsl #47
2774 | ldrb TMP1w, STR:CARG3->marked
2775 | str TMP0, [CARG2]
2776 | tbnz TMP2w, #2, >2 // isblack(uv)
2777 |1:
2778 | ins_next
2779 |
2780 |2: // Check if string is white and ensure upvalue is closed.
2781 | ldrb TMP0w, UPVAL:CARG1->closed
2782 | tst TMP1w, #LJ_GC_WHITES // iswhite(str)
2783 | ccmp TMP0w, #0, #4, ne
2784 | beq <1
2785 | // Crossed a write barrier. Move the barrier forward.
2786 | mov CARG1, GL
2787 | bl extern lj_gc_barrieruv // (global_State *g, TValue *tv)
2788 | b <1
2789 break;
2790 case BC_USETN:
2791 | // RA = uvnum, RC = num_const
2792 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2793 | add RA, RA, #offsetof(GCfuncL, uvptr)/8
2794 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2795 | ldr UPVAL:CARG2, [LFUNC:CARG2, RA, lsl #3]
2796 | ldr TMP0, [KBASE, RC, lsl #3]
2797 | ldr CARG2, UPVAL:CARG2->v
2798 | str TMP0, [CARG2]
2799 | ins_next
2800 break;
2801 case BC_USETP:
2802 | // RA = uvnum, RC = primitive_type (~)
2803 | ldr LFUNC:CARG2, [BASE, FRAME_FUNC]
2804 | add RA, RA, #offsetof(GCfuncL, uvptr)/8
2805 | and LFUNC:CARG2, CARG2, #LJ_GCVMASK
2806 | ldr UPVAL:CARG2, [LFUNC:CARG2, RA, lsl #3]
2807 | mvn TMP0, RC, lsl #47
2808 | ldr CARG2, UPVAL:CARG2->v
2809 | str TMP0, [CARG2]
2810 | ins_next
2811 break;
2812
2813 case BC_UCLO:
2814 | // RA = level, RC = target
2815 | ldr CARG3, L->openupval
2816 | add RC, PC, RC, lsl #2
2817 | str BASE, L->base
2818 | sub PC, RC, #0x20000
2819 | cbz CARG3, >1
2820 | mov CARG1, L
2821 | add CARG2, BASE, RA, lsl #3
2822 | bl extern lj_func_closeuv // (lua_State *L, TValue *level)
2823 | ldr BASE, L->base
2824 |1:
2825 | ins_next
2826 break;
2827
2828 case BC_FNEW:
2829 | // RA = dst, RC = proto_const (~) (holding function prototype)
2830 | mvn RC, RC
2831 | str BASE, L->base
2832 | ldr LFUNC:CARG3, [BASE, FRAME_FUNC]
2833 | str PC, SAVE_PC
2834 | ldr CARG2, [KBASE, RC, lsl #3]
2835 | mov CARG1, L
2836 | and LFUNC:CARG3, CARG3, #LJ_GCVMASK
2837 | // (lua_State *L, GCproto *pt, GCfuncL *parent)
2838 | bl extern lj_func_newL_gc
2839 | // Returns GCfuncL *.
2840 | ldr BASE, L->base
2841 | movn TMP0, #~LJ_TFUNC
2842 | add CRET1, CRET1, TMP0, lsl #47
2843 | str CRET1, [BASE, RA, lsl #3]
2844 | ins_next
2845 break;
2846
2847 /* -- Table ops --------------------------------------------------------- */
2848
2849 case BC_TNEW:
2850 case BC_TDUP:
2851 | // RA = dst, RC = (hbits|asize) | tab_const (~)
2852 | ldp CARG3, CARG4, GL->gc.total // Assumes threshold follows total.
2853 | str BASE, L->base
2854 | str PC, SAVE_PC
2855 | mov CARG1, L
2856 | cmp CARG3, CARG4
2857 | bhs >5
2858 |1:
2859 if (op == BC_TNEW) {
2860 | and CARG2, RC, #0x7ff
2861 | lsr CARG3, RC, #11
2862 | cmp CARG2, #0x7ff
2863 | mov TMP0, #0x801
2864 | csel CARG2, CARG2, TMP0, ne
2865 | bl extern lj_tab_new // (lua_State *L, int32_t asize, uint32_t hbits)
2866 | // Returns GCtab *.
2867 } else {
2868 | mvn RC, RC
2869 | ldr CARG2, [KBASE, RC, lsl #3]
2870 | bl extern lj_tab_dup // (lua_State *L, Table *kt)
2871 | // Returns GCtab *.
2872 }
2873 | ldr BASE, L->base
2874 | movk CRET1, #(LJ_TTAB>>1)&0xffff, lsl #48
2875 | str CRET1, [BASE, RA, lsl #3]
2876 | ins_next
2877 |
2878 |5:
2879 | bl extern lj_gc_step_fixtop // (lua_State *L)
2880 | mov CARG1, L
2881 | b <1
2882 break;
2883
2884 case BC_GGET:
2885 | // RA = dst, RC = str_const (~)
2886 case BC_GSET:
2887 | // RA = dst, RC = str_const (~)
2888 | ldr LFUNC:CARG1, [BASE, FRAME_FUNC]
2889 | mvn RC, RC
2890 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK
2891 | ldr TAB:CARG2, LFUNC:CARG1->env
2892 | ldr STR:RC, [KBASE, RC, lsl #3]
2893 if (op == BC_GGET) {
2894 | b ->BC_TGETS_Z
2895 } else {
2896 | b ->BC_TSETS_Z
2897 }
2898 break;
2899
2900 case BC_TGETV:
2901 | decode_RB RB, INS
2902 | and RC, RC, #255
2903 | // RA = dst, RB = table, RC = key
2904 | ldr CARG2, [BASE, RB, lsl #3]
2905 | ldr TMP1, [BASE, RC, lsl #3]
2906 | checktab CARG2, ->vmeta_tgetv
2907 | checkint TMP1, >9 // Integer key?
2908 | ldr CARG3, TAB:CARG2->array
2909 | ldr CARG1w, TAB:CARG2->asize
2910 | add CARG3, CARG3, TMP1, uxtw #3
2911 | cmp TMP1w, CARG1w // In array part?
2912 | bhs ->vmeta_tgetv
2913 | ldr TMP0, [CARG3]
2914 | cmp TMP0, TISNIL
2915 | beq >5
2916 |1:
2917 | str TMP0, [BASE, RA, lsl #3]
2918 | ins_next
2919 |
2920 |5: // Check for __index if table value is nil.
2921 | ldr TAB:CARG1, TAB:CARG2->metatable
2922 | cbz TAB:CARG1, <1 // No metatable: done.
2923 | ldrb TMP1w, TAB:CARG1->nomm
2924 | tbnz TMP1w, #MM_index, <1 // 'no __index' flag set: done.
2925 | b ->vmeta_tgetv
2926 |
2927 |9:
2928 | asr ITYPE, TMP1, #47
2929 | cmn ITYPE, #-LJ_TSTR // String key?
2930 | bne ->vmeta_tgetv
2931 | and STR:RC, TMP1, #LJ_GCVMASK
2932 | b ->BC_TGETS_Z
2933 break;
2934 case BC_TGETS:
2935 | decode_RB RB, INS
2936 | and RC, RC, #255
2937 | // RA = dst, RB = table, RC = str_const (~)
2938 | ldr CARG2, [BASE, RB, lsl #3]
2939 | mvn RC, RC
2940 | ldr STR:RC, [KBASE, RC, lsl #3]
2941 | checktab CARG2, ->vmeta_tgets1
2942 |->BC_TGETS_Z:
2943 | // TAB:CARG2 = GCtab *, STR:RC = GCstr *, RA = dst
2944 | ldr TMP1w, TAB:CARG2->hmask
2945 | ldr TMP2w, STR:RC->hash
2946 | ldr NODE:CARG3, TAB:CARG2->node
2947 | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask
2948 | add TMP1, TMP1, TMP1, lsl #1
2949 | movn CARG4, #~LJ_TSTR
2950 | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8
2951 | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for.
2952 |1:
2953 | ldp TMP0, CARG1, NODE:CARG3->val
2954 | ldr NODE:CARG3, NODE:CARG3->next
2955 | cmp CARG1, CARG4
2956 | bne >4
2957 | cmp TMP0, TISNIL
2958 | beq >5
2959 |3:
2960 | str TMP0, [BASE, RA, lsl #3]
2961 | ins_next
2962 |
2963 |4: // Follow hash chain.
2964 | cbnz NODE:CARG3, <1
2965 | // End of hash chain: key not found, nil result.
2966 | mov TMP0, TISNIL
2967 |
2968 |5: // Check for __index if table value is nil.
2969 | ldr TAB:CARG1, TAB:CARG2->metatable
2970 | cbz TAB:CARG1, <3 // No metatable: done.
2971 | ldrb TMP1w, TAB:CARG1->nomm
2972 | tbnz TMP1w, #MM_index, <3 // 'no __index' flag set: done.
2973 | b ->vmeta_tgets
2974 break;
2975 case BC_TGETB:
2976 | decode_RB RB, INS
2977 | and RC, RC, #255
2978 | // RA = dst, RB = table, RC = index
2979 | ldr CARG2, [BASE, RB, lsl #3]
2980 | checktab CARG2, ->vmeta_tgetb
2981 | ldr CARG3, TAB:CARG2->array
2982 | ldr CARG1w, TAB:CARG2->asize
2983 | add CARG3, CARG3, RC, lsl #3
2984 | cmp RCw, CARG1w // In array part?
2985 | bhs ->vmeta_tgetb
2986 | ldr TMP0, [CARG3]
2987 | cmp TMP0, TISNIL
2988 | beq >5
2989 |1:
2990 | str TMP0, [BASE, RA, lsl #3]
2991 | ins_next
2992 |
2993 |5: // Check for __index if table value is nil.
2994 | ldr TAB:CARG1, TAB:CARG2->metatable
2995 | cbz TAB:CARG1, <1 // No metatable: done.
2996 | ldrb TMP1w, TAB:CARG1->nomm
2997 | tbnz TMP1w, #MM_index, <1 // 'no __index' flag set: done.
2998 | b ->vmeta_tgetb
2999 break;
3000 case BC_TGETR:
3001 | decode_RB RB, INS
3002 | and RC, RC, #255
3003 | // RA = dst, RB = table, RC = key
3004 | ldr CARG1, [BASE, RB, lsl #3]
3005 | ldr TMP1, [BASE, RC, lsl #3]
3006 | and TAB:CARG1, CARG1, #LJ_GCVMASK
3007 | ldr CARG3, TAB:CARG1->array
3008 | ldr TMP2w, TAB:CARG1->asize
3009 | add CARG3, CARG3, TMP1w, uxtw #3
3010 | cmp TMP1w, TMP2w // In array part?
3011 | bhs ->vmeta_tgetr
3012 | ldr TMP0, [CARG3]
3013 |->BC_TGETR_Z:
3014 | str TMP0, [BASE, RA, lsl #3]
3015 | ins_next
3016 break;
3017
3018 case BC_TSETV:
3019 | decode_RB RB, INS
3020 | and RC, RC, #255
3021 | // RA = src, RB = table, RC = key
3022 | ldr CARG2, [BASE, RB, lsl #3]
3023 | ldr TMP1, [BASE, RC, lsl #3]
3024 | checktab CARG2, ->vmeta_tsetv
3025 | checkint TMP1, >9 // Integer key?
3026 | ldr CARG3, TAB:CARG2->array
3027 | ldr CARG1w, TAB:CARG2->asize
3028 | add CARG3, CARG3, TMP1, uxtw #3
3029 | cmp TMP1w, CARG1w // In array part?
3030 | bhs ->vmeta_tsetv
3031 | ldr TMP1, [CARG3]
3032 | ldr TMP0, [BASE, RA, lsl #3]
3033 | ldrb TMP2w, TAB:CARG2->marked
3034 | cmp TMP1, TISNIL // Previous value is nil?
3035 | beq >5
3036 |1:
3037 | str TMP0, [CARG3]
3038 | tbnz TMP2w, #2, >7 // isblack(table)
3039 |2:
3040 | ins_next
3041 |
3042 |5: // Check for __newindex if previous value is nil.
3043 | ldr TAB:CARG1, TAB:CARG2->metatable
3044 | cbz TAB:CARG1, <1 // No metatable: done.
3045 | ldrb TMP1w, TAB:CARG1->nomm
3046 | tbnz TMP1w, #MM_newindex, <1 // 'no __newindex' flag set: done.
3047 | b ->vmeta_tsetv
3048 |
3049 |7: // Possible table write barrier for the value. Skip valiswhite check.
3050 | barrierback TAB:CARG2, TMP2w, TMP1
3051 | b <2
3052 |
3053 |9:
3054 | asr ITYPE, TMP1, #47
3055 | cmn ITYPE, #-LJ_TSTR // String key?
3056 | bne ->vmeta_tsetv
3057 | and STR:RC, TMP1, #LJ_GCVMASK
3058 | b ->BC_TSETS_Z
3059 break;
3060 case BC_TSETS:
3061 | decode_RB RB, INS
3062 | and RC, RC, #255
3063 | // RA = dst, RB = table, RC = str_const (~)
3064 | ldr CARG2, [BASE, RB, lsl #3]
3065 | mvn RC, RC
3066 | ldr STR:RC, [KBASE, RC, lsl #3]
3067 | checktab CARG2, ->vmeta_tsets1
3068 |->BC_TSETS_Z:
3069 | // TAB:CARG2 = GCtab *, STR:RC = GCstr *, RA = src
3070 | ldr TMP1w, TAB:CARG2->hmask
3071 | ldr TMP2w, STR:RC->hash
3072 | ldr NODE:CARG3, TAB:CARG2->node
3073 | and TMP1w, TMP1w, TMP2w // idx = str->hash & tab->hmask
3074 | add TMP1, TMP1, TMP1, lsl #1
3075 | movn CARG4, #~LJ_TSTR
3076 | add NODE:CARG3, NODE:CARG3, TMP1, lsl #3 // node = tab->node + idx*3*8
3077 | add CARG4, STR:RC, CARG4, lsl #47 // Tagged key to look for.
3078 | strb wzr, TAB:CARG2->nomm // Clear metamethod cache.
3079 |1:
3080 | ldp TMP1, CARG1, NODE:CARG3->val
3081 | ldr NODE:TMP3, NODE:CARG3->next
3082 | ldrb TMP2w, TAB:CARG2->marked
3083 | cmp CARG1, CARG4
3084 | bne >5
3085 | ldr TMP0, [BASE, RA, lsl #3]
3086 | cmp TMP1, TISNIL // Previous value is nil?
3087 | beq >4
3088 |2:
3089 | str TMP0, NODE:CARG3->val
3090 | tbnz TMP2w, #2, >7 // isblack(table)
3091 |3:
3092 | ins_next
3093 |
3094 |4: // Check for __newindex if previous value is nil.
3095 | ldr TAB:CARG1, TAB:CARG2->metatable
3096 | cbz TAB:CARG1, <2 // No metatable: done.
3097 | ldrb TMP1w, TAB:CARG1->nomm
3098 | tbnz TMP1w, #MM_newindex, <2 // 'no __newindex' flag set: done.
3099 | b ->vmeta_tsets
3100 |
3101 |5: // Follow hash chain.
3102 | mov NODE:CARG3, NODE:TMP3
3103 | cbnz NODE:TMP3, <1
3104 | // End of hash chain: key not found, add a new one.
3105 |
3106 | // But check for __newindex first.
3107 | ldr TAB:CARG1, TAB:CARG2->metatable
3108 | cbz TAB:CARG1, >6 // No metatable: continue.
3109 | ldrb TMP1w, TAB:CARG1->nomm
3110 | // 'no __newindex' flag NOT set: check.
3111 | tbz TMP1w, #MM_newindex, ->vmeta_tsets
3112 |6:
3113 | movn TMP1, #~LJ_TSTR
3114 | str PC, SAVE_PC
3115 | add TMP0, STR:RC, TMP1, lsl #47
3116 | str BASE, L->base
3117 | mov CARG1, L
3118 | str TMP0, TMPD
3119 | add CARG3, sp, TMPDofs
3120 | bl extern lj_tab_newkey // (lua_State *L, GCtab *t, TValue *k)
3121 | // Returns TValue *.
3122 | ldr BASE, L->base
3123 | ldr TMP0, [BASE, RA, lsl #3]
3124 | str TMP0, [CRET1]
3125 | b <3 // No 2nd write barrier needed.
3126 |
3127 |7: // Possible table write barrier for the value. Skip valiswhite check.
3128 | barrierback TAB:CARG2, TMP2w, TMP1
3129 | b <3
3130 break;
3131 case BC_TSETB:
3132 | decode_RB RB, INS
3133 | and RC, RC, #255
3134 | // RA = src, RB = table, RC = index
3135 | ldr CARG2, [BASE, RB, lsl #3]
3136 | checktab CARG2, ->vmeta_tsetb
3137 | ldr CARG3, TAB:CARG2->array
3138 | ldr CARG1w, TAB:CARG2->asize
3139 | add CARG3, CARG3, RC, lsl #3
3140 | cmp RCw, CARG1w // In array part?
3141 | bhs ->vmeta_tsetb
3142 | ldr TMP1, [CARG3]
3143 | ldr TMP0, [BASE, RA, lsl #3]
3144 | ldrb TMP2w, TAB:CARG2->marked
3145 | cmp TMP1, TISNIL // Previous value is nil?
3146 | beq >5
3147 |1:
3148 | str TMP0, [CARG3]
3149 | tbnz TMP2w, #2, >7 // isblack(table)
3150 |2:
3151 | ins_next
3152 |
3153 |5: // Check for __newindex if previous value is nil.
3154 | ldr TAB:CARG1, TAB:CARG2->metatable
3155 | cbz TAB:CARG1, <1 // No metatable: done.
3156 | ldrb TMP1w, TAB:CARG1->nomm
3157 | tbnz TMP1w, #MM_newindex, <1 // 'no __newindex' flag set: done.
3158 | b ->vmeta_tsetb
3159 |
3160 |7: // Possible table write barrier for the value. Skip valiswhite check.
3161 | barrierback TAB:CARG2, TMP2w, TMP1
3162 | b <2
3163 break;
3164 case BC_TSETR:
3165 | decode_RB RB, INS
3166 | and RC, RC, #255
3167 | // RA = src, RB = table, RC = key
3168 | ldr CARG2, [BASE, RB, lsl #3]
3169 | ldr TMP1, [BASE, RC, lsl #3]
3170 | and TAB:CARG2, CARG2, #LJ_GCVMASK
3171 | ldr CARG1, TAB:CARG2->array
3172 | ldrb TMP2w, TAB:CARG2->marked
3173 | ldr CARG4w, TAB:CARG2->asize
3174 | add CARG1, CARG1, TMP1, uxtw #3
3175 | tbnz TMP2w, #2, >7 // isblack(table)
3176 |2:
3177 | cmp TMP1w, CARG4w // In array part?
3178 | bhs ->vmeta_tsetr
3179 |->BC_TSETR_Z:
3180 | ldr TMP0, [BASE, RA, lsl #3]
3181 | str TMP0, [CARG1]
3182 | ins_next
3183 |
3184 |7: // Possible table write barrier for the value. Skip valiswhite check.
3185 | barrierback TAB:CARG2, TMP2w, TMP0
3186 | b <2
3187 break;
3188
3189 case BC_TSETM:
3190 | // RA = base (table at base-1), RC = num_const (start index)
3191 | add RA, BASE, RA, lsl #3
3192 |1:
3193 | ldr RBw, SAVE_MULTRES
3194 | ldr TAB:CARG2, [RA, #-8] // Guaranteed to be a table.
3195 | ldr TMP1, [KBASE, RC, lsl #3] // Integer constant is in lo-word.
3196 | sub RB, RB, #8
3197 | cbz RB, >4 // Nothing to copy?
3198 | and TAB:CARG2, CARG2, #LJ_GCVMASK
3199 | ldr CARG1w, TAB:CARG2->asize
3200 | add CARG3w, TMP1w, RBw, lsr #3
3201 | ldr CARG4, TAB:CARG2->array
3202 | cmp CARG3, CARG1
3203 | add RB, RA, RB
3204 | bhi >5
3205 | add TMP1, CARG4, TMP1w, uxtw #3
3206 | ldrb TMP2w, TAB:CARG2->marked
3207 |3: // Copy result slots to table.
3208 | ldr TMP0, [RA], #8
3209 | str TMP0, [TMP1], #8
3210 | cmp RA, RB
3211 | blo <3
3212 | tbnz TMP2w, #2, >7 // isblack(table)
3213 |4:
3214 | ins_next
3215 |
3216 |5: // Need to resize array part.
3217 | str BASE, L->base
3218 | mov CARG1, L
3219 | str PC, SAVE_PC
3220 | bl extern lj_tab_reasize // (lua_State *L, GCtab *t, int nasize)
3221 | // Must not reallocate the stack.
3222 | b <1
3223 |
3224 |7: // Possible table write barrier for any value. Skip valiswhite check.
3225 | barrierback TAB:CARG2, TMP2w, TMP1
3226 | b <4
3227 break;
3228
3229 /* -- Calls and vararg handling ----------------------------------------- */
3230
3231 case BC_CALLM:
3232 | // RA = base, (RB = nresults+1,) RC = extra_nargs
3233 | ldr TMP0w, SAVE_MULTRES
3234 | decode_RC8RD NARGS8:RC, RC
3235 | add NARGS8:RC, NARGS8:RC, TMP0
3236 | b ->BC_CALL_Z
3237 break;
3238 case BC_CALL:
3239 | decode_RC8RD NARGS8:RC, RC
3240 | // RA = base, (RB = nresults+1,) RC = (nargs+1)*8
3241 |->BC_CALL_Z:
3242 | mov RB, BASE // Save old BASE for vmeta_call.
3243 | add BASE, BASE, RA, lsl #3
3244 | ldr CARG3, [BASE]
3245 | sub NARGS8:RC, NARGS8:RC, #8
3246 | add BASE, BASE, #16
3247 | checkfunc CARG3, ->vmeta_call
3248 | ins_call
3249 break;
3250
3251 case BC_CALLMT:
3252 | // RA = base, (RB = 0,) RC = extra_nargs
3253 | ldr TMP0w, SAVE_MULTRES
3254 | add NARGS8:RC, TMP0, RC, lsl #3
3255 | b ->BC_CALLT1_Z
3256 break;
3257 case BC_CALLT:
3258 | lsl NARGS8:RC, RC, #3
3259 | // RA = base, (RB = 0,) RC = (nargs+1)*8
3260 |->BC_CALLT1_Z:
3261 | add RA, BASE, RA, lsl #3
3262 | ldr TMP1, [RA]
3263 | sub NARGS8:RC, NARGS8:RC, #8
3264 | add RA, RA, #16
3265 | checktp CARG3, TMP1, LJ_TFUNC, ->vmeta_callt
3266 | ldr PC, [BASE, FRAME_PC]
3267 |->BC_CALLT2_Z:
3268 | mov RB, #0
3269 | ldrb TMP2w, LFUNC:CARG3->ffid
3270 | tst PC, #FRAME_TYPE
3271 | bne >7
3272 |1:
3273 | str TMP1, [BASE, FRAME_FUNC] // Copy function down, but keep PC.
3274 | cbz NARGS8:RC, >3
3275 |2:
3276 | ldr TMP0, [RA, RB]
3277 | add TMP1, RB, #8
3278 | cmp TMP1, NARGS8:RC
3279 | str TMP0, [BASE, RB]
3280 | mov RB, TMP1
3281 | bne <2
3282 |3:
3283 | cmp TMP2, #1 // (> FF_C) Calling a fast function?
3284 | bhi >5
3285 |4:
3286 | ins_callt
3287 |
3288 |5: // Tailcall to a fast function with a Lua frame below.
3289 | ldrb RAw, [PC, #-4+OFS_RA]
3290 | sub CARG1, BASE, RA, lsl #3
3291 | ldr LFUNC:CARG1, [CARG1, #-32]
3292 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK
3293 | ldr CARG1, LFUNC:CARG1->pc
3294 | ldr KBASE, [CARG1, #PC2PROTO(k)]
3295 | b <4
3296 |
3297 |7: // Tailcall from a vararg function.
3298 | eor PC, PC, #FRAME_VARG
3299 | tst PC, #FRAME_TYPEP // Vararg frame below?
3300 | csel TMP2, RB, TMP2, ne // Clear ffid if no Lua function below.
3301 | bne <1
3302 | sub BASE, BASE, PC
3303 | ldr PC, [BASE, FRAME_PC]
3304 | tst PC, #FRAME_TYPE
3305 | csel TMP2, RB, TMP2, ne // Clear ffid if no Lua function below.
3306 | b <1
3307 break;
3308
3309 case BC_ITERC:
3310 | // RA = base, (RB = nresults+1, RC = nargs+1 (2+1))
3311 | add RA, BASE, RA, lsl #3
3312 | ldr CARG3, [RA, #-24]
3313 | mov RB, BASE // Save old BASE for vmeta_call.
3314 | ldp CARG1, CARG2, [RA, #-16]
3315 | add BASE, RA, #16
3316 | mov NARGS8:RC, #16 // Iterators get 2 arguments.
3317 | str CARG3, [RA] // Copy callable.
3318 | stp CARG1, CARG2, [RA, #16] // Copy state and control var.
3319 | checkfunc CARG3, ->vmeta_call
3320 | ins_call
3321 break;
3322
3323 case BC_ITERN:
3324 | // RA = base, (RB = nresults+1, RC = nargs+1 (2+1))
3325 |.if JIT
3326 | // NYI: add hotloop, record BC_ITERN.
3327 |.endif
3328 | add RA, BASE, RA, lsl #3
3329 | ldr TAB:RB, [RA, #-16]
3330 | ldrh TMP3w, [PC, # OFS_RD]
3331 | ldr CARG1w, [RA, #-8+LO] // Get index from control var.
3332 | add PC, PC, #4
3333 | add TMP3, PC, TMP3, lsl #2
3334 | and TAB:RB, RB, #LJ_GCVMASK
3335 | sub TMP3, TMP3, #0x20000
3336 | ldr TMP1w, TAB:RB->asize
3337 | ldr CARG2, TAB:RB->array
3338 |1: // Traverse array part.
3339 | subs RC, CARG1, TMP1
3340 | add CARG3, CARG2, CARG1, lsl #3
3341 | bhs >5 // Index points after array part?
3342 | ldr TMP0, [CARG3]
3343 | cmp TMP0, TISNIL
3344 | cinc CARG1, CARG1, eq // Skip holes in array part.
3345 | beq <1
3346 | add CARG1, CARG1, TISNUM
3347 | stp CARG1, TMP0, [RA]
3348 | add CARG1, CARG1, #1
3349 |3:
3350 | str CARG1w, [RA, #-8+LO] // Update control var.
3351 | mov PC, TMP3
3352 |4:
3353 | ins_next
3354 |
3355 |5: // Traverse hash part.
3356 | ldr TMP2w, TAB:RB->hmask
3357 | ldr NODE:RB, TAB:RB->node
3358 |6:
3359 | add CARG1, RC, RC, lsl #1
3360 | cmp RC, TMP2 // End of iteration? Branch to ITERN+1.
3361 | add NODE:CARG3, NODE:RB, CARG1, lsl #3 // node = tab->node + idx*3*8
3362 | bhi <4
3363 | ldp TMP0, CARG1, NODE:CARG3->val
3364 | cmp TMP0, TISNIL
3365 | add RC, RC, #1
3366 | beq <6 // Skip holes in hash part.
3367 | stp CARG1, TMP0, [RA]
3368 | add CARG1, RC, TMP1
3369 | b <3
3370 break;
3371
3372 case BC_ISNEXT:
3373 | // RA = base, RC = target (points to ITERN)
3374 | add RA, BASE, RA, lsl #3
3375 | ldr CFUNC:CARG1, [RA, #-24]
3376 | add RC, PC, RC, lsl #2
3377 | ldp TAB:CARG3, CARG4, [RA, #-16]
3378 | sub RC, RC, #0x20000
3379 | checkfunc CFUNC:CARG1, >5
3380 | asr TMP0, TAB:CARG3, #47
3381 | ldrb TMP1w, CFUNC:CARG1->ffid
3382 | cmn TMP0, #-LJ_TTAB
3383 | ccmp CARG4, TISNIL, #0, eq
3384 | ccmp TMP1w, #FF_next_N, #0, eq
3385 | bne >5
3386 | mov TMP0w, #0xfffe7fff
3387 | lsl TMP0, TMP0, #32
3388 | str TMP0, [RA, #-8] // Initialize control var.
3389 |1:
3390 | mov PC, RC
3391 | ins_next
3392 |
3393 |5: // Despecialize bytecode if any of the checks fail.
3394 | mov TMP0, #BC_JMP
3395 | mov TMP1, #BC_ITERC
3396 | strb TMP0w, [PC, #-4+OFS_OP]
3397 | strb TMP1w, [RC, # OFS_OP]
3398 | b <1
3399 break;
3400
3401 case BC_VARG:
3402 | decode_RB RB, INS
3403 | and RC, RC, #255
3404 | // RA = base, RB = (nresults+1), RC = numparams
3405 | ldr TMP1, [BASE, FRAME_PC]
3406 | add RC, BASE, RC, lsl #3
3407 | add RA, BASE, RA, lsl #3
3408 | add RC, RC, #FRAME_VARG
3409 | add TMP2, RA, RB, lsl #3
3410 | sub RC, RC, TMP1 // RC = vbase
3411 | // Note: RC may now be even _above_ BASE if nargs was < numparams.
3412 | sub TMP3, BASE, #16 // TMP3 = vtop
3413 | cbz RB, >5
3414 | sub TMP2, TMP2, #16
3415 |1: // Copy vararg slots to destination slots.
3416 | cmp RC, TMP3
3417 | ldr TMP0, [RC], #8
3418 | csel TMP0, TMP0, TISNIL, lo
3419 | cmp RA, TMP2
3420 | str TMP0, [RA], #8
3421 | blo <1
3422 |2:
3423 | ins_next
3424 |
3425 |5: // Copy all varargs.
3426 | ldr TMP0, L->maxstack
3427 | subs TMP2, TMP3, RC
3428 | csel RB, xzr, TMP2, le // MULTRES = (max(vtop-vbase,0)+1)*8
3429 | add RB, RB, #8
3430 | add TMP1, RA, TMP2
3431 | str RBw, SAVE_MULTRES
3432 | ble <2 // Nothing to copy.
3433 | cmp TMP1, TMP0
3434 | bhi >7
3435 |6:
3436 | ldr TMP0, [RC], #8
3437 | str TMP0, [RA], #8
3438 | cmp RC, TMP3
3439 | blo <6
3440 | b <2
3441 |
3442 |7: // Grow stack for varargs.
3443 | lsr CARG2, TMP2, #3
3444 | stp BASE, RA, L->base
3445 | mov CARG1, L
3446 | sub RC, RC, BASE // Need delta, because BASE may change.
3447 | str PC, SAVE_PC
3448 | bl extern lj_state_growstack // (lua_State *L, int n)
3449 | ldp BASE, RA, L->base
3450 | add RC, BASE, RC
3451 | sub TMP3, BASE, #16
3452 | b <6
3453 break;
3454
3455 /* -- Returns ----------------------------------------------------------- */
3456
3457 case BC_RETM:
3458 | // RA = results, RC = extra results
3459 | ldr TMP0w, SAVE_MULTRES
3460 | ldr PC, [BASE, FRAME_PC]
3461 | add RA, BASE, RA, lsl #3
3462 | add RC, TMP0, RC, lsl #3
3463 | b ->BC_RETM_Z
3464 break;
3465
3466 case BC_RET:
3467 | // RA = results, RC = nresults+1
3468 | ldr PC, [BASE, FRAME_PC]
3469 | lsl RC, RC, #3
3470 | add RA, BASE, RA, lsl #3
3471 |->BC_RETM_Z:
3472 | str RCw, SAVE_MULTRES
3473 |1:
3474 | ands CARG1, PC, #FRAME_TYPE
3475 | eor CARG2, PC, #FRAME_VARG
3476 | bne ->BC_RETV2_Z
3477 |
3478 |->BC_RET_Z:
3479 | // BASE = base, RA = resultptr, RC = (nresults+1)*8, PC = return
3480 | ldr INSw, [PC, #-4]
3481 | subs TMP1, RC, #8
3482 | sub CARG3, BASE, #16
3483 | beq >3
3484 |2:
3485 | ldr TMP0, [RA], #8
3486 | add BASE, BASE, #8
3487 | sub TMP1, TMP1, #8
3488 | str TMP0, [BASE, #-24]
3489 | cbnz TMP1, <2
3490 |3:
3491 | decode_RA RA, INS
3492 | sub CARG4, CARG3, RA, lsl #3
3493 | decode_RB RB, INS
3494 | ldr LFUNC:CARG1, [CARG4, FRAME_FUNC]
3495 |5:
3496 | cmp RC, RB, lsl #3 // More results expected?
3497 | blo >6
3498 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK
3499 | mov BASE, CARG4
3500 | ldr CARG2, LFUNC:CARG1->pc
3501 | ldr KBASE, [CARG2, #PC2PROTO(k)]
3502 | ins_next
3503 |
3504 |6: // Fill up results with nil.
3505 | add BASE, BASE, #8
3506 | add RC, RC, #8
3507 | str TISNIL, [BASE, #-24]
3508 | b <5
3509 |
3510 |->BC_RETV1_Z: // Non-standard return case.
3511 | add RA, BASE, RA, lsl #3
3512 |->BC_RETV2_Z:
3513 | tst CARG2, #FRAME_TYPEP
3514 | bne ->vm_return
3515 | // Return from vararg function: relocate BASE down.
3516 | sub BASE, BASE, CARG2
3517 | ldr PC, [BASE, FRAME_PC]
3518 | b <1
3519 break;
3520
3521 case BC_RET0: case BC_RET1:
3522 | // RA = results, RC = nresults+1
3523 | ldr PC, [BASE, FRAME_PC]
3524 | lsl RC, RC, #3
3525 | str RCw, SAVE_MULTRES
3526 | ands CARG1, PC, #FRAME_TYPE
3527 | eor CARG2, PC, #FRAME_VARG
3528 | bne ->BC_RETV1_Z
3529 | ldr INSw, [PC, #-4]
3530 if (op == BC_RET1) {
3531 | ldr TMP0, [BASE, RA, lsl #3]
3532 }
3533 | sub CARG4, BASE, #16
3534 | decode_RA RA, INS
3535 | sub BASE, CARG4, RA, lsl #3
3536 if (op == BC_RET1) {
3537 | str TMP0, [CARG4], #8
3538 }
3539 | decode_RB RB, INS
3540 | ldr LFUNC:CARG1, [BASE, FRAME_FUNC]
3541 |5:
3542 | cmp RC, RB, lsl #3
3543 | blo >6
3544 | and LFUNC:CARG1, CARG1, #LJ_GCVMASK
3545 | ldr CARG2, LFUNC:CARG1->pc
3546 | ldr KBASE, [CARG2, #PC2PROTO(k)]
3547 | ins_next
3548 |
3549 |6: // Fill up results with nil.
3550 | add RC, RC, #8
3551 | str TISNIL, [CARG4], #8
3552 | b <5
3553 break;
3554
3555 /* -- Loops and branches ------------------------------------------------ */
3556
3557 |.define FOR_IDX, [RA]; .define FOR_TIDX, [RA, #4]
3558 |.define FOR_STOP, [RA, #8]; .define FOR_TSTOP, [RA, #12]
3559 |.define FOR_STEP, [RA, #16]; .define FOR_TSTEP, [RA, #20]
3560 |.define FOR_EXT, [RA, #24]; .define FOR_TEXT, [RA, #28]
3561
3562 case BC_FORL:
3563 |.if JIT
3564 | hotloop
3565 |.endif
3566 | // Fall through. Assumes BC_IFORL follows.
3567 break;
3568
3569 case BC_JFORI:
3570 case BC_JFORL:
3571#if !LJ_HASJIT
3572 break;
3573#endif
3574 case BC_FORI:
3575 case BC_IFORL:
3576 | // RA = base, RC = target (after end of loop or start of loop)
3577 vk = (op == BC_IFORL || op == BC_JFORL);
3578 | add RA, BASE, RA, lsl #3
3579 | ldp CARG1, CARG2, FOR_IDX // CARG1 = IDX, CARG2 = STOP
3580 | ldr CARG3, FOR_STEP // CARG3 = STEP
3581 if (op != BC_JFORL) {
3582 | add RC, PC, RC, lsl #2
3583 | sub RC, RC, #0x20000
3584 }
3585 | checkint CARG1, >5
3586 if (!vk) {
3587 | checkint CARG2, ->vmeta_for
3588 | checkint CARG3, ->vmeta_for
3589 | tbnz CARG3w, #31, >4
3590 | cmp CARG1w, CARG2w
3591 } else {
3592 | adds CARG1w, CARG1w, CARG3w
3593 | bvs >2
3594 | add TMP0, CARG1, TISNUM
3595 | tbnz CARG3w, #31, >4
3596 | cmp CARG1w, CARG2w
3597 }
3598 |1:
3599 if (op == BC_FORI) {
3600 | csel PC, RC, PC, gt
3601 } else if (op == BC_JFORI) {
3602 | mov PC, RC
3603 | ldrh RCw, [RC, #-4+OFS_RD]
3604 } else if (op == BC_IFORL) {
3605 | csel PC, RC, PC, le
3606 }
3607 if (vk) {
3608 | str TMP0, FOR_IDX
3609 | str TMP0, FOR_EXT
3610 } else {
3611 | str CARG1, FOR_EXT
3612 }
3613 if (op == BC_JFORI || op == BC_JFORL) {
3614 | ble =>BC_JLOOP
3615 }
3616 |2:
3617 | ins_next
3618 |
3619 |4: // Invert check for negative step.
3620 | cmp CARG2w, CARG1w
3621 | b <1
3622 |
3623 |5: // FP loop.
3624 | ldp d0, d1, FOR_IDX
3625 | blo ->vmeta_for
3626 if (!vk) {
3627 | checknum CARG2, ->vmeta_for
3628 | checknum CARG3, ->vmeta_for
3629 | str d0, FOR_EXT
3630 } else {
3631 | ldr d2, FOR_STEP
3632 | fadd d0, d0, d2
3633 }
3634 | tbnz CARG3, #63, >7
3635 | fcmp d0, d1
3636 |6:
3637 if (vk) {
3638 | str d0, FOR_IDX
3639 | str d0, FOR_EXT
3640 }
3641 if (op == BC_FORI) {
3642 | csel PC, RC, PC, hi
3643 } else if (op == BC_JFORI) {
3644 | ldrh RCw, [RC, #-4+OFS_RD]
3645 | bls =>BC_JLOOP
3646 } else if (op == BC_IFORL) {
3647 | csel PC, RC, PC, ls
3648 } else {
3649 | bls =>BC_JLOOP
3650 }
3651 | b <2
3652 |
3653 |7: // Invert check for negative step.
3654 | fcmp d1, d0
3655 | b <6
3656 break;
3657
3658 case BC_ITERL:
3659 |.if JIT
3660 | hotloop
3661 |.endif
3662 | // Fall through. Assumes BC_IITERL follows.
3663 break;
3664
3665 case BC_JITERL:
3666#if !LJ_HASJIT
3667 break;
3668#endif
3669 case BC_IITERL:
3670 | // RA = base, RC = target
3671 | ldr CARG1, [BASE, RA, lsl #3]
3672 | add TMP1, BASE, RA, lsl #3
3673 | cmp CARG1, TISNIL
3674 | beq >1 // Stop if iterator returned nil.
3675 if (op == BC_JITERL) {
3676 | str CARG1, [TMP1, #-8]
3677 | b =>BC_JLOOP
3678 } else {
3679 | add TMP0, PC, RC, lsl #2 // Otherwise save control var + branch.
3680 | sub PC, TMP0, #0x20000
3681 | str CARG1, [TMP1, #-8]
3682 }
3683 |1:
3684 | ins_next
3685 break;
3686
3687 case BC_LOOP:
3688 | // RA = base, RC = target (loop extent)
3689 | // Note: RA/RC is only used by trace recorder to determine scope/extent
3690 | // This opcode does NOT jump, it's only purpose is to detect a hot loop.
3691 |.if JIT
3692 | hotloop
3693 |.endif
3694 | // Fall through. Assumes BC_ILOOP follows.
3695 break;
3696
3697 case BC_ILOOP:
3698 | // RA = base, RC = target (loop extent)
3699 | ins_next
3700 break;
3701
3702 case BC_JLOOP:
3703 |.if JIT
3704 | // RA = base (ignored), RC = traceno
3705 | ldr CARG1, [GL, #GL_J(trace)]
3706 | mov CARG2w, #0 // Traces on ARM64 don't store the trace #, so use 0.
3707 | ldr TRACE:RC, [CARG1, RC, lsl #3]
3708 | st_vmstate CARG2w
3709 | ldr RA, TRACE:RC->mcode
3710 | str BASE, GL->jit_base
3711 | str L, GL->tmpbuf.L
3712 | sub sp, sp, #16 // See SPS_FIXED. Avoids sp adjust in every root trace.
3713 | br RA
3714 |.endif
3715 break;
3716
3717 case BC_JMP:
3718 | // RA = base (only used by trace recorder), RC = target
3719 | add RC, PC, RC, lsl #2
3720 | sub PC, RC, #0x20000
3721 | ins_next
3722 break;
3723
3724 /* -- Function headers -------------------------------------------------- */
3725
3726 case BC_FUNCF:
3727 |.if JIT
3728 | hotcall
3729 |.endif
3730 case BC_FUNCV: /* NYI: compiled vararg functions. */
3731 | // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow.
3732 break;
3733
3734 case BC_JFUNCF:
3735#if !LJ_HASJIT
3736 break;
3737#endif
3738 case BC_IFUNCF:
3739 | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8
3740 | ldr CARG1, L->maxstack
3741 | ldrb TMP1w, [PC, #-4+PC2PROTO(numparams)]
3742 | ldr KBASE, [PC, #-4+PC2PROTO(k)]
3743 | cmp RA, CARG1
3744 | bhi ->vm_growstack_l
3745 |2:
3746 | cmp NARGS8:RC, TMP1, lsl #3 // Check for missing parameters.
3747 | blo >3
3748 if (op == BC_JFUNCF) {
3749 | decode_RD RC, INS
3750 | b =>BC_JLOOP
3751 } else {
3752 | ins_next
3753 }
3754 |
3755 |3: // Clear missing parameters.
3756 | str TISNIL, [BASE, NARGS8:RC]
3757 | add NARGS8:RC, NARGS8:RC, #8
3758 | b <2
3759 break;
3760
3761 case BC_JFUNCV:
3762#if !LJ_HASJIT
3763 break;
3764#endif
3765 | NYI // NYI: compiled vararg functions
3766 break; /* NYI: compiled vararg functions. */
3767
3768 case BC_IFUNCV:
3769 | // BASE = new base, RA = BASE+framesize*8, CARG3 = LFUNC, RC = nargs*8
3770 | ldr CARG1, L->maxstack
3771 | movn TMP0, #~LJ_TFUNC
3772 | add TMP2, BASE, RC
3773 | add LFUNC:CARG3, CARG3, TMP0, lsl #47
3774 | add RA, RA, RC
3775 | add TMP0, RC, #16+FRAME_VARG
3776 | str LFUNC:CARG3, [TMP2], #8 // Store (tagged) copy of LFUNC.
3777 | ldr KBASE, [PC, #-4+PC2PROTO(k)]
3778 | cmp RA, CARG1
3779 | str TMP0, [TMP2], #8 // Store delta + FRAME_VARG.
3780 | bhs ->vm_growstack_l
3781 | sub RC, TMP2, #16
3782 | ldrb TMP1w, [PC, #-4+PC2PROTO(numparams)]
3783 | mov RA, BASE
3784 | mov BASE, TMP2
3785 | cbz TMP1, >2
3786 |1:
3787 | cmp RA, RC // Less args than parameters?
3788 | bhs >3
3789 | ldr TMP0, [RA]
3790 | sub TMP1, TMP1, #1
3791 | str TISNIL, [RA], #8 // Clear old fixarg slot (help the GC).
3792 | str TMP0, [TMP2], #8
3793 | cbnz TMP1, <1
3794 |2:
3795 | ins_next
3796 |
3797 |3:
3798 | sub TMP1, TMP1, #1
3799 | str TISNIL, [TMP2], #8
3800 | cbz TMP1, <2
3801 | b <3
3802 break;
3803
3804 case BC_FUNCC:
3805 case BC_FUNCCW:
3806 | // BASE = new base, RA = BASE+framesize*8, CARG3 = CFUNC, RC = nargs*8
3807 if (op == BC_FUNCC) {
3808 | ldr CARG4, CFUNC:CARG3->f
3809 } else {
3810 | ldr CARG4, GL->wrapf
3811 }
3812 | add CARG2, RA, NARGS8:RC
3813 | ldr CARG1, L->maxstack
3814 | add RC, BASE, NARGS8:RC
3815 | cmp CARG2, CARG1
3816 | stp BASE, RC, L->base
3817 if (op == BC_FUNCCW) {
3818 | ldr CARG2, CFUNC:CARG3->f
3819 }
3820 | mv_vmstate TMP0w, C
3821 | mov CARG1, L
3822 | bhi ->vm_growstack_c // Need to grow stack.
3823 | st_vmstate TMP0w
3824 | blr CARG4 // (lua_State *L [, lua_CFunction f])
3825 | // Returns nresults.
3826 | ldp BASE, TMP1, L->base
3827 | str L, GL->cur_L
3828 | sbfiz RC, CRET1, #3, #32
3829 | st_vmstate ST_INTERP
3830 | ldr PC, [BASE, FRAME_PC]
3831 | sub RA, TMP1, RC // RA = L->top - nresults*8
3832 | b ->vm_returnc
3833 break;
3834
3835 /* ---------------------------------------------------------------------- */
3836
3837 default:
3838 fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]);
3839 exit(2);
3840 break;
3841 }
3842}
3843
3844static int build_backend(BuildCtx *ctx)
3845{
3846 int op;
3847
3848 dasm_growpc(Dst, BC__MAX);
3849
3850 build_subroutines(ctx);
3851
3852 |.code_op
3853 for (op = 0; op < BC__MAX; op++)
3854 build_ins(ctx, (BCOp)op, op);
3855
3856 return BC__MAX;
3857}
3858
3859/* Emit pseudo frame-info for all assembler functions. */
3860static void emit_asm_debug(BuildCtx *ctx)
3861{
3862 int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code);
3863 int i, cf = CFRAME_SIZE >> 3;
3864 switch (ctx->mode) {
3865 case BUILD_elfasm:
3866 fprintf(ctx->fp, "\t.section .debug_frame,\"\",%%progbits\n");
3867 fprintf(ctx->fp,
3868 ".Lframe0:\n"
3869 "\t.long .LECIE0-.LSCIE0\n"
3870 ".LSCIE0:\n"
3871 "\t.long 0xffffffff\n"
3872 "\t.byte 0x1\n"
3873 "\t.string \"\"\n"
3874 "\t.uleb128 0x1\n"
3875 "\t.sleb128 -8\n"
3876 "\t.byte 30\n" /* Return address is in lr. */
3877 "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */
3878 "\t.align 3\n"
3879 ".LECIE0:\n\n");
3880 fprintf(ctx->fp,
3881 ".LSFDE0:\n"
3882 "\t.long .LEFDE0-.LASFDE0\n"
3883 ".LASFDE0:\n"
3884 "\t.long .Lframe0\n"
3885 "\t.quad .Lbegin\n"
3886 "\t.quad %d\n"
3887 "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */
3888 "\t.byte 0x9d\n\t.uleb128 %d\n" /* offset fp */
3889 "\t.byte 0x9e\n\t.uleb128 %d\n", /* offset lr */
3890 fcofs, CFRAME_SIZE, cf, cf-1);
3891 for (i = 19; i <= 28; i++) /* offset x19-x28 */
3892 fprintf(ctx->fp, "\t.byte 0x%x\n\t.uleb128 %d\n", 0x80+i, cf-i+17);
3893 for (i = 8; i <= 15; i++) /* offset d8-d15 */
3894 fprintf(ctx->fp, "\t.byte 5\n\t.uleb128 0x%x\n\t.uleb128 %d\n",
3895 64+i, cf-i-4);
3896 fprintf(ctx->fp,
3897 "\t.align 3\n"
3898 ".LEFDE0:\n\n");
3899#if LJ_HASFFI
3900 fprintf(ctx->fp,
3901 ".LSFDE1:\n"
3902 "\t.long .LEFDE1-.LASFDE1\n"
3903 ".LASFDE1:\n"
3904 "\t.long .Lframe0\n"
3905 "\t.quad lj_vm_ffi_call\n"
3906 "\t.quad %d\n"
3907 "\t.byte 0xe\n\t.uleb128 32\n" /* def_cfa_offset */
3908 "\t.byte 0x9d\n\t.uleb128 4\n" /* offset fp */
3909 "\t.byte 0x9e\n\t.uleb128 3\n" /* offset lr */
3910 "\t.byte 0x93\n\t.uleb128 2\n" /* offset x19 */
3911 "\t.align 3\n"
3912 ".LEFDE1:\n\n", (int)ctx->codesz - fcofs);
3913#endif
3914 fprintf(ctx->fp, "\t.section .eh_frame,\"a\",%%progbits\n");
3915 fprintf(ctx->fp,
3916 ".Lframe1:\n"
3917 "\t.long .LECIE1-.LSCIE1\n"
3918 ".LSCIE1:\n"
3919 "\t.long 0\n"
3920 "\t.byte 0x1\n"
3921 "\t.string \"zPR\"\n"
3922 "\t.uleb128 0x1\n"
3923 "\t.sleb128 -8\n"
3924 "\t.byte 30\n" /* Return address is in lr. */
3925 "\t.uleb128 6\n" /* augmentation length */
3926 "\t.byte 0x1b\n" /* pcrel|sdata4 */
3927 "\t.long lj_err_unwind_dwarf-.\n"
3928 "\t.byte 0x1b\n" /* pcrel|sdata4 */
3929 "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */
3930 "\t.align 3\n"
3931 ".LECIE1:\n\n");
3932 fprintf(ctx->fp,
3933 ".LSFDE2:\n"
3934 "\t.long .LEFDE2-.LASFDE2\n"
3935 ".LASFDE2:\n"
3936 "\t.long .LASFDE2-.Lframe1\n"
3937 "\t.long .Lbegin-.\n"
3938 "\t.long %d\n"
3939 "\t.uleb128 0\n" /* augmentation length */
3940 "\t.byte 0xe\n\t.uleb128 %d\n" /* def_cfa_offset */
3941 "\t.byte 0x9d\n\t.uleb128 %d\n" /* offset fp */
3942 "\t.byte 0x9e\n\t.uleb128 %d\n", /* offset lr */
3943 fcofs, CFRAME_SIZE, cf, cf-1);
3944 for (i = 19; i <= 28; i++) /* offset x19-x28 */
3945 fprintf(ctx->fp, "\t.byte 0x%x\n\t.uleb128 %d\n", 0x80+i, cf-i+17);
3946 for (i = 8; i <= 15; i++) /* offset d8-d15 */
3947 fprintf(ctx->fp, "\t.byte 5\n\t.uleb128 0x%x\n\t.uleb128 %d\n",
3948 64+i, cf-i-4);
3949 fprintf(ctx->fp,
3950 "\t.align 3\n"
3951 ".LEFDE2:\n\n");
3952#if LJ_HASFFI
3953 fprintf(ctx->fp,
3954 ".Lframe2:\n"
3955 "\t.long .LECIE2-.LSCIE2\n"
3956 ".LSCIE2:\n"
3957 "\t.long 0\n"
3958 "\t.byte 0x1\n"
3959 "\t.string \"zR\"\n"
3960 "\t.uleb128 0x1\n"
3961 "\t.sleb128 -8\n"
3962 "\t.byte 30\n" /* Return address is in lr. */
3963 "\t.uleb128 1\n" /* augmentation length */
3964 "\t.byte 0x1b\n" /* pcrel|sdata4 */
3965 "\t.byte 0xc\n\t.uleb128 31\n\t.uleb128 0\n" /* def_cfa sp */
3966 "\t.align 3\n"
3967 ".LECIE2:\n\n");
3968 fprintf(ctx->fp,
3969 ".LSFDE3:\n"
3970 "\t.long .LEFDE3-.LASFDE3\n"
3971 ".LASFDE3:\n"
3972 "\t.long .LASFDE3-.Lframe2\n"
3973 "\t.long lj_vm_ffi_call-.\n"
3974 "\t.long %d\n"
3975 "\t.uleb128 0\n" /* augmentation length */
3976 "\t.byte 0xe\n\t.uleb128 32\n" /* def_cfa_offset */
3977 "\t.byte 0x9d\n\t.uleb128 4\n" /* offset fp */
3978 "\t.byte 0x9e\n\t.uleb128 3\n" /* offset lr */
3979 "\t.byte 0x93\n\t.uleb128 2\n" /* offset x19 */
3980 "\t.align 3\n"
3981 ".LEFDE3:\n\n", (int)ctx->codesz - fcofs);
3982#endif
3983 break;
3984 default:
3985 break;
3986 }
3987}
3988