move insn_cache into cs_struct to gurantee thread-safe
diff --git a/arch/AArch64/mapping.c b/arch/AArch64/mapping.c
index 73ad300..3c77373 100644
--- a/arch/AArch64/mapping.c
+++ b/arch/AArch64/mapping.c
@@ -2991,18 +2991,16 @@
 	// { AArch64_SUBSxxx_lsl, ARM64_INS_NEGS, { 0 }, { ARM64_REG_NZCV, 0 }, { 0 } },
 };
 
-static unsigned short *insn_cache = NULL;
-
 // given internal insn id, return public instruction info
-void AArch64_get_insn_id(cs_insn *insn, unsigned int id, int detail)
+void AArch64_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
 {
-	int i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
+	int i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
 	if (i != 0) {
 		insn->id = insns[i].mapid;
 
-		if (detail) {
+		if (h->detail) {
 			cs_struct handle;
-			handle.detail = detail;
+			handle.detail = h->detail;
 
 			memcpy(insn->detail->regs_read, insns[i].regs_use, sizeof(insns[i].regs_use));
 			insn->detail->regs_read_count = count_positive(insns[i].regs_use);
@@ -3527,9 +3525,8 @@
 	return (i != -1)? i : ARM64_REG_INVALID;
 }
 
-void AArch64_free_cache(void)
+void AArch64_free_cache(cs_struct *h)
 {
-	my_free(insn_cache);
-
-	insn_cache = NULL;
+	my_free(h->insn_cache);
+	h->insn_cache = NULL;
 }
diff --git a/arch/AArch64/mapping.h b/arch/AArch64/mapping.h
index 4bcd40d..402ee83 100644
--- a/arch/AArch64/mapping.h
+++ b/arch/AArch64/mapping.h
@@ -11,7 +11,7 @@
 const char *AArch64_reg_name(csh handle, unsigned int reg);
 
 // given internal insn id, return public instruction info
-void AArch64_get_insn_id(cs_insn *insn, unsigned int id, int detail);
+void AArch64_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id);
 
 // given public insn id, return internal instruction ID
 unsigned int AArch64_get_insn_id2(unsigned int id);
@@ -22,6 +22,6 @@
 arm64_reg AArch64_map_insn(const char *name);
 
 // free insn cache
-void AArch64_free_cache(void);
+void AArch64_free_cache(cs_struct *h);
 
 #endif
diff --git a/arch/AArch64/module.c b/arch/AArch64/module.c
index 60f9654..9d28889 100644
--- a/arch/AArch64/module.c
+++ b/arch/AArch64/module.c
@@ -32,7 +32,7 @@
 
 static void destroy(cs_struct *handle)
 {
-	AArch64_free_cache();
+	AArch64_free_cache(handle);
 }
 
 static void __attribute__ ((constructor)) __init_arm64__()
diff --git a/arch/ARM/ARMInstPrinter.c b/arch/ARM/ARMInstPrinter.c
index e3f7d49..07ef651 100644
--- a/arch/ARM/ARMInstPrinter.c
+++ b/arch/ARM/ARMInstPrinter.c
@@ -563,7 +563,7 @@
 		// to reflect absolute address. 
 		// Note: in ARM, PC is always 2 instructions ahead, so we have to
 		// add 8 in ARM mode, or 4 in Thumb mode
-		if (ARM_rel_branch(MCInst_getOpcode(MI))) {
+		if (ARM_rel_branch(MI->csh, MCInst_getOpcode(MI))) {
 			// only do this for relative branch
 			if (MI->csh->mode & CS_MODE_THUMB)
 				imm += MI->address + 4;
diff --git a/arch/ARM/mapping.c b/arch/ARM/mapping.c
index 1a1e5d1..042fd8f 100644
--- a/arch/ARM/mapping.c
+++ b/arch/ARM/mapping.c
@@ -2301,17 +2301,15 @@
 };
 
 
-static unsigned short *insn_cache = NULL;
-
-void ARM_get_insn_id(cs_insn *insn, unsigned int id, int detail)
+void ARM_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
 {
-	int i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
+	int i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
 	if (i != 0) {
 		insn->id = insns[i].mapid;
 
-		if (detail) {
+		if (h->detail) {
 			cs_struct handle;
-			handle.detail = detail;
+			handle.detail = h->detail;
 
 			memcpy(insn->detail->regs_read, insns[i].regs_use, sizeof(insns[i].regs_use));
 			insn->detail->regs_read_count = count_positive(insns[i].regs_use);
@@ -2791,9 +2789,9 @@
 	return (i != -1)? i : ARM_REG_INVALID;
 }
 
-bool ARM_rel_branch(unsigned int id)
+bool ARM_rel_branch(cs_struct *h, unsigned int id)
 {
-	int i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
+	int i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
 	if (i != 0)
 		return (insns[i].branch && !insns[i].indirect_branch);
 	else {
@@ -2802,9 +2800,8 @@
 	}
 }
 
-void ARM_free_cache(void)
+void ARM_free_cache(cs_struct *h)
 {
-	my_free(insn_cache);
-
-	insn_cache = NULL;
+	my_free(h->insn_cache);
+	h->insn_cache = NULL;
 }
diff --git a/arch/ARM/mapping.h b/arch/ARM/mapping.h
index 62b8d92..4aebd1d 100644
--- a/arch/ARM/mapping.h
+++ b/arch/ARM/mapping.h
@@ -12,7 +12,7 @@
 const char *ARM_reg_name(csh handle, unsigned int reg);
 
 // given internal insn id, return public instruction ID
-void ARM_get_insn_id(cs_insn *insn, unsigned int id, int detail);
+void ARM_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id);
 
 // given public insn id, return internal instruction info
 unsigned int ARM_get_insn_id2(unsigned int id);
@@ -23,9 +23,9 @@
 arm_reg ARM_map_insn(const char *name);
 
 // check if this insn is relative branch
-bool ARM_rel_branch(unsigned int insn_id);
+bool ARM_rel_branch(cs_struct *h, unsigned int insn_id);
 
 // free insn cache
-void ARM_free_cache(void);
+void ARM_free_cache(cs_struct *h);
 
 #endif
diff --git a/arch/ARM/module.c b/arch/ARM/module.c
index e5f4131..dde4b5f 100644
--- a/arch/ARM/module.c
+++ b/arch/ARM/module.c
@@ -45,7 +45,7 @@
 
 static void destroy(cs_struct *handle)
 {
-	ARM_free_cache();
+	ARM_free_cache(handle);
 }
 
 static void __attribute__ ((constructor)) __init_arm__()
diff --git a/arch/Mips/mapping.c b/arch/Mips/mapping.c
index 3975da7..a2fa1ae 100644
--- a/arch/Mips/mapping.c
+++ b/arch/Mips/mapping.c
@@ -1388,10 +1388,8 @@
 	{ Mips_SUBu, MIPS_INS_NEGU, { 0 }, { 0 }, { MIPS_GRP_STDENC, 0 }, 0, 0 },
 };
 
-static unsigned short *insn_cache = NULL;
-
 // given internal insn id, return public instruction info
-void Mips_get_insn_id(cs_insn *insn, unsigned int id, int detail)
+void Mips_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
 {
 	int i;
 
@@ -1400,7 +1398,7 @@
 		if (alias_insns[i].id == id) {
 			insn->id = alias_insns[i].mapid;
 
-			if (detail) {
+			if (h->detail) {
 				memcpy(insn->detail->regs_read, alias_insns[i].regs_use, sizeof(alias_insns[i].regs_use));
 				insn->detail->regs_read_count = count_positive(alias_insns[i].regs_use);
 
@@ -1421,11 +1419,11 @@
 		}
 	}
 
-	i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
+	i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
 	if (i != 0) {
 		insn->id = insns[i].mapid;
 
-		if (detail) {
+		if (h->detail) {
 			memcpy(insn->detail->regs_read, insns[i].regs_use, sizeof(insns[i].regs_use));
 			insn->detail->regs_read_count = count_positive(insns[i].regs_use);
 
@@ -2035,9 +2033,8 @@
 	return 0;
 }
 
-void Mips_free_cache(void)
+void Mips_free_cache(cs_struct *h)
 {
-	my_free(insn_cache);
-
-	insn_cache = NULL;
+	my_free(h->insn_cache);
+	h->insn_cache = NULL;
 }
diff --git a/arch/Mips/mapping.h b/arch/Mips/mapping.h
index 7d9e74c..3c1eb2c 100644
--- a/arch/Mips/mapping.h
+++ b/arch/Mips/mapping.h
@@ -11,7 +11,7 @@
 const char *Mips_reg_name(csh handle, unsigned int reg);
 
 // given internal insn id, return public instruction info
-void Mips_get_insn_id(cs_insn *insn, unsigned int id, int detail);
+void Mips_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id);
 
 // given public insn id, return internal insn id
 unsigned int Mips_get_insn_id2(unsigned int id);
@@ -26,6 +26,6 @@
 mips_reg Mips_map_register(unsigned int r);
 
 // free insn cache
-void Mips_free_cache(void);
+void Mips_free_cache(cs_struct *h);
 
 #endif
diff --git a/arch/Mips/module.c b/arch/Mips/module.c
index 13fbd67..21c193f 100644
--- a/arch/Mips/module.c
+++ b/arch/Mips/module.c
@@ -43,7 +43,7 @@
 
 static void destroy(cs_struct *handle)
 {
-	Mips_free_cache();
+	Mips_free_cache(handle);
 }
 
 static void __attribute__ ((constructor)) __init_mips__()
diff --git a/arch/PowerPC/mapping.c b/arch/PowerPC/mapping.c
index f63331e..a61e6d2 100644
--- a/arch/PowerPC/mapping.c
+++ b/arch/PowerPC/mapping.c
@@ -917,10 +917,8 @@
 static insn_map alias_insns[] = {
 };
 
-static unsigned short *insn_cache = NULL;
-
 // given internal insn id, return public instruction info
-void PPC_get_insn_id(cs_insn *insn, unsigned int id, int detail)
+void PPC_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
 {
 	int i;
 
@@ -929,9 +927,9 @@
 		if (alias_insns[i].id == id) {
 			insn->id = alias_insns[i].mapid;
 
-			if (detail) {
+			if (h->detail) {
 				cs_struct handle;
-				handle.detail = detail;
+				handle.detail = h->detail;
 
 				memcpy(insn->detail->regs_read, alias_insns[i].regs_use, sizeof(alias_insns[i].regs_use));
 				insn->detail->regs_read_count = count_positive(alias_insns[i].regs_use);
@@ -954,13 +952,13 @@
 		}
 	}
 
-	i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
+	i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
 	if (i != 0) {
 		insn->id = insns[i].mapid;
 
-		if (detail) {
+		if (h->detail) {
 			cs_struct handle;
-			handle.detail = detail;
+			handle.detail = h->detail;
 
 			memcpy(insn->detail->regs_read, insns[i].regs_use, sizeof(insns[i].regs_use));
 			insn->detail->regs_read_count = count_positive(insns[i].regs_use);
@@ -1516,9 +1514,8 @@
 	return 0;
 }
 
-void PPC_free_cache(void)
+void PPC_free_cache(cs_struct *h)
 {
-	my_free(insn_cache);
-
-	insn_cache = NULL;
+	my_free(h->insn_cache);
+	h->insn_cache = NULL;
 }
diff --git a/arch/PowerPC/mapping.h b/arch/PowerPC/mapping.h
index 13c886b..0eb19d4 100644
--- a/arch/PowerPC/mapping.h
+++ b/arch/PowerPC/mapping.h
@@ -11,7 +11,7 @@
 const char *PPC_reg_name(csh handle, unsigned int reg);
 
 // given internal insn id, return public instruction info
-void PPC_get_insn_id(cs_insn *insn, unsigned int id, int detail);
+void PPC_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id);
 
 // given public insn id, return internal insn id
 unsigned int PPC_get_insn_id2(unsigned int id);
@@ -26,7 +26,7 @@
 ppc_reg PPC_map_register(unsigned int r);
 
 // free insn cache
-void PPC_free_cache(void);
+void PPC_free_cache(cs_struct *);
 
 #endif
 
diff --git a/arch/PowerPC/module.c b/arch/PowerPC/module.c
index 9ab6211..90f7fa7 100644
--- a/arch/PowerPC/module.c
+++ b/arch/PowerPC/module.c
@@ -36,7 +36,7 @@
 
 static void destroy(cs_struct *handle)
 {
-	PPC_free_cache();
+	PPC_free_cache(handle);
 }
 
 static void __attribute__ ((constructor)) __init_mips__()
diff --git a/arch/X86/mapping.c b/arch/X86/mapping.c
index eb0f6a1..953907d 100644
--- a/arch/X86/mapping.c
+++ b/arch/X86/mapping.c
@@ -6605,16 +6605,14 @@
 	}
 }
 
-static unsigned short *insn_cache = NULL;
-
 // given internal insn id, return public instruction info
-void X86_get_insn_id(cs_insn *insn, unsigned int id, int detail)
+void X86_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
 {
-	int i = insn_find(insns, ARR_SIZE(insns), id, &insn_cache);
+	int i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
 	if (i != 0) {
 		insn->id = insns[i].mapid;
 
-		if (detail) {
+		if (h->detail) {
 			memcpy(insn->detail->regs_read, insns[i].regs_use, sizeof(insns[i].regs_use));
 			insn->detail->regs_read_count = count_positive(insns[i].regs_use);
 
@@ -6639,8 +6637,8 @@
 	return insn_reverse_id(insns, ARR_SIZE(insns), id);
 }
 
-void X86_free_cache(void)
+void X86_free_cache(cs_struct *h)
 {
-	my_free(insn_cache);
-	insn_cache = NULL;
+	my_free(h->insn_cache);
+	h->insn_cache = NULL;
 }
diff --git a/arch/X86/mapping.h b/arch/X86/mapping.h
index 1065626..d164bb9 100644
--- a/arch/X86/mapping.h
+++ b/arch/X86/mapping.h
@@ -6,6 +6,7 @@
 
 #include "../../include/capstone.h"
 #include "../../include/x86.h"
+#include "../../cs_priv.h"
 
 // map sib_base to x86_reg
 x86_reg x86_map_sib_base(int r);
@@ -23,7 +24,7 @@
 const char *X86_reg_name(csh handle, unsigned int reg);
 
 // given internal insn id, return public instruction info
-void X86_get_insn_id(cs_insn *insn, unsigned int id, int detail);
+void X86_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id);
 
 // return insn name, given insn id
 const char *X86_insn_name(csh handle, unsigned int id);
@@ -38,6 +39,6 @@
 void X86_post_printer(csh handle, cs_insn *pub_insn, char *insn_asm);
 
 // free insn cache
-void X86_free_cache(void);
+void X86_free_cache(cs_struct *h);
 
 #endif
diff --git a/arch/X86/module.c b/arch/X86/module.c
index eab9f4c..428373a 100644
--- a/arch/X86/module.c
+++ b/arch/X86/module.c
@@ -46,7 +46,7 @@
 
 static void destroy(cs_struct *handle)
 {
-	X86_free_cache();
+	X86_free_cache(handle);
 }
 
 static void __attribute__ ((constructor)) __init_x86__()
diff --git a/bindings/python/test.py b/bindings/python/test.py
index 37555b1..4e911c2 100755
--- a/bindings/python/test.py
+++ b/bindings/python/test.py
@@ -28,7 +28,7 @@
         (CS_ARCH_ARM, CS_MODE_THUMB, THUMB_CODE, "THUMB", 0),
         (CS_ARCH_MIPS, CS_MODE_32 + CS_MODE_BIG_ENDIAN, MIPS_CODE, "MIPS-32 (Big-endian)", 0),
         (CS_ARCH_MIPS, CS_MODE_64+ CS_MODE_LITTLE_ENDIAN, MIPS_CODE2, "MIPS-64-EL (Little-endian)", 0),
-        (CS_ARCH_ARM64, CS_MODE_ARM, ARM64_CODE, "ARM-64", 0),
+       (CS_ARCH_ARM64, CS_MODE_ARM, ARM64_CODE, "ARM-64", 0),
         (CS_ARCH_PPC, CS_MODE_BIG_ENDIAN, PPC_CODE, "PPC-64", 0),
         )
 
diff --git a/cs.c b/cs.c
index 8ee19fe..5e424d7 100644
--- a/cs.c
+++ b/cs.c
@@ -138,8 +138,7 @@
 			return CS_ERR_HANDLE;
 	}
 
-	if (arch_destroy[ud->arch])
-		arch_destroy[ud->arch](ud);
+	arch_destroy[ud->arch](ud);
 
 	memset(ud, 0, sizeof(*ud));
 	my_free(ud);
@@ -174,7 +173,7 @@
 
 	// map internal instruction opcode to public insn ID
 	if (handle->insn_id)
-		handle->insn_id(insn, MCInst_getOpcode(mci), handle->detail);
+		handle->insn_id(handle, insn, MCInst_getOpcode(mci));
 
 	// alias instruction might have ID saved in OpcodePub
 	if (MCInst_getOpcodePub(mci))
diff --git a/cs_priv.h b/cs_priv.h
index 56b98a4..eb7e379 100644
--- a/cs_priv.h
+++ b/cs_priv.h
@@ -19,7 +19,7 @@
 
 typedef const char *(*GetName_t)(csh handle, unsigned int reg);
 
-typedef void (*GetID_t)(cs_insn *insn, unsigned int id, int detail);
+typedef void (*GetID_t)(cs_struct *h, cs_insn *insn, unsigned int id);
 
 // for ARM only
 typedef struct ARM_ITStatus {
@@ -44,6 +44,7 @@
 	cs_opt_value detail;
 	int syntax;	// asm syntax for simple printer such as PPC
 	bool doing_mem;	// handling memory operand in InstPrinter code
+	unsigned short *insn_cache;	// index caching for mapping.c
 };
 
 #define MAX_ARCH 8