add PROTECT_RE mode for protect()
diff --git a/readme.md b/readme.md
index 04bbc94..9b8ab74 100644
--- a/readme.md
+++ b/readme.md
@@ -1,5 +1,5 @@
 
-Xbyak 5.65 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++
+Xbyak 5.66 ; JIT assembler for x86(IA32), x64(AMD64, x86-64) by C++
 =============
 
 Abstract
@@ -333,6 +333,7 @@
 
 History
 -------------
+* 2018/Jul/24 ver 5.66 add CodeArray::PROTECT_RE to mode of protect()
 * 2018/Jun/26 ver 5.65 fix push(qword [mem])
 * 2018/Mar/07 ver 5.64 fix zero division in Cpu() on some cpu
 * 2018/Feb/14 ver 5.63 fix Cpu::setCacheHierarchy() and fix EvexModifierZero for clang<3.9(thanks to mgouicem)
diff --git a/readme.txt b/readme.txt
index b1c15a2..4f17d00 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,5 +1,5 @@
 

-    C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.65

+    C++用x86(IA-32), x64(AMD64, x86-64) JITアセンブラ Xbyak 5.66

 

 -----------------------------------------------------------------------------

 ◎概要

@@ -343,6 +343,7 @@
 -----------------------------------------------------------------------------

 ◎履歴

 

+2018/07/24 ver 5.66 protect()のmodeにCodeArray::PROTECT_REを追加

 2018/06/26 ver 5.65 fix push(qword [mem])

 2018/03/07 ver 5.64 Cpu()の中でzero divisionが出ることがあるのを修正

 2018/02/14 ver 5.63 Cpu::setCacheHierarchy()の修正とclang<3.9のためのEvexModifierZero修正(thanks to mgouicem)

diff --git a/sample/static_buf.cpp b/sample/static_buf.cpp
index a2ef0e2..7cf8038 100644
--- a/sample/static_buf.cpp
+++ b/sample/static_buf.cpp
@@ -13,7 +13,6 @@
 	{
 		puts("generate");
 		printf("ptr=%p, %p\n", getCode(), buf);
-		Xbyak::CodeArray::protect(buf, sizeof(buf), true);
 #ifdef XBYAK32
 		mov(eax, ptr [esp + 4]);
 		add(eax, ptr [esp + 8]);
@@ -23,6 +22,11 @@
 		lea(rax, ptr [rdi + rsi]);
 #endif
 		ret();
+		Xbyak::CodeArray::protect(buf, sizeof(buf), Xbyak::CodeArray::PROTECT_RE);
+	}
+	~Code()
+	{
+		Xbyak::CodeArray::protect(buf, sizeof(buf), Xbyak::CodeArray::PROTECT_RW);
 	}
 } s_code;
 
diff --git a/sample/test0.cpp b/sample/test0.cpp
index e437092..eabd745 100644
--- a/sample/test0.cpp
+++ b/sample/test0.cpp
@@ -165,15 +165,15 @@
 			const size_t codeSize = 1024;
 			uint8 buf[codeSize + 16];
 			uint8 *p = CodeArray::getAlignedAddress(buf);
-			CodeArray::protect(p, codeSize, true);
 			Sample s(p, codeSize);
+			CodeArray::protect(p, codeSize, CodeArray::PROTECT_RE);
 			int (*func)(int) = s.getCode<int (*)(int)>();
 			if (Xbyak::CastTo<uint8*>(func) != p) {
 				fprintf(stderr, "internal error %p %p\n", p, Xbyak::CastTo<uint8*>(func));
 				return 1;
 			}
 			printf("0 + ... + %d = %d\n", 100, func(100));
-			CodeArray::protect(p, codeSize, false);
+			CodeArray::protect(p, codeSize, CodeArray::PROTECT_RW);
 		}
 		puts("OK");
 		testReset();
diff --git a/test/jmp.cpp b/test/jmp.cpp
index 79d5490..2578adb 100644
--- a/test/jmp.cpp
+++ b/test/jmp.cpp
@@ -1143,10 +1143,11 @@
 			ret();
 		}
 	} code;
