]> git.ipfire.org Git - thirdparty/LuaJIT.git/commitdiff
Refactor string.reverse(), string.lower(), string.upper().
authorMike Pall <mike>
Thu, 25 Apr 2013 22:31:10 +0000 (00:31 +0200)
committerMike Pall <mike>
Thu, 25 Apr 2013 22:31:10 +0000 (00:31 +0200)
src/Makefile.dep
src/lib_string.c
src/lj_buf.c
src/lj_buf.h
src/lj_dispatch.c
src/lj_dispatch.h
src/vm_arm.dasc
src/vm_mips.dasc
src/vm_ppc.dasc
src/vm_x86.dasc

index c501db44b6ee3e91fbf5133788c12537f645c1e6..a29b396a18664f5b87462cd3a63cf305b22af286 100644 (file)
@@ -96,10 +96,10 @@ lj_debug.o: lj_debug.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
  lj_err.h lj_errmsg.h lj_debug.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \
  lj_state.h lj_frame.h lj_bc.h lj_jit.h lj_ir.h
 lj_dispatch.o: lj_dispatch.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
- lj_err.h lj_errmsg.h lj_func.h lj_str.h lj_tab.h lj_meta.h lj_debug.h \
- lj_state.h lj_frame.h lj_bc.h lj_ff.h lj_ffdef.h lj_jit.h lj_ir.h \
- lj_ccallback.h lj_ctype.h lj_gc.h lj_trace.h lj_dispatch.h lj_traceerr.h \
- lj_vm.h luajit.h
+ lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_func.h lj_tab.h \
+ lj_meta.h lj_debug.h lj_state.h lj_frame.h lj_bc.h lj_ff.h lj_ffdef.h \
+ lj_jit.h lj_ir.h lj_ccallback.h lj_ctype.h lj_trace.h lj_dispatch.h \
+ lj_traceerr.h lj_vm.h luajit.h
 lj_err.o: lj_err.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_err.h \
  lj_errmsg.h lj_debug.h lj_str.h lj_func.h lj_state.h lj_frame.h lj_bc.h \
  lj_ff.h lj_ffdef.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h \
index 27e0d594fcc05fa42b0db4700260cdfb13c0d6e1..c8243d6c847cc92b685a5acd7c0786ed65c4d545 100644 (file)
@@ -135,8 +135,7 @@ LJLIB_ASM(string_rep)
 
 LJLIB_ASM(string_reverse)
 {
-  GCstr *s = lj_lib_checkstr(L, 1);
-  lj_buf_tmp(L, s->len);
+  lj_lib_checkstr(L, 1);
   return FFH_RETRY;
 }
 LJLIB_ASM_(string_lower)
index 675256947476e115c8ac6d0eeaa31998086e69b6..32ed52b9e54d59512641108847fcb084e46b4c10 100644 (file)
@@ -34,7 +34,7 @@ LJ_NOINLINE void LJ_FASTCALL lj_buf_grow(SBuf *sb, char *en)
 char * LJ_FASTCALL lj_buf_tmp(lua_State *L, MSize sz)
 {
   SBuf *sb = &G(L)->tmpbuf;
-  setmref(sb->L, L);
+  setsbufL(sb, L);
   return lj_buf_need(sb, sz);
 }
 
@@ -95,12 +95,59 @@ SBuf * LJ_FASTCALL lj_buf_putnum(SBuf *sb, cTValue *o)
   setsbufP(sb, lj_str_bufnum(lj_buf_more(sb, LJ_STR_NUMBUF), o));
   return sb;
 }
