Browse Source

Merge branch 'main' into 12.x

Sasha Szpakowski 2 years ago
parent
commit
17eb2fe045
51 changed files with 495 additions and 168 deletions
  1. 1 1
      CMakeLists.txt
  2. 1 1
      libs/LuaJIT/.relver
  3. 1 2
      libs/LuaJIT/src/jit/dis_arm64.lua
  4. 18 10
      libs/LuaJIT/src/lj_asm_arm.h
  5. 14 6
      libs/LuaJIT/src/lj_asm_arm64.h
  6. 17 10
      libs/LuaJIT/src/lj_asm_mips.h
  7. 17 10
      libs/LuaJIT/src/lj_asm_ppc.h
  8. 31 18
      libs/LuaJIT/src/lj_asm_x86.h
  9. 3 1
      libs/LuaJIT/src/lj_cparse.c
  10. 7 4
      libs/LuaJIT/src/lj_def.h
  11. 38 9
      libs/LuaJIT/src/lj_opt_fold.c
  12. 10 5
      libs/LuaJIT/src/lj_opt_mem.c
  13. 12 2
      libs/LuaJIT/src/lj_record.c
  14. 5 2
      libs/LuaJIT/src/lj_state.c
  15. 7 0
      libs/LuaJIT/src/vm_arm.dasc
  16. 8 0
      libs/LuaJIT/src/vm_arm64.dasc
  17. 9 1
      libs/LuaJIT/src/vm_mips.dasc
  18. 10 2
      libs/LuaJIT/src/vm_mips64.dasc
  19. 9 0
      libs/LuaJIT/src/vm_ppc.dasc
  20. 6 0
      libs/LuaJIT/src/vm_x64.dasc
  21. 7 1
      libs/LuaJIT/src/vm_x86.dasc
  22. 16 2
      libs/SDL2/CMakeLists.txt
  23. 1 1
      libs/SDL2/Makefile.os2
  24. 1 1
      libs/SDL2/Makefile.w32
  25. 1 1
      libs/SDL2/SDL2.spec
  26. 1 1
      libs/SDL2/VERSION.txt
  27. 2 2
      libs/SDL2/Xcode/SDL/Info-Framework.plist
  28. 6 6
      libs/SDL2/Xcode/SDL/SDL.xcodeproj/project.pbxproj
  29. 1 1
      libs/SDL2/Xcode/SDL/pkg-support/SDL.info
  30. 1 0
      libs/SDL2/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
  31. 1 1
      libs/SDL2/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
  32. 1 1
      libs/SDL2/configure
  33. 1 1
      libs/SDL2/configure.ac
  34. 2 2
      libs/SDL2/include/SDL_revision.h
  35. 1 1
      libs/SDL2/include/SDL_version.h
  36. 2 2
      libs/SDL2/src/audio/arts/SDL_artsaudio.c
  37. 2 2
      libs/SDL2/src/core/android/SDL_android.c
  38. 1 0
      libs/SDL2/src/hidapi/libusb/hid.c
  39. 4 0
      libs/SDL2/src/joystick/SDL_joystick.c
  40. 1 0
      libs/SDL2/src/joystick/controller_list.h
  41. 7 0
      libs/SDL2/src/joystick/hidapi/SDL_hidapijoystick.c
  42. 4 4
      libs/SDL2/src/main/windows/version.rc
  43. 13 8
      libs/SDL2/src/render/software/SDL_triangle.c
  44. 71 0
      libs/SDL2/src/stdlib/SDL_string.c
  45. 3 1
      libs/SDL2/src/test/SDL_test_fuzzer.c
  46. 13 8
      libs/SDL2/src/video/SDL_blit_slow.c
  47. 1 0
      libs/SDL2/src/video/android/SDL_androidevents.c
  48. 8 2
      libs/SDL2/src/video/wayland/SDL_waylandevents.c
  49. 10 16
      libs/SDL2/src/video/wayland/SDL_waylandwindow.c
  50. 11 18
      libs/SDL2/src/video/x11/SDL_x11mouse.c
  51. 77 1
      libs/SDL2/test/testautomation_stdlib.c

+ 1 - 1
CMakeLists.txt

@@ -203,7 +203,7 @@ set(MEGA_LIBOGG_VER "1.3.2")
 set(MEGA_LIBVORBIS_VER "1.3.5")
 set(MEGA_LIBVORBIS_VER "1.3.5")
 set(MEGA_LIBTHEORA_VER "1.1.1")
 set(MEGA_LIBTHEORA_VER "1.1.1")
 set(MEGA_FREETYPE_VER "2.12.0")
 set(MEGA_FREETYPE_VER "2.12.0")
-set(MEGA_SDL2_VER "2.28.4")
+set(MEGA_SDL2_VER "2.28.5")
 set(MEGA_OPENAL_VER "1.22.0")
 set(MEGA_OPENAL_VER "1.22.0")
 set(MEGA_MODPLUG_VER "0.8.8.4")
 set(MEGA_MODPLUG_VER "0.8.8.4")
 
 

+ 1 - 1
libs/LuaJIT/.relver

@@ -1 +1 @@
-1697887905
+1700008891

+ 1 - 2
libs/LuaJIT/src/jit/dis_arm64.lua

@@ -985,8 +985,7 @@ local function disass_ins(ctx)
 	x = x.."]"
 	x = x.."]"
       end
       end
     elseif p == "P" then
     elseif p == "P" then
-      local opcv, sh = rshift(op, 26), 2
-      if opcv >= 0x2a then sh = 4 elseif opcv >= 0x1b then sh = 3 end
+      local sh = 2 + rshift(op, 31 - band(rshift(op, 26), 1))
       local imm7 = lshift(arshift(lshift(op, 10), 25), sh)
       local imm7 = lshift(arshift(lshift(op, 10), 25), sh)
       local rn = map_regs.x[band(rshift(op, 5), 31)]
       local rn = map_regs.x[band(rshift(op, 5), 31)]
       local ind = band(rshift(op, 23), 3)
       local ind = band(rshift(op, 23), 3)

+ 18 - 10
libs/LuaJIT/src/lj_asm_arm.h

@@ -969,24 +969,32 @@ static void asm_hrefk(ASMState *as, IRIns *ir)
 static void asm_uref(ASMState *as, IRIns *ir)
 static void asm_uref(ASMState *as, IRIns *ir)
 {
 {
   Reg dest = ra_dest(as, ir, RSET_GPR);
   Reg dest = ra_dest(as, ir, RSET_GPR);
-  if (irref_isk(ir->op1)) {
+  int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC);
+  if (irref_isk(ir->op1) && !guarded) {
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     emit_lsptr(as, ARMI_LDR, dest, v);
     emit_lsptr(as, ARMI_LDR, dest, v);
   } else {
   } else {
-    Reg uv = ra_scratch(as, RSET_GPR);
-    Reg func = ra_alloc1(as, ir->op1, RSET_GPR);
-    if (ir->o == IR_UREFC) {
-      asm_guardcc(as, CC_NE);
+    if (guarded) {
+      asm_guardcc(as, ir->o == IR_UREFC ? CC_NE : CC_EQ);
       emit_n(as, ARMI_CMP|ARMI_K12|1, RID_TMP);
       emit_n(as, ARMI_CMP|ARMI_K12|1, RID_TMP);
-      emit_opk(as, ARMI_ADD, dest, uv,
+    }
+    if (ir->o == IR_UREFC)
+      emit_opk(as, ARMI_ADD, dest, dest,
 	       (int32_t)offsetof(GCupval, tv), RSET_GPR);
 	       (int32_t)offsetof(GCupval, tv), RSET_GPR);
-      emit_lso(as, ARMI_LDRB, RID_TMP, uv, (int32_t)offsetof(GCupval, closed));
+    else
+      emit_lso(as, ARMI_LDR, dest, dest, (int32_t)offsetof(GCupval, v));
+    if (guarded)
+      emit_lso(as, ARMI_LDRB, RID_TMP, dest,
+	       (int32_t)offsetof(GCupval, closed));
+    if (irref_isk(ir->op1)) {
+      GCfunc *fn = ir_kfunc(IR(ir->op1));
+      int32_t k = (int32_t)gcrefu(fn->l.uvptr[(ir->op2 >> 8)]);
+      emit_loadi(as, dest, k);
     } else {
     } else {
-      emit_lso(as, ARMI_LDR, dest, uv, (int32_t)offsetof(GCupval, v));
+      emit_lso(as, ARMI_LDR, dest, ra_alloc1(as, ir->op1, RSET_GPR),
+	       (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8));
     }
     }
-    emit_lso(as, ARMI_LDR, uv, func,
-	     (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8));
   }
   }
 }
 }
 
 

+ 14 - 6
libs/LuaJIT/src/lj_asm_arm64.h

@@ -931,22 +931,30 @@ static void asm_hrefk(ASMState *as, IRIns *ir)
 static void asm_uref(ASMState *as, IRIns *ir)
 static void asm_uref(ASMState *as, IRIns *ir)
 {
 {
   Reg dest = ra_dest(as, ir, RSET_GPR);
   Reg dest = ra_dest(as, ir, RSET_GPR);
-  if (irref_isk(ir->op1)) {
+  int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC);
+  if (irref_isk(ir->op1) && !guarded) {
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     emit_lsptr(as, A64I_LDRx, dest, v);
     emit_lsptr(as, A64I_LDRx, dest, v);
   } else {
   } else {
-    if (ir->o == IR_UREFC) {
-      asm_guardcnb(as, A64I_CBZ, RID_TMP);
+    if (guarded)
+      asm_guardcnb(as, ir->o == IR_UREFC ? A64I_CBZ : A64I_CBNZ, RID_TMP);
+    if (ir->o == IR_UREFC)
       emit_opk(as, A64I_ADDx, dest, dest,
       emit_opk(as, A64I_ADDx, dest, dest,
 	       (int32_t)offsetof(GCupval, tv), RSET_GPR);
 	       (int32_t)offsetof(GCupval, tv), RSET_GPR);
+    else
+      emit_lso(as, A64I_LDRx, dest, dest, (int32_t)offsetof(GCupval, v));
+    if (guarded)
       emit_lso(as, A64I_LDRB, RID_TMP, dest,
       emit_lso(as, A64I_LDRB, RID_TMP, dest,
 	       (int32_t)offsetof(GCupval, closed));
 	       (int32_t)offsetof(GCupval, closed));
+    if (irref_isk(ir->op1)) {
+      GCfunc *fn = ir_kfunc(IR(ir->op1));
+      uint64_t k = gcrefu(fn->l.uvptr[(ir->op2 >> 8)]);
+      emit_loadu64(as, dest, k);
     } else {
     } else {
-      emit_lso(as, A64I_LDRx, dest, dest, (int32_t)offsetof(GCupval, v));
+      emit_lso(as, A64I_LDRx, dest, ra_alloc1(as, ir->op1, RSET_GPR),
+	       (int32_t)offsetof(GCfuncL, uvptr) + 8*(int32_t)(ir->op2 >> 8));
     }
     }
-    emit_lso(as, A64I_LDRx, dest, ra_alloc1(as, ir->op1, RSET_GPR),
-	     (int32_t)offsetof(GCfuncL, uvptr) + 8*(int32_t)(ir->op2 >> 8));
   }
   }
 }
 }
 
 

+ 17 - 10
libs/LuaJIT/src/lj_asm_mips.h

@@ -1207,22 +1207,29 @@ nolo:
 static void asm_uref(ASMState *as, IRIns *ir)
 static void asm_uref(ASMState *as, IRIns *ir)
 {
 {
   Reg dest = ra_dest(as, ir, RSET_GPR);
   Reg dest = ra_dest(as, ir, RSET_GPR);
-  if (irref_isk(ir->op1)) {
+  int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC);
+  if (irref_isk(ir->op1) && !guarded) {
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     emit_lsptr(as, MIPSI_AL, dest, v, RSET_GPR);
     emit_lsptr(as, MIPSI_AL, dest, v, RSET_GPR);
   } else {
   } else {
-    Reg uv = ra_scratch(as, RSET_GPR);
-    Reg func = ra_alloc1(as, ir->op1, RSET_GPR);
-    if (ir->o == IR_UREFC) {
-      asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO);
-      emit_tsi(as, MIPSI_AADDIU, dest, uv, (int32_t)offsetof(GCupval, tv));
-      emit_tsi(as, MIPSI_LBU, RID_TMP, uv, (int32_t)offsetof(GCupval, closed));
+    if (guarded)
+      asm_guard(as, ir->o == IR_UREFC ? MIPSI_BEQ : MIPSI_BNE, RID_TMP, RID_ZERO);
+    if (ir->o == IR_UREFC)
+      emit_tsi(as, MIPSI_AADDIU, dest, dest, (int32_t)offsetof(GCupval, tv));
+    else
+      emit_tsi(as, MIPSI_AL, dest, dest, (int32_t)offsetof(GCupval, v));
+    if (guarded)
+      emit_tsi(as, MIPSI_LBU, RID_TMP, dest, (int32_t)offsetof(GCupval, closed));
+    if (irref_isk(ir->op1)) {
+      GCfunc *fn = ir_kfunc(IR(ir->op1));
+      GCobj *o = gcref(fn->l.uvptr[(ir->op2 >> 8)]);
+      emit_loada(as, dest, o);
     } else {
     } else {
-      emit_tsi(as, MIPSI_AL, dest, uv, (int32_t)offsetof(GCupval, v));
+      emit_tsi(as, MIPSI_AL, dest, ra_alloc1(as, ir->op1, RSET_GPR),
+	       (int32_t)offsetof(GCfuncL, uvptr) +
+	       (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8));
     }
     }
-    emit_tsi(as, MIPSI_AL, uv, func, (int32_t)offsetof(GCfuncL, uvptr) +
-	     (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8));
   }
   }
 }
 }
 
 