-	Xbyak::CodeArray::protect(p, 4096, true);
+	Xbyak::CodeArray::protect(p, 4096, Xbyak::CodeArray::PROTECT_RE);
 	code.getCode<void (*)()>()();
 	CYBOZU_TEST_EQUAL(*x0, 123);
 	CYBOZU_TEST_EQUAL(*x1, 456);
 	CYBOZU_TEST_EQUAL(buf[8], 99);
+	Xbyak::CodeArray::protect(p, 4096, Xbyak::CodeArray::PROTECT_RW);
 }
 #endif
diff --git a/test/test_address.bat b/test/test_address.bat
index f96542f..f82c125 100644
--- a/test/test_address.bat
+++ b/test/test_address.bat
@@ -31,7 +31,7 @@
 echo cl -I../ -DXBYAK_TEST nm_frame.cpp %OPT% %OPT2%
 cl -I../ -DXBYAK_TEST nm_frame.cpp %OPT% %OPT2%
 nm_frame > x.lst
-diff x.lst ok.lst
+diff -w x.lst ok.lst
 wc x.lst
 
 :end
diff --git a/test/test_avx.bat b/test/test_avx.bat
index 5e51aa2..e40de15 100644
--- a/test/test_avx.bat
+++ b/test/test_avx.bat
@@ -38,5 +38,5 @@
 echo cl -I../ -DXBYAK_TEST nm_frame.cpp %OPT% %OPT2%
 cl -I../ -DXBYAK_TEST nm_frame.cpp %OPT% %OPT2%
 nm_frame |%FILTER% > x.lst
-diff x.lst ok.lst
+diff -w x.lst ok.lst
 wc x.lst
diff --git a/test/test_avx512.bat b/test/test_avx512.bat
index a49d562..5234146 100644
--- a/test/test_avx512.bat
+++ b/test/test_avx512.bat
@@ -27,5 +27,5 @@
 make_512 jit > nm.cpp
 cl -I../ -DXBYAK_TEST nm_frame.cpp %OPT% %OPT2% /DXBYAK_AVX512
 nm_frame |%FILTER% > x.lst
-diff x.lst ok.lst
+diff -w x.lst ok.lst
 wc x.lst
diff --git a/test/test_nm.bat b/test/test_nm.bat
index 32abfac..0d63b65 100644
--- a/test/test_nm.bat
+++ b/test/test_nm.bat
@@ -39,5 +39,5 @@
 make_nm jit > nm.cpp
 cl -I../ -DXBYAK_TEST nm_frame.cpp %OPT% %OPT2%
 nm_frame |%FILTER% > x.lst
-diff x.lst ok.lst
+diff -w x.lst ok.lst
 wc x.lst
diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h
index d703522..c33f085 100644
--- a/xbyak/xbyak.h
+++ b/xbyak/xbyak.h
@@ -105,7 +105,7 @@
 
 enum {
 	DEFAULT_MAX_CODE_SIZE = 4096,
-	VERSION = 0x5650 /* 0xABCD = A.BC(D) */
+	VERSION = 0x5660 /* 0xABCD = A.BC(D) */
 };
 
 #ifndef MIE_INTEGER_TYPE_DEFINED
@@ -848,10 +848,15 @@
 			uint64 disp = i->getVal(top_);
 			rewrite(i->codeOffset, disp, i->jmpSize);
 		}
-		if (alloc_->useProtect() && !protect(top_, size_, true)) throw Error(ERR_CANT_PROTECT);
+		if (alloc_->useProtect() && !protect(top_, size_, PROTECT_RWE)) throw Error(ERR_CANT_PROTECT);
 		isCalledCalcJmpAddress_ = true;
 	}
 public:
+	enum ProtectMode {
+		PROTECT_RW = 0, // read/write
+		PROTECT_RWE = 1, // read/write/exec
+		PROTECT_RE = 2 // read/exec
+	};
 	explicit CodeArray(size_t maxSize, void *userPtr = 0, Allocator *allocator = 0)
 		: type_(userPtr == AutoGrow ? AUTO_GROW : userPtr ? USER_BUF : ALLOC_BUF)
 		, alloc_(allocator ? allocator : (Allocator*)&defaultAllocator_)