+#endif
+
+SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s)
+{
+  MSize len = s->len;
+  char *p = lj_buf_more(sb, len), *e = p+len;
+  const char *q = strdata(s)+len-1;
+  while (p < e)
+    *p++ = *q--;
+  setsbufP(sb, p);
+  return sb;
+}
+
+SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s)
+{
+  MSize len = s->len;
+  char *p = lj_buf_more(sb, len), *e = p+len;
+  const char *q = strdata(s);
+  for (; p < e; p++, q++) {
+    uint32_t c = *(unsigned char *)q;
+#if LJ_TARGET_PPC
+    *p = c + ((c >= 'A' && c <= 'Z') << 5);
+#else
+    if (c >= 'A' && c <= 'Z') c += 0x20;
+    *p = c;
+#endif
+  }
+  setsbufP(sb, p);
+  return sb;
+}
+
+SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s)
+{
+  MSize len = s->len;
+  char *p = lj_buf_more(sb, len), *e = p+len;
+  const char *q = strdata(s);
+  for (; p < e; p++, q++) {
+    uint32_t c = *(unsigned char *)q;
+#if LJ_TARGET_PPC
+    *p = c - ((c >= 'a' && c <= 'z') << 5);
+#else
+    if (c >= 'a' && c <= 'z') c -= 0x20;
+    *p = c;
+#endif
+  }
+  setsbufP(sb, p);
+  return sb;
+}
 
 GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb)
 {
   return lj_str_new(sbufL(sb), sbufB(sb), sbuflen(sb));
 }
-#endif
 
 uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp)
 {
index 426ec7206891871683740882ab313517c0493fb9..98bcad20726ba77b59c07151ae64eaca8645ffce 100644 (file)
@@ -31,8 +31,11 @@ LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s);
 LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c);
 LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putint(SBuf *sb, int32_t k);
 LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putnum(SBuf *sb, cTValue *o);
-LJ_FUNC GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb);
 #endif
+LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s);
+LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s);
+LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s);
+LJ_FUNCA GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb);
 LJ_FUNC uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp);
 LJ_FUNC char * LJ_FASTCALL lj_buf_wuleb128(char *p, uint32_t v);
 
index d57f1a6f92f5ea2e28c9ab0f338968050e1e6954..c144afceca7a4ff20c14dd33093aae8b53850c9e 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "lj_obj.h"
 #include "lj_err.h"
+#include "lj_buf.h"
 #include "lj_func.h"
 #include "lj_str.h"
 #include "lj_tab.h"
index a03804af1551b566dc507a5d102e0798432242eb..1368594a17a33d523218a738cbe58518ff0a0897 100644 (file)
@@ -37,7 +37,8 @@
   _(lj_meta_tset) _(lj_state_growstack) _(lj_str_fromnum) _(lj_str_fromnumber) \
   _(lj_str_new) _(lj_tab_dup) _(lj_tab_get) _(lj_tab_getinth) _(lj_tab_len) \
   _(lj_tab_new) _(lj_tab_newkey) _(lj_tab_next) _(lj_tab_reasize) \