+ 17 - 10
libs/LuaJIT/src/lj_asm_ppc.h

@@ -840,23 +840,30 @@ static void asm_hrefk(ASMState *as, IRIns *ir)
 static void asm_uref(ASMState *as, IRIns *ir)
 static void asm_uref(ASMState *as, IRIns *ir)
 {
 {
   Reg dest = ra_dest(as, ir, RSET_GPR);
   Reg dest = ra_dest(as, ir, RSET_GPR);
-  if (irref_isk(ir->op1)) {
+  int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC);
+  if (irref_isk(ir->op1) && !guarded) {
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     emit_lsptr(as, PPCI_LWZ, dest, v, RSET_GPR);
     emit_lsptr(as, PPCI_LWZ, dest, v, RSET_GPR);
   } else {
   } else {
-    Reg uv = ra_scratch(as, RSET_GPR);
-    Reg func = ra_alloc1(as, ir->op1, RSET_GPR);
-    if (ir->o == IR_UREFC) {
-      asm_guardcc(as, CC_NE);
+    if (guarded) {
+      asm_guardcc(as, ir->o == IR_UREFC ? CC_NE : CC_EQ);
       emit_ai(as, PPCI_CMPWI, RID_TMP, 1);
       emit_ai(as, PPCI_CMPWI, RID_TMP, 1);
-      emit_tai(as, PPCI_ADDI, dest, uv, (int32_t)offsetof(GCupval, tv));
-      emit_tai(as, PPCI_LBZ, RID_TMP, uv, (int32_t)offsetof(GCupval, closed));
+    }
+    if (ir->o == IR_UREFC)
+      emit_tai(as, PPCI_ADDI, dest, dest, (int32_t)offsetof(GCupval, tv));
+    else
+      emit_tai(as, PPCI_LWZ, dest, dest, (int32_t)offsetof(GCupval, v));
+    if (guarded)
+      emit_tai(as, PPCI_LBZ, RID_TMP, dest, (int32_t)offsetof(GCupval, closed));
+    if (irref_isk(ir->op1)) {
+      GCfunc *fn = ir_kfunc(IR(ir->op1));
+      int32_t k = (int32_t)gcrefu(fn->l.uvptr[(ir->op2 >> 8)]);
+      emit_loadi(as, dest, k);
     } else {
     } else {
-      emit_tai(as, PPCI_LWZ, dest, uv, (int32_t)offsetof(GCupval, v));
+      emit_tai(as, PPCI_LWZ, dest, ra_alloc1(as, ir->op1, RSET_GPR),
+	       (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8));
     }
     }
-    emit_tai(as, PPCI_LWZ, uv, func,
-	     (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8));
   }
   }
 }
 }
 
 

+ 31 - 18
libs/LuaJIT/src/lj_asm_x86.h

@@ -109,7 +109,7 @@ static int asm_isk32(ASMState *as, IRRef ref, int32_t *k)
 /* Check if there's no conflicting instruction between curins and ref.
 /* Check if there's no conflicting instruction between curins and ref.
 ** Also avoid fusing loads if there are multiple references.
 ** Also avoid fusing loads if there are multiple references.
 */
 */