@@ -861,7 +866,7 @@
 		, isCalledCalcJmpAddress_(false)
 	{
 		if (maxSize_ > 0 && top_ == 0) throw Error(ERR_CANT_ALLOC);
-		if ((type_ == ALLOC_BUF && alloc_->useProtect()) && !protect(top_, maxSize, true)) {
+		if ((type_ == ALLOC_BUF && alloc_->useProtect()) && !protect(top_, maxSize, PROTECT_RWE)) {
 			alloc_->free(top_);
 			throw Error(ERR_CANT_PROTECT);
 		}
@@ -869,7 +874,7 @@
 	virtual ~CodeArray()
 	{
 		if (isAllocType()) {
-			if (alloc_->useProtect()) protect(top_, maxSize_, false);
+			if (alloc_->useProtect()) protect(top_, maxSize_, PROTECT_RW);
 			alloc_->free(top_);
 		}
 	}
@@ -960,19 +965,36 @@
 		change exec permission of memory
 		@param addr [in] buffer address
 		@param size [in] buffer size
-		@param canExec [in] true(enable to exec), false(disable to exec)
+		@param protectMode [in] mode(RW/RWE/RE)
 		@return true(success), false(failure)
 	*/
-	static inline bool protect(const void *addr, size_t size, bool canExec)
+	static inline bool protect(const void *addr, size_t size, int protectMode)
 	{
-#if defined(_WIN32)
+#if defined(_MSC_VER)
+		const DWORD c_rw = PAGE_READWRITE;
+		const DWORD c_rwe = PAGE_EXECUTE_READWRITE;
+		const DWORD c_re = PAGE_EXECUTE_READ;
+		DWORD mode;
+#else
+		const int c_rw = PROT_READ | PROT_WRITE;
+		const int c_rwe = PROT_READ | PROT_WRITE | PROT_EXEC;
+		const int c_re = PROT_READ | PROT_EXEC;
+		int mode;
+#endif
+		switch (protectMode) {
+		case PROTECT_RW: mode = c_rw; break;
+		case PROTECT_RWE: mode = c_rwe; break;
+		case PROTECT_RE: mode = c_re; break;
+		default:
+			return false;
+		}
+#if defined(_MSC_VER)
 		DWORD oldProtect;
-		return VirtualProtect(const_cast<void*>(addr), size, canExec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldProtect) != 0;
+		return VirtualProtect(const_cast<void*>(addr), size, mode, &oldProtect) != 0;
 #elif defined(__GNUC__)
 		size_t pageSize = sysconf(_SC_PAGESIZE);
 		size_t iaddr = reinterpret_cast<size_t>(addr);
 		size_t roundAddr = iaddr & ~(pageSize - static_cast<size_t>(1));
-		int mode = PROT_READ | PROT_WRITE | (canExec ? PROT_EXEC : 0);
 		return mprotect(reinterpret_cast<void*>(roundAddr), size + (iaddr - roundAddr), mode) == 0;
 #else
 		return true;
diff --git a/xbyak/xbyak_mnemonic.h b/xbyak/xbyak_mnemonic.h
index fea242a..07dd8f3 100644
--- a/xbyak/xbyak_mnemonic.h
+++ b/xbyak/xbyak_mnemonic.h
@@ -1,4 +1,4 @@
-const char *getVersionString() const { return "5.65"; }
+const char *getVersionString() const { return "5.66"; }
 void adc(const Operand& op, uint32 imm) { opRM_I(op, imm, 0x10, 2); }
 void adc(const Operand& op1, const Operand& op2) { opRM_RM(op1, op2, 0x10); }
 void adcx(const Reg32e& reg, const Operand& op) { opGen(reg, op, 0xF6, 0x66, isREG32_REG32orMEM, NONE, 0x38); }