-  _(lj_tab_setinth) JITGOTDEF(_) FFIGOTDEF(_)
+  _(lj_tab_setinth) _(lj_buf_putstr_reverse) _(lj_buf_putstr_lower) \
+  _(lj_buf_putstr_upper) _(lj_buf_tostr) JITGOTDEF(_) FFIGOTDEF(_)
 
 enum {
 #define GOTENUM(name) LJ_GOT_##name,
index 4579b2630cc276a95a4c2b5c4343de71d1af023b..5a15c409b8080cbded4ba0f33403f31a9bf5c876 100644 (file)
@@ -99,6 +99,7 @@
 |.type NODE,           Node
 |.type NARGS8,         int
 |.type TRACE,          GCtrace
+|.type SBUF,           SBuf
 |
 |//-----------------------------------------------------------------------
 |
@@ -1743,6 +1744,7 @@ static void build_subroutines(BuildCtx *ctx)
   |  mov CARG1, L
   |   str PC, SAVE_PC
   |  bl extern lj_str_new              // (lua_State *L, char *str, size_t l)
+  |->fff_resstr:
   |  // Returns GCstr *.
   |  ldr BASE, L->base
   |   mvn CARG2, #~LJ_TSTR
@@ -1813,56 +1815,28 @@ static void build_subroutines(BuildCtx *ctx)
   |  bge <1
   |  b ->fff_newstr
   |
-  |.ffunc string_reverse
+  |.macro ffstring_op, name
+  |  .ffunc string_ .. name
   |  ffgccheck
-  |  ldrd CARG12, [BASE]
-  |   cmp NARGS8:RC, #8
-  |   blo ->fff_fallback
-  |  checkstr CARG2, ->fff_fallback
-  |  ldr CARG3, STR:CARG1->len
-  |   ldr CARG2, [DISPATCH, #DISPATCH_GL(tmpbuf.b)]
-  |    ldr RB, [DISPATCH, #DISPATCH_GL(tmpbuf.e)]
-  |  mov CARG4, CARG3
-  |  add CARG1, STR:CARG1, #sizeof(GCstr)
-  |   add INS, CARG2, CARG3
-  |   cmp RB, INS
-  |   blo ->fff_fallback
-  |1:  // Reverse string copy.
-  |  ldrb RB, [CARG1], #1
-  |   subs CARG4, CARG4, #1
-  |   blt ->fff_newstr
-  |  strb RB, [CARG2, CARG4]
-  |  b <1
-  |
-  |.macro ffstring_case, name, lo
-  |  .ffunc name
-  |  ffgccheck
-  |  ldrd CARG12, [BASE]
+  |  ldr CARG3, [BASE, #4]
   |   cmp NARGS8:RC, #8
+  |  ldr STR:CARG2, [BASE]
   |   blo ->fff_fallback
-  |  checkstr CARG2, ->fff_fallback
-  |  ldr CARG3, STR:CARG1->len
-  |   ldr CARG2, [DISPATCH, #DISPATCH_GL(tmpbuf.b)]
-  |    ldr RB, [DISPATCH, #DISPATCH_GL(tmpbuf.e)]
-  |  mov CARG4, #0
-  |  add CARG1, STR:CARG1, #sizeof(GCstr)
-  |   add INS, CARG2, CARG3
-  |   cmp RB, INS
-  |   blo ->fff_fallback
-  |1:  // ASCII case conversion.
-  |  ldrb RB, [CARG1, CARG4]
-  |   cmp CARG4, CARG3
-  |   bhs ->fff_newstr
-  |  sub RC, RB, #lo
-  |  cmp RC, #26
-  |  eorlo RB, RB, #0x20
-  |  strb RB, [CARG2, CARG4]
-  |   add CARG4, CARG4, #1
-  |  b <1
+  |  sub SBUF:CARG1, DISPATCH, #-DISPATCH_GL(tmpbuf)
+  |  checkstr CARG3, ->fff_fallback
+  |  ldr CARG4, SBUF:CARG1->b
+  |   str BASE, L->base
+  |   str PC, SAVE_PC
+  |   str L, SBUF:CARG1->L
+  |  str CARG4, SBUF:CARG1->p
+  |  bl extern lj_buf_putstr_ .. name
+  |  bl extern lj_buf_tostr
+  |  b ->fff_resstr
   |.endmacro
   |
-  |ffstring_case string_lower, 65
-  |ffstring_case string_upper, 97
+  |ffstring_op reverse
+  |ffstring_op lower
+  |ffstring_op upper
   |
   |//-- Bit library --------------------------------------------------------
   |
index c4f01e81899348a88c85436312f7c77cbe1dbf65..fa53a5545eb97af400bc33ea528f8634dd62a651 100644 (file)
 |.type NODE,           Node
 |.type NARGS8,         int
 |.type TRACE,          GCtrace
+|.type SBUF,           SBuf
 |
 |//-----------------------------------------------------------------------
 |
@@ -1668,6 +1669,7 @@ static void build_subroutines(BuildCtx *ctx)
   |.  move CARG1, L
   |  // Returns GCstr *.
   |  lw BASE, L->base
+  |->fff_resstr:
   |  move CARG1, CRET1
   |  b ->fff_restv
   |.  li CARG3, LJ_TSTR
@@ -1756,63 +1758,32 @@ static void build_subroutines(BuildCtx *ctx)
   |  b ->fff_newstr
   |.  nop
   |
-  |.ffunc string_reverse
+  |.macro ffstring_op, name
+  |  .ffunc string_ .. name
   |  ffgccheck
   |  lw CARG3, HI(BASE)
-  |   lw STR:CARG1, LO(BASE)
+  |   lw STR:CARG2, LO(BASE)
   |  beqz NARGS8:RC, ->fff_fallback
   |.  li AT, LJ_TSTR
   |  bne CARG3, AT, ->fff_fallback
-  |.  lw CARG2, DISPATCH_GL(tmpbuf.b)(DISPATCH)
-  |   lw CARG3, STR:CARG1->len
-  |  lw TMP1, DISPATCH_GL(tmpbuf.e)(DISPATCH)
-  |   addiu CARG1, STR:CARG1, #STR
-  |   addu CARG4, CARG2, CARG3
-  |  sltu AT, TMP1, CARG4
-  |  bnez AT, ->fff_fallback
-  |.  addu TMP3, CARG1, CARG3
-  |1:  // Reverse string copy.
-  |   lbu TMP1, 0(CARG1)
-  |  sltu AT, CARG1, TMP3
-  |  beqz AT, ->fff_newstr
-  |.  addiu CARG1, CARG1, 1
-  |  addiu CARG4, CARG4, -1
-  |  b <1
-  |   sb TMP1, 0(CARG4)
-  |
-  |.macro ffstring_case, name, lo
-  |  .ffunc name
-  |  ffgccheck
-  |  lw CARG3, HI(BASE)
-  |   lw STR:CARG1, LO(BASE)
-  |  beqz NARGS8:RC, ->fff_fallback
-  |.  li AT, LJ_TSTR
-  |  bne CARG3, AT, ->fff_fallback
-  |.  lw CARG2, DISPATCH_GL(tmpbuf.b)(DISPATCH)
-  |   lw CARG3, STR:CARG1->len
-  |  lw TMP1, DISPATCH_GL(tmpbuf.e)(DISPATCH)
-  |   addiu CARG1, STR:CARG1, #STR
-  |   addu TMP3, CARG2, CARG3
-  |  sltu AT, TMP1, TMP3
-  |  bnez AT, ->fff_fallback
-  |.  addu TMP3, CARG1, CARG3
-  |  move CARG4, CARG2
-  |1:  // ASCII case conversion.
-  |   lbu TMP1, 0(CARG1)
-  |  sltu AT, CARG1, TMP3
-  |  beqz AT, ->fff_newstr
-  |.  addiu TMP0, TMP1, -lo
-  |   xori TMP2, TMP1, 0x20
-  |   sltiu AT, TMP0, 26
-  |   movn TMP1, TMP2, AT
-  |  addiu CARG1, CARG1, 1
-  |   sb TMP1, 0(CARG4)
-  |  b <1
-  |.  addiu CARG4, CARG4, 1
+  |.  addiu SBUF:CARG1, DISPATCH, DISPATCH_GL(tmpbuf)
+  |  load_got lj_buf_putstr_ .. name
+  |  lw TMP0, SBUF:CARG1->b
+  |   sw L, SBUF:CARG1->L
+  |   sw BASE, L->base
+  |  sw TMP0, SBUF:CARG1->p
+  |  call_intern extern lj_buf_putstr_ .. name
+  |.  sw PC, SAVE_PC
+  |  load_got lj_buf_tostr
+  |  call_intern lj_buf_tostr
+  |.  move SBUF:CARG1, SBUF:CRET1
+  |  b ->fff_resstr
+  |.  lw BASE, L->base
   |.endmacro
   |
-  |ffstring_case string_lower, 65
-  |ffstring_case string_upper, 97
+  |ffstring_op reverse
+  |ffstring_op lower
+  |ffstring_op upper
   |
   |//-- Bit library --------------------------------------------------------
   |
index c85f1f10e71299c1c8d2d77ab755ef49d33ce759..ac399900033190c3c051dd67e07bba71d2f126a2 100644 (file)
 |.type NODE,           Node
 |.type NARGS8,         int
 |.type TRACE,          GCtrace
+|.type SBUF,           SBuf
 |
 |//-----------------------------------------------------------------------
 |
@@ -2103,6 +2104,7 @@ static void build_subroutines(BuildCtx *ctx)
   |  stp BASE, L->base
   |  stw PC, SAVE_PC
   |  bl extern lj_str_new              // (lua_State *L, char *str, size_t l)
+  |->fff_resstr:
   |  // Returns GCstr *.
   |  lp BASE, L->base
   |  li CARG3, LJ_TSTR
@@ -2223,66 +2225,29 @@ static void build_subroutines(BuildCtx *ctx)
   |  li CARG3, LJ_TSTR
   |  b ->fff_restv
   |
-  |.ffunc string_reverse
+  |.macro ffstring_op, name
+  |  .ffunc string_ .. name
   |  ffgccheck
   |  cmplwi NARGS8:RC, 8
   |   lwz CARG3, 0(BASE)
-  |    lwz STR:CARG1, 4(BASE)
+  |    lwz STR:CARG2, 4(BASE)
   |  blt ->fff_fallback
   |  checkstr CARG3
-  |   lwz CARG2, DISPATCH_GL(tmpbuf.b)(DISPATCH)
-  |   lwz TMP1, DISPATCH_GL(tmpbuf.e)(DISPATCH)
+  |   la SBUF:CARG1, DISPATCH_GL(tmpbuf)(DISPATCH)
   |  bne ->fff_fallback
-  |  lwz CARG3, STR:CARG1->len
-  |   la CARG1, #STR(STR:CARG1)
-  |   li TMP2, 0
-  |   add TMP3, CARG2, CARG3
-  |  cmplw TMP1, TMP3
-  |   subi TMP3, CARG3, 1
-  |  blt ->fff_fallback
-  |1:  // Reverse string copy.
-  |  cmpwi TMP3, 0
-  |   lbzx TMP1, CARG1, TMP2
-  |  blty ->fff_newstr
-  |   stbx TMP1, CARG2, TMP3
-  |  subi TMP3, TMP3, 1
-  |  addi TMP2, TMP2, 1
-  |  b <1
-  |
-  |.macro ffstring_case, name, lo
-  |  .ffunc name
-  |  ffgccheck
-  |  cmplwi NARGS8:RC, 8
-  |   lwz CARG3, 0(BASE)
-  |    lwz STR:CARG1, 4(BASE)
-  |  blt ->fff_fallback
-  |  checkstr CARG3
-  |   lwz CARG2, DISPATCH_GL(tmpbuf.b)(DISPATCH)
-  |   lwz TMP1, DISPATCH_GL(tmpbuf.e)(DISPATCH)
-  |  bne ->fff_fallback
-  |  lwz CARG3, STR:CARG1->len
-  |   la CARG1, #STR(STR:CARG1)
-  |   li TMP2, 0
-  |   add TMP3, CARG2, CARG3
-  |  cmplw TMP1, TMP3
-  |  blt ->fff_fallback
-  |1:  // ASCII case conversion.
-  |  cmplw TMP2, CARG3
-  |   lbzx TMP1, CARG1, TMP2
-  |  bgey ->fff_newstr
-  |   subi TMP0, TMP1, lo
-  |    xori TMP3, TMP1, 0x20
-  |   addic TMP0, TMP0, -26
-  |   subfe TMP3, TMP3, TMP3
-  |   rlwinm TMP3, TMP3, 0, 26, 26     // x &= 0x20.
-  |   xor TMP1, TMP1, TMP3
-  |   stbx TMP1, CARG2, TMP2
-  |  addi TMP2, TMP2, 1
-  |  b <1
+  |   lwz TMP0, SBUF:CARG1->b
+  |  stw L, SBUF:CARG1->L
+  |  stp BASE, L->base
+  |  stw PC, SAVE_PC
+  |   stw TMP0, SBUF:CARG1->p
+  |  bl extern lj_buf_putstr_ .. name
+  |  bl extern lj_buf_tostr
+  |  b ->fff_resstr
   |.endmacro
   |
-  |ffstring_case string_lower, 65
-  |ffstring_case string_upper, 97
+  |ffstring_op reverse
+  |ffstring_op lower
+  |ffstring_op upper
   |
   |//-- Bit library --------------------------------------------------------
   |
index 8ed55fd26bc6484d81a8dc2a9689c7069c802830..8bbeaa2bc700bf072a99af5e3acba2e34bf4bb1b 100644 (file)
 |.type NODE,           Node
 |.type NARGS,          int
 |.type TRACE,          GCtrace
+|.type SBUF,           SBuf
 |
 |// Stack layout while in interpreter. Must match with lj_frame.h.
 |//-----------------------------------------------------------------------
@@ -2258,6 +2259,7 @@ static void build_subroutines(BuildCtx *ctx)
   |.endif
   |  mov SAVE_PC, PC
   |  call extern lj_str_new            // (lua_State *L, char *str, size_t l)
+  |->fff_resstr:
   |  // GCstr * returned in eax (RD).
   |  mov BASE, L:RB->base
   |  mov PC, [BASE-4]
@@ -2373,69 +2375,27 @@ static void build_subroutines(BuildCtx *ctx)
   |  mov RD, [DISPATCH+DISPATCH_GL(tmpbuf.b)]
   |  jmp ->fff_newstr
   |
-  |.ffunc_1 string_reverse
+  |.macro ffstring_op, name
+  |  .ffunc_1 string_ .. name
   |  ffgccheck
   |  cmp dword [BASE+4], LJ_TSTR;  jne ->fff_fallback
-  |  mov STR:RB, [BASE]
-  |  mov RC, STR:RB->len
-  |  test RC, RC
-  |  jz ->fff_emptystr                 // Zero length string?
-  |  mov TMP2, PC                      // Need another temp register.
-  |  mov PC, [DISPATCH+DISPATCH_GL(tmpbuf.b)]
-  |  lea RA, [PC+RC]
-  |  cmp [DISPATCH+DISPATCH_GL(tmpbuf.e)], RA;  jb ->fff_fallback_1
-  |  add RB, #STR
-  |.if X64
-  |  mov TMP3, RC
-  |.else
-  |  mov ARG3, RC
-  |.endif
-  |1:
-  |  movzx RA, byte [RB]
-  |  add RB, 1
-  |  sub RC, 1
-  |  mov [PC+RC], RAL
-  |  jnz <1
-  |  mov RD, PC
-  |  mov PC, TMP2
-  |  jmp ->fff_newstr
-  |
-  |.macro ffstring_case, name, lo, hi
-  |  .ffunc_1 name
-  |  ffgccheck
-  |  cmp dword [BASE+4], LJ_TSTR;  jne ->fff_fallback
-  |  mov TMP2, PC                      // Need another temp register.
-  |  mov STR:RB, [BASE]
-  |  mov RC, STR:RB->len
-  |  mov PC, [DISPATCH+DISPATCH_GL(tmpbuf.b)]
-  |  lea RA, [PC+RC]
-  |  cmp [DISPATCH+DISPATCH_GL(tmpbuf.e)], RA;  jb ->fff_fallback_1
-  |  add RB, #STR
-  |.if X64
-  |  mov TMP3, RC
-  |.else
-  |  mov ARG3, RC
-  |.endif
-  |  jmp >3
-  |1:  // ASCII case conversion. Yes, this is suboptimal code (do you care?).
-  |  movzx RA, byte [RB+RC]
-  |  cmp RA, lo
-  |  jb >2
-  |  cmp RA, hi
-  |  ja >2
-  |  xor RA, 0x20
-  |2:
-  |  mov [PC+RC], RAL
-  |3:
-  |  sub RC, 1
-  |  jns <1
-  |  mov RD, PC
-  |  mov PC, TMP2
-  |  jmp ->fff_newstr
+  |  mov L:RB, SAVE_L
+  |   lea SBUF:FCARG1, [DISPATCH+DISPATCH_GL(tmpbuf)]
+  |  mov L:RB->base, BASE
+  |  mov STR:FCARG2, [BASE]            // Caveat: FCARG2 == BASE
+  |   mov RC, SBUF:FCARG1->b
+  |   mov SBUF:FCARG1->L, L:RB
+  |   mov SBUF:FCARG1->p, RC
+  |  mov SAVE_PC, PC
+  |  call extern lj_buf_putstr_ .. name
+  |  mov FCARG1, eax
+  |  call extern lj_buf_tostr
+  |  jmp ->fff_resstr
   |.endmacro
   |
-  |ffstring_case string_lower, 0x41, 0x5a
-  |ffstring_case string_upper, 0x61, 0x7a
+  |ffstring_op reverse
+  |ffstring_op lower
+  |ffstring_op upper
   |
   |//-- Bit library --------------------------------------------------------
   |