-static int noconflict(ASMState *as, IRRef ref, IROp conflict, int noload)
+static int noconflict(ASMState *as, IRRef ref, IROp conflict, int check)
 {
 {
   IRIns *ir = as->ir;
   IRIns *ir = as->ir;
   IRRef i = as->curins;
   IRRef i = as->curins;
@@ -118,7 +118,9 @@ static int noconflict(ASMState *as, IRRef ref, IROp conflict, int noload)
   while (--i > ref) {
   while (--i > ref) {
     if (ir[i].o == conflict)
     if (ir[i].o == conflict)
       return 0;  /* Conflict found. */
       return 0;  /* Conflict found. */
-    else if (!noload && (ir[i].op1 == ref || ir[i].op2 == ref))
+    else if ((check & 1) && (ir[i].o == IR_NEWREF || ir[i].o == IR_CALLS))
+      return 0;
+    else if ((check & 2) && (ir[i].op1 == ref || ir[i].op2 == ref))
       return 0;
       return 0;
   }
   }
   return 1;  /* Ok, no conflict. */
   return 1;  /* Ok, no conflict. */
@@ -134,7 +136,7 @@ static IRRef asm_fuseabase(ASMState *as, IRRef ref)
     lj_assertA(irb->op2 == IRFL_TAB_ARRAY, "expected FLOAD TAB_ARRAY");
     lj_assertA(irb->op2 == IRFL_TAB_ARRAY, "expected FLOAD TAB_ARRAY");
     /* We can avoid the FLOAD of t->array for colocated arrays. */
     /* We can avoid the FLOAD of t->array for colocated arrays. */
     if (ira->o == IR_TNEW && ira->op1 <= LJ_MAX_COLOSIZE &&
     if (ira->o == IR_TNEW && ira->op1 <= LJ_MAX_COLOSIZE &&
-	!neverfuse(as) && noconflict(as, irb->op1, IR_NEWREF, 1)) {
+	!neverfuse(as) && noconflict(as, irb->op1, IR_NEWREF, 0)) {
       as->mrm.ofs = (int32_t)sizeof(GCtab);  /* Ofs to colocated array. */
       as->mrm.ofs = (int32_t)sizeof(GCtab);  /* Ofs to colocated array. */
       return irb->op1;  /* Table obj. */
       return irb->op1;  /* Table obj. */
     }
     }
@@ -456,7 +458,7 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow)
     RegSet xallow = (allow & RSET_GPR) ? allow : RSET_GPR;
     RegSet xallow = (allow & RSET_GPR) ? allow : RSET_GPR;
     if (ir->o == IR_SLOAD) {
     if (ir->o == IR_SLOAD) {
       if (!(ir->op2 & (IRSLOAD_PARENT|IRSLOAD_CONVERT)) &&
       if (!(ir->op2 & (IRSLOAD_PARENT|IRSLOAD_CONVERT)) &&
-	  noconflict(as, ref, IR_RETF, 0) &&
+	  noconflict(as, ref, IR_RETF, 2) &&
 	  !(LJ_GC64 && irt_isaddr(ir->t))) {
 	  !(LJ_GC64 && irt_isaddr(ir->t))) {
 	as->mrm.base = (uint8_t)ra_alloc1(as, REF_BASE, xallow);
 	as->mrm.base = (uint8_t)ra_alloc1(as, REF_BASE, xallow);
 	as->mrm.ofs = 8*((int32_t)ir->op1-1-LJ_FR2) +
 	as->mrm.ofs = 8*((int32_t)ir->op1-1-LJ_FR2) +
@@ -467,12 +469,12 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow)
     } else if (ir->o == IR_FLOAD) {
     } else if (ir->o == IR_FLOAD) {
       /* Generic fusion is only ok for 32 bit operand (but see asm_comp). */
       /* Generic fusion is only ok for 32 bit operand (but see asm_comp). */
       if ((irt_isint(ir->t) || irt_isu32(ir->t) || irt_isaddr(ir->t)) &&
       if ((irt_isint(ir->t) || irt_isu32(ir->t) || irt_isaddr(ir->t)) &&
-	  noconflict(as, ref, IR_FSTORE, 0)) {
+	  noconflict(as, ref, IR_FSTORE, 2)) {
 	asm_fusefref(as, ir, xallow);
 	asm_fusefref(as, ir, xallow);
 	return RID_MRM;
 	return RID_MRM;
       }
       }
     } else if (ir->o == IR_ALOAD || ir->o == IR_HLOAD || ir->o == IR_ULOAD) {
     } else if (ir->o == IR_ALOAD || ir->o == IR_HLOAD || ir->o == IR_ULOAD) {
-      if (noconflict(as, ref, ir->o + IRDELTA_L2S, 0) &&
+      if (noconflict(as, ref, ir->o + IRDELTA_L2S, 2+(ir->o != IR_ULOAD)) &&
 	  !(LJ_GC64 && irt_isaddr(ir->t))) {
 	  !(LJ_GC64 && irt_isaddr(ir->t))) {
 	asm_fuseahuref(as, ir->op1, xallow);
 	asm_fuseahuref(as, ir->op1, xallow);
 	return RID_MRM;
 	return RID_MRM;
@@ -482,7 +484,7 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow)
       ** Fusing unaligned memory operands is ok on x86 (except for SIMD types).
       ** Fusing unaligned memory operands is ok on x86 (except for SIMD types).
       */
       */
       if ((!irt_typerange(ir->t, IRT_I8, IRT_U16)) &&
       if ((!irt_typerange(ir->t, IRT_I8, IRT_U16)) &&
-	  noconflict(as, ref, IR_XSTORE, 0)) {
+	  noconflict(as, ref, IR_XSTORE, 2)) {
 	asm_fusexref(as, ir->op1, xallow);
 	asm_fusexref(as, ir->op1, xallow);
 	return RID_MRM;
 	return RID_MRM;
       }
       }
@@ -815,6 +817,7 @@ static void asm_tointg(ASMState *as, IRIns *ir, Reg left)
   emit_rr(as, XO_UCOMISD, left, tmp);
   emit_rr(as, XO_UCOMISD, left, tmp);
   emit_rr(as, XO_CVTSI2SD, tmp, dest);
   emit_rr(as, XO_CVTSI2SD, tmp, dest);
   emit_rr(as, XO_XORPS, tmp, tmp);  /* Avoid partial register stall. */
   emit_rr(as, XO_XORPS, tmp, tmp);  /* Avoid partial register stall. */
+  checkmclim(as);
   emit_rr(as, XO_CVTTSD2SI, dest, left);
   emit_rr(as, XO_CVTTSD2SI, dest, left);
   /* Can't fuse since left is needed twice. */
   /* Can't fuse since left is needed twice. */
 }
 }
@@ -857,6 +860,7 @@ static void asm_conv(ASMState *as, IRIns *ir)
       emit_rr(as, XO_SUBSD, dest, bias);  /* Subtract 2^52+2^51 bias. */
       emit_rr(as, XO_SUBSD, dest, bias);  /* Subtract 2^52+2^51 bias. */
       emit_rr(as, XO_XORPS, dest, bias);  /* Merge bias and integer. */
       emit_rr(as, XO_XORPS, dest, bias);  /* Merge bias and integer. */
       emit_rma(as, XO_MOVSD, bias, k);
       emit_rma(as, XO_MOVSD, bias, k);
+      checkmclim(as);
       emit_mrm(as, XO_MOVD, dest, asm_fuseload(as, lref, RSET_GPR));
       emit_mrm(as, XO_MOVD, dest, asm_fuseload(as, lref, RSET_GPR));
       return;
       return;
     } else {  /* Integer to FP conversion. */
     } else {  /* Integer to FP conversion. */
@@ -1173,6 +1177,7 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
     asm_guardcc(as, CC_E);
     asm_guardcc(as, CC_E);
   else
   else
     emit_sjcc(as, CC_E, l_end);
     emit_sjcc(as, CC_E, l_end);
+  checkmclim(as);
   if (irt_isnum(kt)) {
   if (irt_isnum(kt)) {
     if (isk) {
     if (isk) {
       /* Assumes -0.0 is already canonicalized to +0.0. */
       /* Assumes -0.0 is already canonicalized to +0.0. */
@@ -1232,7 +1237,6 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
 #endif
 #endif
   }
   }
   emit_sfixup(as, l_loop);
   emit_sfixup(as, l_loop);
-  checkmclim(as);
 #if LJ_GC64
 #if LJ_GC64
   if (!isk && irt_isaddr(kt)) {
   if (!isk && irt_isaddr(kt)) {
     emit_rr(as, XO_OR, tmp|REX_64, key);
     emit_rr(as, XO_OR, tmp|REX_64, key);
@@ -1259,6 +1263,7 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
       emit_rr(as, XO_ARITH(XOg_SUB), dest, tmp);
       emit_rr(as, XO_ARITH(XOg_SUB), dest, tmp);
       emit_shifti(as, XOg_ROL, tmp, HASH_ROT3);
       emit_shifti(as, XOg_ROL, tmp, HASH_ROT3);
       emit_rr(as, XO_ARITH(XOg_XOR), dest, tmp);
       emit_rr(as, XO_ARITH(XOg_XOR), dest, tmp);
+      checkmclim(as);
       emit_shifti(as, XOg_ROL, dest, HASH_ROT2);
       emit_shifti(as, XOg_ROL, dest, HASH_ROT2);
       emit_rr(as, XO_ARITH(XOg_SUB), tmp, dest);
       emit_rr(as, XO_ARITH(XOg_SUB), tmp, dest);
       emit_shifti(as, XOg_ROL, dest, HASH_ROT1);
       emit_shifti(as, XOg_ROL, dest, HASH_ROT1);
@@ -1276,7 +1281,6 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge)
       } else {
       } else {
 	emit_rr(as, XO_MOV, tmp, key);
 	emit_rr(as, XO_MOV, tmp, key);
 #if LJ_GC64
 #if LJ_GC64
-	checkmclim(as);
 	emit_gri(as, XG_ARITHi(XOg_XOR), dest, irt_toitype(kt) << 15);
 	emit_gri(as, XG_ARITHi(XOg_XOR), dest, irt_toitype(kt) << 15);
 	if ((as->flags & JIT_F_BMI2)) {
 	if ((as->flags & JIT_F_BMI2)) {
 	  emit_i8(as, 32);
 	  emit_i8(as, 32);
@@ -1373,24 +1377,31 @@ static void asm_hrefk(ASMState *as, IRIns *ir)
 static void asm_uref(ASMState *as, IRIns *ir)
 static void asm_uref(ASMState *as, IRIns *ir)
 {
 {
   Reg dest = ra_dest(as, ir, RSET_GPR);
   Reg dest = ra_dest(as, ir, RSET_GPR);
-  if (irref_isk(ir->op1)) {
+  int guarded = (irt_t(ir->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC);
+  if (irref_isk(ir->op1) && !guarded) {
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     GCfunc *fn = ir_kfunc(IR(ir->op1));
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
     emit_rma(as, XO_MOV, dest|REX_GC64, v);
     emit_rma(as, XO_MOV, dest|REX_GC64, v);
   } else {
   } else {
     Reg uv = ra_scratch(as, RSET_GPR);
     Reg uv = ra_scratch(as, RSET_GPR);
-    Reg func = ra_alloc1(as, ir->op1, RSET_GPR);
-    if (ir->o == IR_UREFC) {
+    if (ir->o == IR_UREFC)
       emit_rmro(as, XO_LEA, dest|REX_GC64, uv, offsetof(GCupval, tv));
       emit_rmro(as, XO_LEA, dest|REX_GC64, uv, offsetof(GCupval, tv));
-      asm_guardcc(as, CC_NE);
-      emit_i8(as, 1);
+    else
+      emit_rmro(as, XO_MOV, dest|REX_GC64, uv, offsetof(GCupval, v));
+    if (guarded) {
+      asm_guardcc(as, ir->o == IR_UREFC ? CC_E : CC_NE);
+      emit_i8(as, 0);
       emit_rmro(as, XO_ARITHib, XOg_CMP, uv, offsetof(GCupval, closed));
       emit_rmro(as, XO_ARITHib, XOg_CMP, uv, offsetof(GCupval, closed));
+    }
+    if (irref_isk(ir->op1)) {
+      GCfunc *fn = ir_kfunc(IR(ir->op1));
+      GCobj *o = gcref(fn->l.uvptr[(ir->op2 >> 8)]);
+      emit_loada(as, uv, o);
     } else {
     } else {
-      emit_rmro(as, XO_MOV, dest|REX_GC64, uv, offsetof(GCupval, v));
+      emit_rmro(as, XO_MOV, uv|REX_GC64, ra_alloc1(as, ir->op1, RSET_GPR),
+	        (int32_t)offsetof(GCfuncL, uvptr) +
+	        (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8));
     }
     }
-    emit_rmro(as, XO_MOV, uv|REX_GC64, func,
-	      (int32_t)offsetof(GCfuncL, uvptr) +
-	      (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8));
   }
   }
 }
 }
 
 
@@ -1547,6 +1558,7 @@ static void asm_ahuvload(ASMState *as, IRIns *ir)
   if (irt_islightud(ir->t)) {
   if (irt_islightud(ir->t)) {
     Reg dest = asm_load_lightud64(as, ir, 1);
     Reg dest = asm_load_lightud64(as, ir, 1);
     if (ra_hasreg(dest)) {
     if (ra_hasreg(dest)) {
+      checkmclim(as);
       asm_fuseahuref(as, ir->op1, RSET_GPR);
       asm_fuseahuref(as, ir->op1, RSET_GPR);
       if (ir->o == IR_VLOAD) as->mrm.ofs += 8 * ir->op2;
       if (ir->o == IR_VLOAD) as->mrm.ofs += 8 * ir->op2;
       emit_mrm(as, XO_MOV, dest|REX_64, RID_MRM);
       emit_mrm(as, XO_MOV, dest|REX_64, RID_MRM);
@@ -1594,6 +1606,7 @@ static void asm_ahuvload(ASMState *as, IRIns *ir)
   if (LJ_64 && irt_type(ir->t) >= IRT_NUM) {
   if (LJ_64 && irt_type(ir->t) >= IRT_NUM) {
     lj_assertA(irt_isinteger(ir->t) || irt_isnum(ir->t),
     lj_assertA(irt_isinteger(ir->t) || irt_isnum(ir->t),
 	       "bad load type %d", irt_type(ir->t));
 	       "bad load type %d", irt_type(ir->t));
+    checkmclim(as);
 #if LJ_GC64
 #if LJ_GC64
     emit_u32(as, LJ_TISNUM << 15);
     emit_u32(as, LJ_TISNUM << 15);
 #else
 #else

+ 3 - 1
libs/LuaJIT/src/lj_cparse.c

@@ -1766,9 +1766,11 @@ static void cp_pragma(CPState *cp, BCLine pragmaline)
     cp_check(cp, '(');
     cp_check(cp, '(');
     if (cp->tok == CTOK_IDENT) {
     if (cp->tok == CTOK_IDENT) {
       if (cp_str_is(cp->str, "push")) {
       if (cp_str_is(cp->str, "push")) {
-	if (cp->curpack < CPARSE_MAX_PACKSTACK) {
+	if (cp->curpack < CPARSE_MAX_PACKSTACK-1) {
 	  cp->packstack[cp->curpack+1] = cp->packstack[cp->curpack];
 	  cp->packstack[cp->curpack+1] = cp->packstack[cp->curpack];
 	  cp->curpack++;
 	  cp->curpack++;
+	} else {
+	  cp_errmsg(cp, cp->tok, LJ_ERR_XLEVELS);
 	}
 	}
       } else if (cp_str_is(cp->str, "pop")) {
       } else if (cp_str_is(cp->str, "pop")) {
 	if (cp->curpack > 0) cp->curpack--;
 	if (cp->curpack > 0) cp->curpack--;

+ 7 - 4
libs/LuaJIT/src/lj_def.h

@@ -259,12 +259,8 @@ static LJ_AINLINE uint32_t lj_fls(uint32_t x)
 #else
 #else
 unsigned char _BitScanForward(unsigned long *, unsigned long);
 unsigned char _BitScanForward(unsigned long *, unsigned long);
 unsigned char _BitScanReverse(unsigned long *, unsigned long);
 unsigned char _BitScanReverse(unsigned long *, unsigned long);
-unsigned char _BitScanForward64(unsigned long *, uint64_t);
-unsigned char _BitScanReverse64(unsigned long *, uint64_t);
 #pragma intrinsic(_BitScanForward)
 #pragma intrinsic(_BitScanForward)
 #pragma intrinsic(_BitScanReverse)
 #pragma intrinsic(_BitScanReverse)
-#pragma intrinsic(_BitScanForward64)
-#pragma intrinsic(_BitScanReverse64)
 
 
 static LJ_AINLINE uint32_t lj_ffs(uint32_t x)
 static LJ_AINLINE uint32_t lj_ffs(uint32_t x)
 {
 {
@@ -276,6 +272,12 @@ static LJ_AINLINE uint32_t lj_fls(uint32_t x)
   unsigned long r; _BitScanReverse(&r, x); return (uint32_t)r;
   unsigned long r; _BitScanReverse(&r, x); return (uint32_t)r;
 }
 }
 
 
+#if defined(_M_X64) || defined(_M_ARM64)
+unsigned char _BitScanForward64(unsigned long *, uint64_t);
+unsigned char _BitScanReverse64(unsigned long *, uint64_t);
+#pragma intrinsic(_BitScanForward64)
+#pragma intrinsic(_BitScanReverse64)
+
 static LJ_AINLINE uint32_t lj_ffs64(uint64_t x)
 static LJ_AINLINE uint32_t lj_ffs64(uint64_t x)
 {
 {
   unsigned long r; _BitScanForward64(&r, x); return (uint32_t)r;
   unsigned long r; _BitScanForward64(&r, x); return (uint32_t)r;
@@ -286,6 +288,7 @@ static LJ_AINLINE uint32_t lj_fls64(uint64_t x)
   unsigned long r; _BitScanReverse64(&r, x); return (uint32_t)r;
   unsigned long r; _BitScanReverse64(&r, x); return (uint32_t)r;
 }
 }
 #endif
 #endif
+#endif
 
 
 unsigned long _byteswap_ulong(unsigned long);
 unsigned long _byteswap_ulong(unsigned long);
 uint64_t _byteswap_uint64(uint64_t);
 uint64_t _byteswap_uint64(uint64_t);

+ 38 - 9
libs/LuaJIT/src/lj_opt_fold.c

@@ -2134,8 +2134,26 @@ LJFOLDX(lj_opt_fwd_uload)
 LJFOLD(ALEN any any)
 LJFOLD(ALEN any any)
 LJFOLDX(lj_opt_fwd_alen)
 LJFOLDX(lj_opt_fwd_alen)
 
 
+/* Try to merge UREFO/UREFC into referenced instruction. */
+static TRef merge_uref(jit_State *J, IRRef ref, IRIns* ir)
+{
+  if (ir->o == IR_UREFO && irt_isguard(ir->t)) {
+    /* Might be pointing to some other coroutine's stack.
+    ** And GC might shrink said stack, thereby repointing the upvalue.
+    ** GC might even collect said coroutine, thereby closing the upvalue.
+    */
+    if (gcstep_barrier(J, ref))
+      return EMITFOLD;  /* So cannot merge. */
+    /* Current fins wants a check, but ir doesn't have one. */
+    if ((irt_t(fins->t) & (IRT_GUARD|IRT_TYPE)) == (IRT_GUARD|IRT_PGC) &&
+	irt_type(ir->t) == IRT_IGC)
+      ir->t.irt += IRT_PGC-IRT_IGC;  /* So install a check. */
+  }
+  return ref;  /* Not a TRef, but the caller doesn't care. */
+}
+
 /* Upvalue refs are really loads, but there are no corresponding stores.
 /* Upvalue refs are really loads, but there are no corresponding stores.
-** So CSE is ok for them, except for UREFO across a GC step (see below).
+** So CSE is ok for them, except for guarded UREFO across a GC step.
 ** If the referenced function is const, its upvalue addresses are const, too.
 ** If the referenced function is const, its upvalue addresses are const, too.
 ** This can be used to improve CSE by looking for the same address,
 ** This can be used to improve CSE by looking for the same address,
 ** even if the upvalues originate from a different function.
 ** even if the upvalues originate from a different function.
@@ -2153,9 +2171,7 @@ LJFOLDF(cse_uref)
       if (irref_isk(ir->op1)) {
       if (irref_isk(ir->op1)) {
 	GCfunc *fn2 = ir_kfunc(IR(ir->op1));
 	GCfunc *fn2 = ir_kfunc(IR(ir->op1));
 	if (gco2uv(gcref(fn2->l.uvptr[(ir->op2 >> 8)])) == uv) {
 	if (gco2uv(gcref(fn2->l.uvptr[(ir->op2 >> 8)])) == uv) {
-	  if (fins->o == IR_UREFO && gcstep_barrier(J, ref))
-	    break;
-	  return ref;
+	  return merge_uref(J, ref, ir);
 	}
 	}
       }
       }
       ref = ir->prev;
       ref = ir->prev;
@@ -2164,6 +2180,24 @@ LJFOLDF(cse_uref)
   return EMITFOLD;
   return EMITFOLD;
 }
 }
 
 
+/* Custom CSE for UREFO. */
+LJFOLD(UREFO any any)
+LJFOLDF(cse_urefo)
+{
+  if (LJ_LIKELY(J->flags & JIT_F_OPT_CSE)) {
+    IRRef ref = J->chain[IR_UREFO];
+    IRRef lim = fins->op1;
+    IRRef2 op12 = (IRRef2)fins->op1 + ((IRRef2)fins->op2 << 16);
+    while (ref > lim) {
+      IRIns *ir = IR(ref);
+      if (ir->op12 == op12)
+	return merge_uref(J, ref, ir);
+      ref = ir->prev;
+    }
+  }
+  return EMITFOLD;
+}
+
 LJFOLD(HREFK any any)
 LJFOLD(HREFK any any)
 LJFOLDX(lj_opt_fwd_hrefk)
 LJFOLDX(lj_opt_fwd_hrefk)
 
 
@@ -2384,14 +2418,9 @@ LJFOLDF(fold_base)
 
 
 /* Write barriers are amenable to CSE, but not across any incremental
 /* Write barriers are amenable to CSE, but not across any incremental
 ** GC steps.
 ** GC steps.
-**
-** The same logic applies to open upvalue references, because a stack
-** may be resized during a GC step (not the current stack, but maybe that
-** of a coroutine).
 */
 */
 LJFOLD(TBAR any)
 LJFOLD(TBAR any)
 LJFOLD(OBAR any any)
 LJFOLD(OBAR any any)
-LJFOLD(UREFO any any)
 LJFOLDF(barrier_tab)
 LJFOLDF(barrier_tab)
 {
 {
   TRef tr = lj_opt_cse(J);
   TRef tr = lj_opt_cse(J);

+ 10 - 5
libs/LuaJIT/src/lj_opt_mem.c

@@ -464,18 +464,23 @@ doemit:
 */
 */
 static AliasRet aa_uref(IRIns *refa, IRIns *refb)
 static AliasRet aa_uref(IRIns *refa, IRIns *refb)
 {
 {
-  if (refa->o != refb->o)
-    return ALIAS_NO;  /* Different UREFx type. */
   if (refa->op1 == refb->op1) {  /* Same function. */
   if (refa->op1 == refb->op1) {  /* Same function. */
     if (refa->op2 == refb->op2)
     if (refa->op2 == refb->op2)
       return ALIAS_MUST;  /* Same function, same upvalue idx. */
       return ALIAS_MUST;  /* Same function, same upvalue idx. */
     else
     else
       return ALIAS_NO;  /* Same function, different upvalue idx. */
       return ALIAS_NO;  /* Same function, different upvalue idx. */
   } else {  /* Different functions, check disambiguation hash values. */
   } else {  /* Different functions, check disambiguation hash values. */
-    if (((refa->op2 ^ refb->op2) & 0xff))
+    if (((refa->op2 ^ refb->op2) & 0xff)) {
       return ALIAS_NO;  /* Upvalues with different hash values cannot alias. */
       return ALIAS_NO;  /* Upvalues with different hash values cannot alias. */
-    else
-      return ALIAS_MAY;  /* No conclusion can be drawn for same hash value. */
+    } else if (refa->o != refb->o) {
+      /* Different UREFx type, but need to confirm the UREFO really is open. */
+      if (irt_type(refa->t) == IRT_IGC) refa->t.irt += IRT_PGC-IRT_IGC;
+      else if (irt_type(refb->t) == IRT_IGC) refb->t.irt += IRT_PGC-IRT_IGC;
+      return ALIAS_NO;
+    } else {
+      /* No conclusion can be drawn for same hash value and same UREFx type. */
+      return ALIAS_MAY;
+    }
   }
   }
 }
 }
 
 

+ 12 - 2
libs/LuaJIT/src/lj_record.c

@@ -976,6 +976,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
       emitir(IRTG(IR_RETF, IRT_PGC), trpt, trpc);
       emitir(IRTG(IR_RETF, IRT_PGC), trpt, trpc);
       J->retdepth++;
       J->retdepth++;
       J->needsnap = 1;
       J->needsnap = 1;
+      J->scev.idx = REF_NIL;
       lj_assertJ(J->baseslot == 1+LJ_FR2, "bad baseslot for return");
       lj_assertJ(J->baseslot == 1+LJ_FR2, "bad baseslot for return");
       /* Shift result slots up and clear the slots of the new frame below. */
       /* Shift result slots up and clear the slots of the new frame below. */
       memmove(J->base + cbase, J->base-1-LJ_FR2, sizeof(TRef)*nresults);
       memmove(J->base + cbase, J->base-1-LJ_FR2, sizeof(TRef)*nresults);
@@ -1772,12 +1773,12 @@ noconstify:
   /* Note: this effectively limits LJ_MAX_UPVAL to 127. */
   /* Note: this effectively limits LJ_MAX_UPVAL to 127. */
   uv = (uv << 8) | (hashrot(uvp->dhash, uvp->dhash + HASH_BIAS) & 0xff);
   uv = (uv << 8) | (hashrot(uvp->dhash, uvp->dhash + HASH_BIAS) & 0xff);
   if (!uvp->closed) {
   if (!uvp->closed) {
-    uref = tref_ref(emitir(IRTG(IR_UREFO, IRT_PGC), fn, uv));
     /* In current stack? */
     /* In current stack? */
     if (uvval(uvp) >= tvref(J->L->stack) &&
     if (uvval(uvp) >= tvref(J->L->stack) &&
 	uvval(uvp) < tvref(J->L->maxstack)) {
 	uvval(uvp) < tvref(J->L->maxstack)) {
       int32_t slot = (int32_t)(uvval(uvp) - (J->L->base - J->baseslot));
       int32_t slot = (int32_t)(uvval(uvp) - (J->L->base - J->baseslot));
       if (slot >= 0) {  /* Aliases an SSA slot? */
       if (slot >= 0) {  /* Aliases an SSA slot? */
+	uref = tref_ref(emitir(IRT(IR_UREFO, IRT_PGC), fn, uv));
 	emitir(IRTG(IR_EQ, IRT_PGC),
 	emitir(IRTG(IR_EQ, IRT_PGC),
 	       REF_BASE,
 	       REF_BASE,
 	       emitir(IRT(IR_ADD, IRT_PGC), uref,
 	       emitir(IRT(IR_ADD, IRT_PGC), uref,
@@ -1792,12 +1793,21 @@ noconstify:
 	}
 	}
       }
       }
     }
     }
+    /* IR_UREFO+IRT_IGC is not checked for open-ness at runtime.
+    ** Always marked as a guard, since it might get promoted to IRT_PGC later.
+    */
+    uref = emitir(IRTG(IR_UREFO, tref_isgcv(val) ? IRT_PGC : IRT_IGC), fn, uv);
+    uref = tref_ref(uref);
     emitir(IRTG(IR_UGT, IRT_PGC),
     emitir(IRTG(IR_UGT, IRT_PGC),
 	   emitir(IRT(IR_SUB, IRT_PGC), uref, REF_BASE),
 	   emitir(IRT(IR_SUB, IRT_PGC), uref, REF_BASE),
 	   lj_ir_kintpgc(J, (J->baseslot + J->maxslot) * 8));
 	   lj_ir_kintpgc(J, (J->baseslot + J->maxslot) * 8));
   } else {
   } else {
+    /* If fn is constant, then so is the GCupval*, and the upvalue cannot
+    ** transition back to open, so no guard is required in this case.
+    */
+    IRType t = (tref_isk(fn) ? 0 : IRT_GUARD) | IRT_PGC;
+    uref = tref_ref(emitir(IRT(IR_UREFC, t), fn, uv));
     needbarrier = 1;
     needbarrier = 1;
-    uref = tref_ref(emitir(IRTG(IR_UREFC, IRT_PGC), fn, uv));
   }
   }
   if (val == 0) {  /* Upvalue load */
   if (val == 0) {  /* Upvalue load */
     IRType t = itype2irt(uvval(uvp));
     IRType t = itype2irt(uvval(uvp));

+ 5 - 2
libs/LuaJIT/src/lj_state.c

@@ -346,8 +346,11 @@ void LJ_FASTCALL lj_state_free(global_State *g, lua_State *L)
   lj_assertG(L != mainthread(g), "free of main thread");
   lj_assertG(L != mainthread(g), "free of main thread");
   if (obj2gco(L) == gcref(g->cur_L))
   if (obj2gco(L) == gcref(g->cur_L))
     setgcrefnull(g->cur_L);
     setgcrefnull(g->cur_L);
-  lj_func_closeuv(L, tvref(L->stack));
-  lj_assertG(gcref(L->openupval) == NULL, "stale open upvalues");
+  if (gcref(L->openupval) != NULL) {
+    lj_func_closeuv(L, tvref(L->stack));
+    lj_trace_abort(g);  /* For aa_uref soundness. */
+    lj_assertG(gcref(L->openupval) == NULL, "stale open upvalues");
+  }
   lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue);
   lj_mem_freevec(g, tvref(L->stack), L->stacksize, TValue);
   lj_mem_freet(g, L);
   lj_mem_freet(g, L);
 }
 }

+ 7 - 0
libs/LuaJIT/src/vm_arm.dasc

@@ -1195,8 +1195,11 @@ static void build_subroutines(BuildCtx *ctx)
   |//-- Base library: catch errors ----------------------------------------
   |//-- Base library: catch errors ----------------------------------------
   |
   |
   |.ffunc pcall
   |.ffunc pcall
+  |   ldr RB, L->maxstack
+  |   add INS, BASE, NARGS8:RC
   |  ldrb RA, [DISPATCH, #DISPATCH_GL(hookmask)]
   |  ldrb RA, [DISPATCH, #DISPATCH_GL(hookmask)]
   |   cmp NARGS8:RC, #8
   |   cmp NARGS8:RC, #8
+  |   cmphs RB, INS
   |   blo ->fff_fallback
   |   blo ->fff_fallback
   |  tst RA, #HOOK_ACTIVE		// Remember active hook before pcall.
   |  tst RA, #HOOK_ACTIVE		// Remember active hook before pcall.
   |   mov RB, BASE
   |   mov RB, BASE
@@ -1207,7 +1210,11 @@ static void build_subroutines(BuildCtx *ctx)
   |  b ->vm_call_dispatch
   |  b ->vm_call_dispatch
   |
   |
   |.ffunc_2 xpcall
   |.ffunc_2 xpcall
+  |   ldr RB, L->maxstack
+  |   add INS, BASE, NARGS8:RC
   |  ldrb RA, [DISPATCH, #DISPATCH_GL(hookmask)]
   |  ldrb RA, [DISPATCH, #DISPATCH_GL(hookmask)]
+  |   cmp RB, INS
+  |   blo ->fff_fallback
   |  checkfunc CARG4, ->fff_fallback	// Traceback must be a function.
   |  checkfunc CARG4, ->fff_fallback	// Traceback must be a function.
   |   mov RB, BASE
   |   mov RB, BASE
   |  strd CARG12, [BASE, #8]		// Swap function and traceback.
   |  strd CARG12, [BASE, #8]		// Swap function and traceback.

+ 8 - 0
libs/LuaJIT/src/vm_arm64.dasc

@@ -1211,6 +1211,10 @@ static void build_subroutines(BuildCtx *ctx)
   |//-- Base library: catch errors ----------------------------------------
   |//-- Base library: catch errors ----------------------------------------
   |
   |
   |.ffunc pcall
   |.ffunc pcall
+  |  ldr TMP1, L->maxstack
+  |  add TMP2, BASE, NARGS8:RC
+  |  cmp TMP1, TMP2
+  |  blo ->fff_fallback
   |   cmp NARGS8:RC, #8
   |   cmp NARGS8:RC, #8
   |  ldrb TMP0w, GL->hookmask
   |  ldrb TMP0w, GL->hookmask
   |   blo ->fff_fallback
   |   blo ->fff_fallback
@@ -1230,6 +1234,10 @@ static void build_subroutines(BuildCtx *ctx)
   |  b ->vm_call_dispatch
   |  b ->vm_call_dispatch
   |
   |
   |.ffunc xpcall
   |.ffunc xpcall
+  |  ldr TMP1, L->maxstack
+  |  add TMP2, BASE, NARGS8:RC
+  |  cmp TMP1, TMP2
+  |  blo ->fff_fallback
   |     ldp CARG1, CARG2, [BASE]
   |     ldp CARG1, CARG2, [BASE]
   |  ldrb TMP0w, GL->hookmask
   |  ldrb TMP0w, GL->hookmask
   |   subs NARGS8:TMP1, NARGS8:RC, #16
   |   subs NARGS8:TMP1, NARGS8:RC, #16

+ 9 - 1
libs/LuaJIT/src/vm_mips.dasc

@@ -1374,9 +1374,13 @@ static void build_subroutines(BuildCtx *ctx)
   |//-- Base library: catch errors ----------------------------------------
   |//-- Base library: catch errors ----------------------------------------
   |
   |
   |.ffunc pcall
   |.ffunc pcall
+  |   lw TMP1, L->maxstack
+  |   addu TMP2, BASE, NARGS8:RC
   |  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
   |  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
   |  beqz NARGS8:RC, ->fff_fallback
   |  beqz NARGS8:RC, ->fff_fallback
-  |   move TMP2, BASE
+  |.  sltu AT, TMP1, TMP2
+  |   bnez AT, ->fff_fallback
+  |.   move TMP2, BASE
   |   addiu BASE, BASE, 8
   |   addiu BASE, BASE, 8
   |  // Remember active hook before pcall.
   |  // Remember active hook before pcall.
   |  srl TMP3, TMP3, HOOK_ACTIVE_SHIFT
   |  srl TMP3, TMP3, HOOK_ACTIVE_SHIFT
@@ -1386,8 +1390,12 @@ static void build_subroutines(BuildCtx *ctx)
   |.  addiu NARGS8:RC, NARGS8:RC, -8
   |.  addiu NARGS8:RC, NARGS8:RC, -8
   |
   |
   |.ffunc xpcall
   |.ffunc xpcall
+  |   lw TMP1, L->maxstack
+  |   addu TMP2, BASE, NARGS8:RC
   |    sltiu AT, NARGS8:RC, 16
   |    sltiu AT, NARGS8:RC, 16
   |  lw CARG4, 8+HI(BASE)
   |  lw CARG4, 8+HI(BASE)
+  |   sltu TMP1, TMP1, TMP2
+  |    or AT, AT, TMP1
   |    bnez AT, ->fff_fallback
   |    bnez AT, ->fff_fallback
   |.  lw CARG3, 8+LO(BASE)
   |.  lw CARG3, 8+LO(BASE)
   |   lw CARG1, LO(BASE)
   |   lw CARG1, LO(BASE)

+ 10 - 2
libs/LuaJIT/src/vm_mips64.dasc

@@ -1415,8 +1415,12 @@ static void build_subroutines(BuildCtx *ctx)
   |//-- Base library: catch errors ----------------------------------------
   |//-- Base library: catch errors ----------------------------------------
   |
   |
   |.ffunc pcall
   |.ffunc pcall
+  |  ld TMP1, L->maxstack
+  |  daddu TMP2, BASE, NARGS8:RC
+  |  sltu AT, TMP1, TMP2
+  |  bnez AT, ->fff_fallback
+  |.  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
   |  daddiu NARGS8:RC, NARGS8:RC, -8
   |  daddiu NARGS8:RC, NARGS8:RC, -8
-  |  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
   |  bltz NARGS8:RC, ->fff_fallback
   |  bltz NARGS8:RC, ->fff_fallback
   |.   move TMP2, BASE
   |.   move TMP2, BASE
   |   daddiu BASE, BASE, 16
   |   daddiu BASE, BASE, 16
@@ -1437,8 +1441,12 @@ static void build_subroutines(BuildCtx *ctx)
   |.  nop
   |.  nop
   |
   |
   |.ffunc xpcall
   |.ffunc xpcall
+  |  ld TMP1, L->maxstack
+  |  daddu TMP2, BASE, NARGS8:RC
+  |  sltu AT, TMP1, TMP2
+  |  bnez AT, ->fff_fallback
+  |.  ld CARG1, 0(BASE)
   |  daddiu NARGS8:TMP0, NARGS8:RC, -16
   |  daddiu NARGS8:TMP0, NARGS8:RC, -16
-  |  ld CARG1, 0(BASE)
   |   ld CARG2, 8(BASE)
   |   ld CARG2, 8(BASE)
   |    bltz NARGS8:TMP0, ->fff_fallback
   |    bltz NARGS8:TMP0, ->fff_fallback
   |.    lbu TMP1, DISPATCH_GL(hookmask)(DISPATCH)
   |.    lbu TMP1, DISPATCH_GL(hookmask)(DISPATCH)

+ 9 - 0
libs/LuaJIT/src/vm_ppc.dasc

@@ -1735,8 +1735,12 @@ static void build_subroutines(BuildCtx *ctx)
   |//-- Base library: catch errors ----------------------------------------
   |//-- Base library: catch errors ----------------------------------------
   |
   |
   |.ffunc pcall
   |.ffunc pcall
+  |    lwz TMP1, L->maxstack
+  |    add TMP2, BASE, NARGS8:RC
   |  cmplwi NARGS8:RC, 8
   |  cmplwi NARGS8:RC, 8
   |   lbz TMP3, DISPATCH_GL(hookmask)(DISPATCH)
   |   lbz TMP3, DISPATCH_GL(hookmask)(DISPATCH)
+  |    cmplw cr1, TMP1, TMP2
+  |  cror 4*cr0+lt, 4*cr0+lt, 4*cr1+lt
   |  blt ->fff_fallback
   |  blt ->fff_fallback
   |   mr TMP2, BASE
   |   mr TMP2, BASE
   |   la BASE, 8(BASE)
   |   la BASE, 8(BASE)
@@ -1747,14 +1751,19 @@ static void build_subroutines(BuildCtx *ctx)
   |  b ->vm_call_dispatch
   |  b ->vm_call_dispatch
   |
   |
   |.ffunc xpcall
   |.ffunc xpcall
+  |     lwz TMP1, L->maxstack
+  |     add TMP2, BASE, NARGS8:RC
   |  cmplwi NARGS8:RC, 16
   |  cmplwi NARGS8:RC, 16
   |   lwz CARG3, 8(BASE)
   |   lwz CARG3, 8(BASE)
+  |     cmplw cr1, TMP1, TMP2
   |.if FPU
   |.if FPU
   |    lfd FARG2, 8(BASE)
   |    lfd FARG2, 8(BASE)
+  |  cror 4*cr0+lt, 4*cr0+lt, 4*cr1+lt
   |    lfd FARG1, 0(BASE)
   |    lfd FARG1, 0(BASE)
   |.else
   |.else
   |    lwz CARG1, 0(BASE)
   |    lwz CARG1, 0(BASE)
   |    lwz CARG2, 4(BASE)
   |    lwz CARG2, 4(BASE)
+  |  cror 4*cr0+lt, 4*cr0+lt, 4*cr1+lt
   |    lwz CARG4, 12(BASE)
   |    lwz CARG4, 12(BASE)
   |.endif
   |.endif
   |  blt ->fff_fallback
   |  blt ->fff_fallback

+ 6 - 0
libs/LuaJIT/src/vm_x64.dasc

@@ -1463,6 +1463,9 @@ static void build_subroutines(BuildCtx *ctx)
   |//-- Base library: catch errors ----------------------------------------
   |//-- Base library: catch errors ----------------------------------------
   |
   |
   |.ffunc_1 pcall
   |.ffunc_1 pcall
+  |  mov L:RB, SAVE_L
+  |  lea RA, [BASE+NARGS:RD*8]
+  |  cmp RA, L:RB->maxstack; ja ->fff_fallback
   |  lea RA, [BASE+16]
   |  lea RA, [BASE+16]
   |  sub NARGS:RDd, 1
   |  sub NARGS:RDd, 1
   |  mov PCd, 16+FRAME_PCALL
   |  mov PCd, 16+FRAME_PCALL
@@ -1481,6 +1484,9 @@ static void build_subroutines(BuildCtx *ctx)
   |  jmp ->vm_call_dispatch
   |  jmp ->vm_call_dispatch
   |
   |
   |.ffunc_2 xpcall
   |.ffunc_2 xpcall
+  |  mov L:RB, SAVE_L
+  |  lea RA, [BASE+NARGS:RD*8]
+  |  cmp RA, L:RB->maxstack; ja ->fff_fallback
   |  mov LFUNC:RA, [BASE+8]
   |  mov LFUNC:RA, [BASE+8]
   |  checktp_nc LFUNC:RA, LJ_TFUNC, ->fff_fallback
   |  checktp_nc LFUNC:RA, LJ_TFUNC, ->fff_fallback
   |  mov LFUNC:RB, [BASE]		// Swap function and traceback.
   |  mov LFUNC:RB, [BASE]		// Swap function and traceback.

+ 7 - 1
libs/LuaJIT/src/vm_x86.dasc

@@ -1369,7 +1369,7 @@ static void build_subroutines(BuildCtx *ctx)
   |  mov LFUNC:RB, [RA-8]
   |  mov LFUNC:RB, [RA-8]
   |  add NARGS:RD, 1
   |  add NARGS:RD, 1
   |  // This is fragile. L->base must not move, KBASE must always be defined.
   |  // This is fragile. L->base must not move, KBASE must always be defined.
-  |.if x64
+  |.if X64
   |  cmp KBASEa, rdx			// Continue with CALLT if flag set.
   |  cmp KBASEa, rdx			// Continue with CALLT if flag set.
   |.else
   |.else
   |  cmp KBASE, BASE			// Continue with CALLT if flag set.
   |  cmp KBASE, BASE			// Continue with CALLT if flag set.
@@ -1793,6 +1793,9 @@ static void build_subroutines(BuildCtx *ctx)
   |//-- Base library: catch errors ----------------------------------------
   |//-- Base library: catch errors ----------------------------------------
   |
   |
   |.ffunc_1 pcall
   |.ffunc_1 pcall
+  |  mov L:RB, SAVE_L
+  |  lea RA, [BASE+NARGS:RD*8]
+  |  cmp RA, L:RB->maxstack; ja ->fff_fallback
   |  lea RA, [BASE+8]
   |  lea RA, [BASE+8]
   |  sub NARGS:RD, 1
   |  sub NARGS:RD, 1
   |  mov PC, 8+FRAME_PCALL
   |  mov PC, 8+FRAME_PCALL
@@ -1804,6 +1807,9 @@ static void build_subroutines(BuildCtx *ctx)
   |  jmp ->vm_call_dispatch
   |  jmp ->vm_call_dispatch
   |
   |
   |.ffunc_2 xpcall
   |.ffunc_2 xpcall
+  |  mov L:RB, SAVE_L
+  |  lea RA, [BASE+NARGS:RD*8]
+  |  cmp RA, L:RB->maxstack; ja ->fff_fallback
   |  cmp dword [BASE+12], LJ_TFUNC;  jne ->fff_fallback
   |  cmp dword [BASE+12], LJ_TFUNC;  jne ->fff_fallback
   |  mov RB, [BASE+4]			// Swap function and traceback.
   |  mov RB, [BASE+4]			// Swap function and traceback.
   |  mov [BASE+12], RB
   |  mov [BASE+12], RB

+ 16 - 2
libs/SDL2/CMakeLists.txt

@@ -87,7 +87,7 @@ endif()
 # See docs/release_checklist.md
 # See docs/release_checklist.md
 set(SDL_MAJOR_VERSION 2)
 set(SDL_MAJOR_VERSION 2)
 set(SDL_MINOR_VERSION 28)
 set(SDL_MINOR_VERSION 28)
-set(SDL_MICRO_VERSION 4)
+set(SDL_MICRO_VERSION 5)
 set(SDL_VERSION "${SDL_MAJOR_VERSION}.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}")
 set(SDL_VERSION "${SDL_MAJOR_VERSION}.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}")
 
 
 # Set defaults preventing destination file conflicts
 # Set defaults preventing destination file conflicts
@@ -3089,9 +3089,17 @@ else()
   set(sdl_static_libname "SDL2")
   set(sdl_static_libname "SDL2")
 endif()
 endif()
 
 
-set(prefix ${CMAKE_INSTALL_PREFIX})
+# CMAKE_PREFIX_PATH and CMAKE_INSTALL_FULL_BINDIR can be a non-absolute path
+# when a master-project does e.g. `set(CMAKE_INSTALL_PREFIX "libs/SDL2" CACHE PATH "prefix" FORCE)`.
+if(NOT IS_ABSOLUTE "${CMAKE_INSTALL_PREFIX}")
+  set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_PREFIX}")
+endif()
+if(NOT IS_ABSOLUTE "${CMAKE_INSTALL_FULL_BINDIR}")
+  set(CMAKE_INSTALL_FULL_BINDIR "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_FULL_BINDIR}")
+endif()
 file(RELATIVE_PATH bin_prefix_relpath "${CMAKE_INSTALL_FULL_BINDIR}" "${CMAKE_INSTALL_PREFIX}")
 file(RELATIVE_PATH bin_prefix_relpath "${CMAKE_INSTALL_FULL_BINDIR}" "${CMAKE_INSTALL_PREFIX}")
 
 
+set(prefix ${CMAKE_INSTALL_PREFIX})
 set(exec_prefix "\${prefix}")
 set(exec_prefix "\${prefix}")
 set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
 set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
 set(bindir "\${exec_prefix}/${CMAKE_INSTALL_BINDIR}")
 set(bindir "\${exec_prefix}/${CMAKE_INSTALL_BINDIR}")
@@ -3335,6 +3343,12 @@ if(ANDROID)
 endif()
 endif()
 
 
 if(APPLE)
 if(APPLE)
+  cmake_push_check_state(RESET)
+  check_c_compiler_flag(-fobjc-arc COMPILER_SUPPORTS_FOBJC_ARC)
+  cmake_pop_check_state()
+  if(NOT COMPILER_SUPPORTS_FOBJC_ARC)
+    message(FATAL_ERROR "Compiler does not support -fobjc-arc: this is required on Apple platforms")
+  endif()
   target_compile_options(sdl-build-options INTERFACE "-fobjc-arc")
   target_compile_options(sdl-build-options INTERFACE "-fobjc-arc")
 endif()
 endif()
 
 

+ 1 - 1
libs/SDL2/Makefile.os2

@@ -15,7 +15,7 @@
 LIBNAME = SDL2
 LIBNAME = SDL2
 MAJOR_VERSION = 2
 MAJOR_VERSION = 2
 MINOR_VERSION = 28
 MINOR_VERSION = 28
-MICRO_VERSION = 4
+MICRO_VERSION = 5
 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 DESCRIPTION = Simple DirectMedia Layer 2
 DESCRIPTION = Simple DirectMedia Layer 2
 
 

+ 1 - 1
libs/SDL2/Makefile.w32

@@ -6,7 +6,7 @@
 LIBNAME = SDL2
 LIBNAME = SDL2
 MAJOR_VERSION = 2
 MAJOR_VERSION = 2
 MINOR_VERSION = 28
 MINOR_VERSION = 28
-MICRO_VERSION = 4
+MICRO_VERSION = 5
 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 
 
 LIBHOME = .
 LIBHOME = .

+ 1 - 1
libs/SDL2/SDL2.spec

@@ -1,6 +1,6 @@
 Summary: Simple DirectMedia Layer
 Summary: Simple DirectMedia Layer
 Name: SDL2
 Name: SDL2
-Version: 2.28.4
+Version: 2.28.5
 Release: 2
 Release: 2
 Source: http://www.libsdl.org/release/%{name}-%{version}.tar.gz
 Source: http://www.libsdl.org/release/%{name}-%{version}.tar.gz
 URL: http://www.libsdl.org/
 URL: http://www.libsdl.org/

+ 1 - 1
libs/SDL2/VERSION.txt

@@ -1 +1 @@
-release-2.28.4-0-gcc016b004
+release-2.28.5-0-g15ead9a40

+ 2 - 2
libs/SDL2/Xcode/SDL/Info-Framework.plist

@@ -19,10 +19,10 @@
 	<key>CFBundlePackageType</key>
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
 	<key>CFBundleShortVersionString</key>
-	<string>2.28.4</string>
+	<string>2.28.5</string>
 	<key>CFBundleSignature</key>
 	<key>CFBundleSignature</key>
 	<string>SDLX</string>
 	<string>SDLX</string>
 	<key>CFBundleVersion</key>
 	<key>CFBundleVersion</key>
-	<string>2.28.4</string>
+	<string>2.28.5</string>
 </dict>
 </dict>
 </plist>
 </plist>

+ 6 - 6
libs/SDL2/Xcode/SDL/SDL.xcodeproj/project.pbxproj

@@ -9529,7 +9529,7 @@
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEPLOYMENT_POSTPROCESSING = YES;
 				DEPLOYMENT_POSTPROCESSING = YES;
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
-				DYLIB_CURRENT_VERSION = 2801.4.0;
+				DYLIB_CURRENT_VERSION = 2801.5.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				GCC_ALTIVEC_EXTENSIONS = YES;
 				GCC_ALTIVEC_EXTENSIONS = YES;
@@ -9570,7 +9570,7 @@
 			isa = XCBuildConfiguration;
 			isa = XCBuildConfiguration;
 			buildSettings = {
 			buildSettings = {
 				CLANG_LINK_OBJC_RUNTIME = NO;
 				CLANG_LINK_OBJC_RUNTIME = NO;
-				MARKETING_VERSION = 2.28.4;
+				MARKETING_VERSION = 2.28.5;
 				OTHER_LDFLAGS = "-liconv";
 				OTHER_LDFLAGS = "-liconv";
 			};
 			};
 			name = Release;
 			name = Release;
@@ -9614,7 +9614,7 @@
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
-				DYLIB_CURRENT_VERSION = 2801.4.0;
+				DYLIB_CURRENT_VERSION = 2801.5.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
 				ENABLE_TESTABILITY = YES;
@@ -9656,7 +9656,7 @@
 			isa = XCBuildConfiguration;
 			isa = XCBuildConfiguration;
 			buildSettings = {
 			buildSettings = {
 				CLANG_LINK_OBJC_RUNTIME = NO;
 				CLANG_LINK_OBJC_RUNTIME = NO;
-				MARKETING_VERSION = 2.28.4;
+				MARKETING_VERSION = 2.28.5;
 				OTHER_LDFLAGS = "-liconv";
 				OTHER_LDFLAGS = "-liconv";
 			};
 			};
 			name = Debug;
 			name = Debug;
@@ -9863,7 +9863,7 @@
 				DEFINES_MODULE = YES;
 				DEFINES_MODULE = YES;
 				DEVELOPMENT_TEAM = "";
 				DEVELOPMENT_TEAM = "";
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
-				DYLIB_CURRENT_VERSION = 2801.4.0;
+				DYLIB_CURRENT_VERSION = 2801.5.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_DYNAMIC_NO_PIC = NO;
@@ -9915,7 +9915,7 @@
 				DEFINES_MODULE = YES;
 				DEFINES_MODULE = YES;
 				DEVELOPMENT_TEAM = "";
 				DEVELOPMENT_TEAM = "";
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
-				DYLIB_CURRENT_VERSION = 2801.4.0;
+				DYLIB_CURRENT_VERSION = 2801.5.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				ENABLE_NS_ASSERTIONS = NO;
 				ENABLE_NS_ASSERTIONS = NO;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_C_LANGUAGE_STANDARD = gnu11;

+ 1 - 1
libs/SDL2/Xcode/SDL/pkg-support/SDL.info

@@ -1,4 +1,4 @@
-Title SDL 2.28.4
+Title SDL 2.28.5
 Version 1
 Version 1
 Description SDL Library for Mac OS X (http://www.libsdl.org)
 Description SDL Library for Mac OS X (http://www.libsdl.org)
 DefaultLocation /Library/Frameworks
 DefaultLocation /Library/Frameworks

+ 1 - 0
libs/SDL2/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java

@@ -273,6 +273,7 @@ public class HIDDeviceManager {
         final int XB1_IFACE_SUBCLASS = 71;
         final int XB1_IFACE_SUBCLASS = 71;
         final int XB1_IFACE_PROTOCOL = 208;
         final int XB1_IFACE_PROTOCOL = 208;
         final int[] SUPPORTED_VENDORS = {
         final int[] SUPPORTED_VENDORS = {
+            0x03f0, // HP
             0x044f, // Thrustmaster
             0x044f, // Thrustmaster
             0x045e, // Microsoft
             0x045e, // Microsoft
             0x0738, // Mad Catz
             0x0738, // Mad Catz

+ 1 - 1
libs/SDL2/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java

@@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     private static final String TAG = "SDL";
     private static final String TAG = "SDL";
     private static final int SDL_MAJOR_VERSION = 2;
     private static final int SDL_MAJOR_VERSION = 2;
     private static final int SDL_MINOR_VERSION = 28;
     private static final int SDL_MINOR_VERSION = 28;
-    private static final int SDL_MICRO_VERSION = 4;
+    private static final int SDL_MICRO_VERSION = 5;
 /*
 /*
     // Display InputType.SOURCE/CLASS of events and devices
     // Display InputType.SOURCE/CLASS of events and devices
     //
     //

+ 1 - 1
libs/SDL2/configure

@@ -3507,7 +3507,7 @@ orig_CFLAGS="$CFLAGS"
 # See docs/release_checklist.md
 # See docs/release_checklist.md
 SDL_MAJOR_VERSION=2
 SDL_MAJOR_VERSION=2
 SDL_MINOR_VERSION=28
 SDL_MINOR_VERSION=28
-SDL_MICRO_VERSION=4
+SDL_MICRO_VERSION=5
 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
 
 
 SDL_BINARY_AGE=`expr $SDL_MINOR_VERSION \* 100 + $SDL_MICRO_VERSION`
 SDL_BINARY_AGE=`expr $SDL_MINOR_VERSION \* 100 + $SDL_MICRO_VERSION`

+ 1 - 1
libs/SDL2/configure.ac

@@ -13,7 +13,7 @@ dnl Set various version strings - taken gratefully from the GTk sources
 # See docs/release_checklist.md
 # See docs/release_checklist.md
 SDL_MAJOR_VERSION=2
 SDL_MAJOR_VERSION=2
 SDL_MINOR_VERSION=28
 SDL_MINOR_VERSION=28
-SDL_MICRO_VERSION=4
+SDL_MICRO_VERSION=5
 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
 
 
 SDL_BINARY_AGE=`expr $SDL_MINOR_VERSION \* 100 + $SDL_MICRO_VERSION`
 SDL_BINARY_AGE=`expr $SDL_MINOR_VERSION \* 100 + $SDL_MICRO_VERSION`

+ 2 - 2
libs/SDL2/include/SDL_revision.h

@@ -1,7 +1,7 @@
 /* Generated by updaterev.sh, do not edit */
 /* Generated by updaterev.sh, do not edit */
 #ifdef SDL_VENDOR_INFO
 #ifdef SDL_VENDOR_INFO
-#define SDL_REVISION "SDL-release-2.28.4-0-gcc016b004 (" SDL_VENDOR_INFO ")"
+#define SDL_REVISION "SDL-release-2.28.5-0-g15ead9a40 (" SDL_VENDOR_INFO ")"
 #else
 #else
-#define SDL_REVISION "SDL-release-2.28.4-0-gcc016b004"
+#define SDL_REVISION "SDL-release-2.28.5-0-g15ead9a40"
 #endif
 #endif
 #define SDL_REVISION_NUMBER 0
 #define SDL_REVISION_NUMBER 0

+ 1 - 1
libs/SDL2/include/SDL_version.h

@@ -59,7 +59,7 @@ typedef struct SDL_version
 */
 */
 #define SDL_MAJOR_VERSION   2
 #define SDL_MAJOR_VERSION   2
 #define SDL_MINOR_VERSION   28
 #define SDL_MINOR_VERSION   28
-#define SDL_PATCHLEVEL      4
+#define SDL_PATCHLEVEL      5
 
 
 /**
 /**
  * Macro to determine SDL version program was compiled against.
  * Macro to determine SDL version program was compiled against.

+ 2 - 2
libs/SDL2/src/audio/arts/SDL_artsaudio.c

@@ -300,12 +300,12 @@ static void ARTS_Deinitialize(void)
 }
 }
 
 
 
 
-static SDL_bool ARTS_Init(SDL_AudioDriverImpl * impl)
+static SDL_bool ARTS_Init(SDL_AudioDriverImpl *impl)
 {
 {
     if (LoadARTSLibrary() < 0) {
     if (LoadARTSLibrary() < 0) {
         return SDL_FALSE;
         return SDL_FALSE;
     } else {
     } else {
-        if (SDL_NAME(arts_init) () != NULL) {
+        if (SDL_NAME(arts_init) () != 0) {
             UnloadARTSLibrary();
             UnloadARTSLibrary();
             SDL_SetError("ARTS: arts_init failed (no audio server?)");
             SDL_SetError("ARTS: arts_init failed (no audio server?)");
             return SDL_FALSE;
             return SDL_FALSE;

+ 2 - 2
libs/SDL2/src/core/android/SDL_android.c

@@ -1939,12 +1939,12 @@ int Android_JNI_FileOpen(SDL_RWops *ctx,
     }
     }
 
 
     if (asset_manager == NULL) {
     if (asset_manager == NULL) {
-        return -1;
+        return SDL_SetError("Couldn't create asset manager");
     }
     }
 
 
     asset = AAssetManager_open(asset_manager, fileName, AASSET_MODE_UNKNOWN);
     asset = AAssetManager_open(asset_manager, fileName, AASSET_MODE_UNKNOWN);
     if (asset == NULL) {
     if (asset == NULL) {
-        return -1;
+        return SDL_SetError("Couldn't open asset '%s'", fileName);
     }
     }
 
 
     ctx->hidden.androidio.asset = (void *)asset;
     ctx->hidden.androidio.asset = (void *)asset;

+ 1 - 0
libs/SDL2/src/hidapi/libusb/hid.c

@@ -711,6 +711,7 @@ static int is_xboxone(unsigned short vendor_id, const struct libusb_interface_de
 	static const int XB1_IFACE_SUBCLASS = 71;
 	static const int XB1_IFACE_SUBCLASS = 71;
 	static const int XB1_IFACE_PROTOCOL = 208;
 	static const int XB1_IFACE_PROTOCOL = 208;
 	static const int SUPPORTED_VENDORS[] = {
 	static const int SUPPORTED_VENDORS[] = {
+        0x03f0, /* HP */
 		0x044f, /* Thrustmaster */
 		0x044f, /* Thrustmaster */
 		0x045e, /* Microsoft */
 		0x045e, /* Microsoft */
 		0x0738, /* Mad Catz */
 		0x0738, /* Mad Catz */

+ 4 - 0
libs/SDL2/src/joystick/SDL_joystick.c

@@ -2507,6 +2507,10 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
         MAKE_VIDPID(0x0eb7, 0x038e), /* Fanatec ClubSport Wheel Base V1 */
         MAKE_VIDPID(0x0eb7, 0x038e), /* Fanatec ClubSport Wheel Base V1 */
         MAKE_VIDPID(0x0eb7, 0x0e03), /* Fanatec CSL Elite Wheel Base */
         MAKE_VIDPID(0x0eb7, 0x0e03), /* Fanatec CSL Elite Wheel Base */
         MAKE_VIDPID(0x11ff, 0x0511), /* DragonRise Inc. Wired Wheel (initial mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) */
         MAKE_VIDPID(0x11ff, 0x0511), /* DragonRise Inc. Wired Wheel (initial mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) */
+        MAKE_VIDPID(0x2433, 0xf300), /* Asetek SimSports Invicta Wheelbase */
+        MAKE_VIDPID(0x2433, 0xf301), /* Asetek SimSports Forte Wheelbase */
+        MAKE_VIDPID(0x2433, 0xf303), /* Asetek SimSports La Prima Wheelbase */
+        MAKE_VIDPID(0x2433, 0xf306), /* Asetek SimSports Tony Kannan Wheelbase */
     };
     };
     int i;
     int i;
 
 

+ 1 - 0
libs/SDL2/src/joystick/controller_list.h

@@ -294,6 +294,7 @@ static const ControllerDescription_t arrControllers[] = {
 	{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafd ), k_eControllerType_XBox360Controller, NULL },	// Afterglow Gamepad 3
 	{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafd ), k_eControllerType_XBox360Controller, NULL },	// Afterglow Gamepad 3
 	{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafe ), k_eControllerType_XBox360Controller, NULL },	// Rock Candy Gamepad for Xbox 360
 	{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafe ), k_eControllerType_XBox360Controller, NULL },	// Rock Candy Gamepad for Xbox 360
 
 
+	{ MAKE_CONTROLLER_ID( 0x03f0, 0x0495 ), k_eControllerType_XBoxOneController, NULL },	// HP HyperX Clutch Gladiate
 	{ MAKE_CONTROLLER_ID( 0x044f, 0xd012 ), k_eControllerType_XBoxOneController, NULL },	// ThrustMaster eSwap PRO Controller Xbox
 	{ MAKE_CONTROLLER_ID( 0x044f, 0xd012 ), k_eControllerType_XBoxOneController, NULL },	// ThrustMaster eSwap PRO Controller Xbox
 	{ MAKE_CONTROLLER_ID( 0x045e, 0x02d1 ), k_eControllerType_XBoxOneController, "Xbox One Controller" },	// Microsoft X-Box One pad
 	{ MAKE_CONTROLLER_ID( 0x045e, 0x02d1 ), k_eControllerType_XBoxOneController, "Xbox One Controller" },	// Microsoft X-Box One pad
 	{ MAKE_CONTROLLER_ID( 0x045e, 0x02dd ), k_eControllerType_XBoxOneController, "Xbox One Controller" },	// Microsoft X-Box One pad (Firmware 2015)
 	{ MAKE_CONTROLLER_ID( 0x045e, 0x02dd ), k_eControllerType_XBoxOneController, "Xbox One Controller" },	// Microsoft X-Box One pad (Firmware 2015)

+ 7 - 0
libs/SDL2/src/joystick/hidapi/SDL_hidapijoystick.c

@@ -265,6 +265,7 @@ static SDL_GameControllerType SDL_GetJoystickGameControllerProtocol(const char *
         interface_protocol == XBONE_IFACE_PROTOCOL) {
         interface_protocol == XBONE_IFACE_PROTOCOL) {
 
 
         static const int SUPPORTED_VENDORS[] = {
         static const int SUPPORTED_VENDORS[] = {
+            0x03f0, /* HP */
             0x044f, /* Thrustmaster */
             0x044f, /* Thrustmaster */
             0x045e, /* Microsoft */
             0x045e, /* Microsoft */
             0x0738, /* Mad Catz */
             0x0738, /* Mad Catz */
@@ -1436,6 +1437,12 @@ static int HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index)
     device->updating = SDL_FALSE;
     device->updating = SDL_FALSE;
     SDL_UnlockMutex(device->dev_lock);
     SDL_UnlockMutex(device->dev_lock);
 
 
+    /* UpdateDevice() may have called HIDAPI_JoystickDisconnected() if the device went away */
+    if (device->num_joysticks == 0) {
+        SDL_free(hwdata);
+        return SDL_SetError("HIDAPI device disconnected while opening");
+    }
+
     if (!device->driver->OpenJoystick(device, joystick)) {
     if (!device->driver->OpenJoystick(device, joystick)) {
         /* The open failed, mark this device as disconnected and update devices */
         /* The open failed, mark this device as disconnected and update devices */
         HIDAPI_JoystickDisconnected(device, joystickID);
         HIDAPI_JoystickDisconnected(device, joystickID);

+ 4 - 4
libs/SDL2/src/main/windows/version.rc

@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 //
 
 
 VS_VERSION_INFO VERSIONINFO
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,28,4,0
- PRODUCTVERSION 2,28,4,0
+ FILEVERSION 2,28,5,0
+ PRODUCTVERSION 2,28,5,0
  FILEFLAGSMASK 0x3fL
  FILEFLAGSMASK 0x3fL
  FILEFLAGS 0x0L
  FILEFLAGS 0x0L
  FILEOS 0x40004L
  FILEOS 0x40004L
@@ -23,12 +23,12 @@ BEGIN
         BEGIN
         BEGIN
             VALUE "CompanyName", "\0"
             VALUE "CompanyName", "\0"
             VALUE "FileDescription", "SDL\0"
             VALUE "FileDescription", "SDL\0"
-            VALUE "FileVersion", "2, 28, 4, 0\0"
+            VALUE "FileVersion", "2, 28, 5, 0\0"
             VALUE "InternalName", "SDL\0"
             VALUE "InternalName", "SDL\0"
             VALUE "LegalCopyright", "Copyright (C) 2023 Sam Lantinga\0"
             VALUE "LegalCopyright", "Copyright (C) 2023 Sam Lantinga\0"
             VALUE "OriginalFilename", "SDL2.dll\0"
             VALUE "OriginalFilename", "SDL2.dll\0"
             VALUE "ProductName", "Simple DirectMedia Layer\0"
             VALUE "ProductName", "Simple DirectMedia Layer\0"
-            VALUE "ProductVersion", "2, 28, 4, 0\0"
+            VALUE "ProductVersion", "2, 28, 5, 0\0"
         END
         END
     END
     END
     BLOCK "VarFileInfo"
     BLOCK "VarFileInfo"

+ 13 - 8
libs/SDL2/src/render/software/SDL_triangle.c

@@ -789,15 +789,20 @@ static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info,
                 continue;
                 continue;
             }
             }
         }
         }
-        if (FORMAT_HAS_ALPHA(dstfmt_val)) {
-            DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA);
-        } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
-            DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB);
-            dstA = 0xFF;
+        if ((flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL))) {
+            if (FORMAT_HAS_ALPHA(dstfmt_val)) {
+                DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA);
+            } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
+                DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB);
+                dstA = 0xFF;
+            } else {
+                /* SDL_PIXELFORMAT_ARGB2101010 */
+                dstpixel = *((Uint32 *) (dst));
+                RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA);
+            }
         } else {
         } else {
-            /* SDL_PIXELFORMAT_ARGB2101010 */
-            dstpixel = *((Uint32 *)(dst));
-            RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA);
+            /* don't care */
+            dstR = dstG = dstB = dstA = 0;
         }
         }
 
 
         if (!is_uniform) {
         if (!is_uniform) {

+ 71 - 0
libs/SDL2/src/stdlib/SDL_string.c

@@ -1114,6 +1114,39 @@ int SDL_vsscanf(const char *text, const char *fmt, va_list ap)
     return vsscanf(text, fmt, ap);
     return vsscanf(text, fmt, ap);
 }
 }
 #else
 #else
+static SDL_bool CharacterMatchesSet(char c, const char *set, size_t set_len)
+{
+    SDL_bool invert = SDL_FALSE;
+    SDL_bool result = SDL_FALSE;
+
+    if (*set == '^') {
+        invert = SDL_TRUE;
+        ++set;
+        --set_len;
+    }
+    while (set_len > 0 && !result) {
+        if (set_len >= 3 && set[1] == '-') {
+            char low_char = SDL_min(set[0], set[2]);
+            char high_char = SDL_max(set[0], set[2]);
+            if (c >= low_char && c <= high_char) {
+                result = SDL_TRUE;
+            }
+            set += 3;
+            set_len -= 3;
+        } else {
+            if (c == *set) {
+                result = SDL_TRUE;
+            }
+            ++set;
+            --set_len;
+        }
+    }
+    if (invert) {
+        result = result ? SDL_FALSE : SDL_TRUE;
+    }
+    return result;
+}
+
 /* NOLINTNEXTLINE(readability-non-const-parameter) */
 /* NOLINTNEXTLINE(readability-non-const-parameter) */
 int SDL_vsscanf(const char *text, const char *fmt, va_list ap)
 int SDL_vsscanf(const char *text, const char *fmt, va_list ap)
 {
 {
@@ -1387,6 +1420,44 @@ int SDL_vsscanf(const char *text, const char *fmt, va_list ap)
                     }
                     }
                     done = SDL_TRUE;
                     done = SDL_TRUE;
                     break;
                     break;
+                case '[':
+                {
+                    const char *set = fmt + 1;
+                    while (*fmt && *fmt != ']') {
+                        ++fmt;
+                    }
+                    if (*fmt) {
+                        size_t set_len = (fmt - set);
+                        if (suppress) {
+                            while (CharacterMatchesSet(*text, set, set_len)) {
+                                ++text;
+                                if (count) {
+                                    if (--count == 0) {
+                                        break;
+                                    }
+                                }
+                            }
+                        } else {
+                            SDL_bool had_match = SDL_FALSE;
+                            char *valuep = va_arg(ap, char *);
+                            while (CharacterMatchesSet(*text, set, set_len)) {
+                                had_match = SDL_TRUE;
+                                *valuep++ = *text++;
+                                if (count) {
+                                    if (--count == 0) {
+                                        break;
+                                    }
+                                }
+                            }
+                            *valuep = '\0';
+                            if (had_match) {
+                                ++retval;
+                            }
+                        }
+                    }
+                }
+                    done = SDL_TRUE;
+                    break;
                 default:
                 default:
                     done = SDL_TRUE;
                     done = SDL_TRUE;
                     break;
                     break;

+ 3 - 1
libs/SDL2/src/test/SDL_test_fuzzer.c

@@ -471,7 +471,9 @@ char *SDLTest_RandomAsciiStringWithMaximumLength(int maxLength)
     }
     }
 
 
     size = (SDLTest_RandomUint32() % (maxLength + 1));
     size = (SDLTest_RandomUint32() % (maxLength + 1));
-
+    if (size == 0) {
+        size = 1;
+    }
     return SDLTest_RandomAsciiStringOfSize(size);
     return SDLTest_RandomAsciiStringOfSize(size);
 }
 }
 
 

+ 13 - 8
libs/SDL2/src/video/SDL_blit_slow.c

@@ -106,15 +106,20 @@ void SDL_Blit_Slow(SDL_BlitInfo *info)
                     continue;
                     continue;
                 }
                 }
             }
             }
-            if (FORMAT_HAS_ALPHA(dstfmt_val)) {
-                DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA);
-            } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
-                DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB);
-                dstA = 0xFF;
+            if ((flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL))) {
+                if (FORMAT_HAS_ALPHA(dstfmt_val)) {
+                    DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA);
+                } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
+                    DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB);
+                    dstA = 0xFF;
+                } else {
+                    /* SDL_PIXELFORMAT_ARGB2101010 */
+                    dstpixel = *((Uint32 *) (dst));
+                    RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA);
+                }
             } else {
             } else {
-                /* SDL_PIXELFORMAT_ARGB2101010 */
-                dstpixel = *((Uint32 *)(dst));
-                RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA);
+                /* don't care */
+                dstR = dstG = dstB = dstA = 0;
             }
             }
 
 
             if (flags & SDL_COPY_MODULATE_COLOR) {
             if (flags & SDL_COPY_MODULATE_COLOR) {

+ 1 - 0
libs/SDL2/src/video/android/SDL_androidevents.c

@@ -74,6 +74,7 @@ static void android_egl_context_restore(SDL_Window *window)
     if (window) {
     if (window) {
         SDL_Event event;
         SDL_Event event;
         SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
         SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+        SDL_GL_MakeCurrent(window, NULL);
         if (SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context) < 0) {
         if (SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context) < 0) {
             /* The context is no longer valid, create a new one */
             /* The context is no longer valid, create a new one */
             data->egl_context = (EGLContext)SDL_GL_CreateContext(window);
             data->egl_context = (EGLContext)SDL_GL_CreateContext(window);

+ 8 - 2
libs/SDL2/src/video/wayland/SDL_waylandevents.c

@@ -2534,6 +2534,10 @@ static void lock_pointer_to_window(SDL_Window *window,
     SDL_VideoData *d = input->display;
     SDL_VideoData *d = input->display;
     struct zwp_locked_pointer_v1 *locked_pointer;
     struct zwp_locked_pointer_v1 *locked_pointer;
 
 
+    if (!d->pointer_constraints || !input->pointer) {
+        return;
+    }
+
     if (w->locked_pointer) {
     if (w->locked_pointer) {
         return;
         return;
     }
     }
@@ -2621,8 +2625,10 @@ int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
         w->locked_pointer = NULL;
         w->locked_pointer = NULL;
     }
     }
 
 
-    zwp_relative_pointer_v1_destroy(input->relative_pointer);
-    input->relative_pointer = NULL;
+    if (input->relative_pointer) {
+        zwp_relative_pointer_v1_destroy(input->relative_pointer);
+        input->relative_pointer = NULL;
+    }
 
 
     d->relative_mouse_mode = 0;
     d->relative_mouse_mode = 0;
 
 

+ 10 - 16
libs/SDL2/src/video/wayland/SDL_waylandwindow.c

@@ -1322,21 +1322,15 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
     /* Create the shell surface and map the toplevel/popup */
     /* Create the shell surface and map the toplevel/popup */
 #ifdef HAVE_LIBDECOR_H
 #ifdef HAVE_LIBDECOR_H
     if (data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
     if (data->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
-        if (data->shell_surface.libdecor.frame) {
-            /* If the frame already exists, just set the visibility. */
-            libdecor_frame_set_visibility(data->shell_surface.libdecor.frame, true);
-            libdecor_frame_set_app_id(data->shell_surface.libdecor.frame, c->classname);
+        data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor,
+                                                               data->surface,
+                                                               &libdecor_frame_interface,
+                                                               data);
+        if (data->shell_surface.libdecor.frame == NULL) {
+            SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Failed to create libdecor frame!");
         } else {
         } else {
-            data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor,
-                                                                   data->surface,
-                                                                   &libdecor_frame_interface,
-                                                                   data);
-            if (data->shell_surface.libdecor.frame == NULL) {
-                SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Failed to create libdecor frame!");
-            } else {
-                libdecor_frame_set_app_id(data->shell_surface.libdecor.frame, c->classname);
-                libdecor_frame_map(data->shell_surface.libdecor.frame);
-            }
+            libdecor_frame_set_app_id(data->shell_surface.libdecor.frame, c->classname);
+            libdecor_frame_map(data->shell_surface.libdecor.frame);
         }
         }
     } else
     } else
 #endif
 #endif
@@ -1540,8 +1534,8 @@ void Wayland_HideWindow(_THIS, SDL_Window *window)
 #ifdef HAVE_LIBDECOR_H
 #ifdef HAVE_LIBDECOR_H
     if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
     if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
         if (wind->shell_surface.libdecor.frame) {
         if (wind->shell_surface.libdecor.frame) {
-            libdecor_frame_set_visibility(wind->shell_surface.libdecor.frame, false);
-            libdecor_frame_set_app_id(wind->shell_surface.libdecor.frame, data->classname);
+            libdecor_frame_unref(wind->shell_surface.libdecor.frame);
+            wind->shell_surface.libdecor.frame = NULL;
         }
         }
     } else
     } else
 #endif
 #endif

+ 11 - 18
libs/SDL2/src/video/x11/SDL_x11mouse.c

@@ -330,13 +330,16 @@ static void WarpMouseInternal(Window xwindow, const int x, const int y)
     Display *display = videodata->display;
     Display *display = videodata->display;
 #if SDL_VIDEO_DRIVER_X11_XINPUT2
 #if SDL_VIDEO_DRIVER_X11_XINPUT2
     int deviceid = 0;
     int deviceid = 0;
-    /* It seems XIWarpPointer() doesn't work correctly on multi-head setups:
-     * https://developer.blender.org/rB165caafb99c6846e53d11c4e966990aaffc06cea
-     */
-    if (ScreenCount(display) == 1) {
-        X11_XIGetClientPointer(display, None, &deviceid);
+    if (X11_Xinput2IsInitialized()) {
+        /* It seems XIWarpPointer() doesn't work correctly on multi-head setups:
+         * https://developer.blender.org/rB165caafb99c6846e53d11c4e966990aaffc06cea
+         */
+        if (ScreenCount(display) == 1) {
+            X11_XIGetClientPointer(display, None, &deviceid);
+        }
     }
     }
     if (deviceid != 0) {
     if (deviceid != 0) {
+        SDL_assert(SDL_X11_HAVE_XINPUT2);
         X11_XIWarpPointer(display, deviceid, None, xwindow, 0.0, 0.0, 0, 0, (double)x, (double)y);
         X11_XIWarpPointer(display, deviceid, None, xwindow, 0.0, 0.0, 0, 0, (double)x, (double)y);
     } else
     } else
 #endif
 #endif
@@ -369,14 +372,7 @@ static int X11_WarpMouseGlobal(int x, int y)
 
 
 static int X11_SetRelativeMouseMode(SDL_bool enabled)
 static int X11_SetRelativeMouseMode(SDL_bool enabled)
 {
 {
-#if SDL_VIDEO_DRIVER_X11_XINPUT2
-    if (X11_Xinput2IsInitialized()) {
-        return 0;
-    }
-#else
-    SDL_Unsupported();
-#endif
-    return -1;
+    return X11_Xinput2IsInitialized() ? 0 : SDL_Unsupported();
 }
 }
 
 
 static int X11_CaptureMouse(SDL_Window *window)
 static int X11_CaptureMouse(SDL_Window *window)
@@ -414,12 +410,9 @@ static Uint32 X11_GetGlobalMouseState(int *x, int *y)
 
 
     /* !!! FIXME: should we XSync() here first? */
     /* !!! FIXME: should we XSync() here first? */
 
 
-#if !SDL_VIDEO_DRIVER_X11_XINPUT2
-    videodata->global_mouse_changed = SDL_TRUE;
-#else
-    if (!SDL_X11_HAVE_XINPUT2)
+    if (!X11_Xinput2IsInitialized()) {
         videodata->global_mouse_changed = SDL_TRUE;
         videodata->global_mouse_changed = SDL_TRUE;
-#endif
+    }
 
 
     /* check if we have this cached since XInput last saw the mouse move. */
     /* check if we have this cached since XInput last saw the mouse move. */
     /* !!! FIXME: can we just calculate this from XInput's events? */
     /* !!! FIXME: can we just calculate this from XInput's events? */

+ 77 - 1
libs/SDL2/test/testautomation_stdlib.c

@@ -339,7 +339,7 @@ int stdlib_sscanf(void *arg)
     long long_output, expected_long_output;
     long long_output, expected_long_output;
     long long long_long_output, expected_long_long_output;
     long long long_long_output, expected_long_long_output;
     size_t size_output, expected_size_output;
     size_t size_output, expected_size_output;
-    char text[128];
+    char text[128], text2[128];
 
 
     expected_output = output = 123;
     expected_output = output = 123;
     expected_result = -1;
     expected_result = -1;
@@ -403,6 +403,82 @@ int stdlib_sscanf(void *arg)
     SDLTest_AssertCheck(expected_size_output == size_output, "Check output, expected: %zu, got: %zu", expected_size_output, size_output);
     SDLTest_AssertCheck(expected_size_output == size_output, "Check output, expected: %zu, got: %zu", expected_size_output, size_output);
     SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
     SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
 
 
+    expected_result = 1;
+    text[0] = '\0';
+    result = SDL_sscanf("abc def", "%s", text);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc def\", \"%%s\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "abc") == 0, "Check output, expected: \"abc\", got: \"%s\"", text);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
+    expected_result = 1;
+    text[0] = '\0';
+    result = SDL_sscanf("abc,def", "%s", text);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc,def\", \"%%s\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "abc,def") == 0, "Check output, expected: \"abc\", got: \"%s\"", text);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
+    expected_result = 1;
+    text[0] = '\0';
+    result = SDL_sscanf("abc,def", "%[cba]", text);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc,def\", \"%%[cba]\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "abc") == 0, "Check output, expected: \"abc\", got: \"%s\"", text);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
+    expected_result = 1;
+    text[0] = '\0';
+    result = SDL_sscanf("abc,def", "%[a-z]", text);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc,def\", \"%%[z-a]\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "abc") == 0, "Check output, expected: \"abc\", got: \"%s\"", text);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
+    expected_result = 1;
+    text[0] = '\0';
+    result = SDL_sscanf("abc,def", "%[^,]", text);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc,def\", \"%%[^,]\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "abc") == 0, "Check output, expected: \"abc\", got: \"%s\"", text);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
+    expected_result = 0;
+    text[0] = '\0';
+    result = SDL_sscanf("abc,def", "%[A-Z]", text);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc,def\", \"%%[A-Z]\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "") == 0, "Check output, expected: \"\", got: \"%s\"", text);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
+    expected_result = 2;
+    text[0] = '\0';
+    text2[0] = '\0';
+    result = SDL_sscanf("abc,def", "%[abc],%[def]", text, text2);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc,def\", \"%%[abc],%%[def]\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "abc") == 0, "Check output, expected: \"abc\", got: \"%s\"", text);
+    SDLTest_AssertCheck(SDL_strcmp(text2, "def") == 0, "Check output, expected: \"def\", got: \"%s\"", text2);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
+    expected_result = 2;
+    text[0] = '\0';
+    text2[0] = '\0';
+    result = SDL_sscanf("abc,def", "%[abc]%*[,]%[def]", text, text2);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc,def\", \"%%[abc]%%*[,]%%[def]\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "abc") == 0, "Check output, expected: \"abc\", got: \"%s\"", text);
+    SDLTest_AssertCheck(SDL_strcmp(text2, "def") == 0, "Check output, expected: \"def\", got: \"%s\"", text2);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
+    expected_result = 2;
+    text[0] = '\0';
+    text2[0] = '\0';
+    result = SDL_sscanf("abc   def", "%[abc] %[def]", text, text2);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc   def\", \"%%[abc] %%[def]\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "abc") == 0, "Check output, expected: \"abc\", got: \"%s\"", text);
+    SDLTest_AssertCheck(SDL_strcmp(text2, "def") == 0, "Check output, expected: \"def\", got: \"%s\"", text2);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
+    expected_result = 1;
+    text[0] = '\0';
+    result = SDL_sscanf("abc123XYZ", "%[a-zA-Z0-9]", text);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"abc123XYZ\", \"%%[a-zA-Z0-9]\", text)");
+    SDLTest_AssertCheck(SDL_strcmp(text, "abc123XYZ") == 0, "Check output, expected: \"abc123XYZ\", got: \"%s\"", text);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
     return TEST_COMPLETED;
     return TEST_COMPLETED;
 }
 }