Index: vm_x86.c
===================================================================
--- vm_x86.c	(revision 1972)
+++ vm_x86.c	(working copy)
@@ -107,6 +107,10 @@
 
 static	ELastCommand	LastCommand;
 
+static void ErrJump( void ) { Com_Error( ERR_DROP, "program tried to execute code outside VM\n" ); }
+
+static void (*const errJumpPtr)(void) = ErrJump;
+
 /*
 =================
 AsmCall
@@ -124,13 +128,21 @@
 	sub		edi, 4
 	test	eax,eax
 	jl		systemCall
+	cmp		eax, [callMask]
+	jae		badAddr
 	// calling another vm function
 	shl		eax,2
 	add		eax, dword ptr [instructionPointers]
 	call	dword ptr [eax]
 	mov		eax, dword ptr [edi]
-	and		eax, [callMask]
 	ret
+badAddr:
+	call	ErrJump
+	// leave something on the opstack
+	//add		edi, 4
+	//mov		dword ptr [edi], 0
+	//ret
+
 systemCall:
 
 	// convert negative num to system call number
@@ -212,12 +224,18 @@
 	"subl  $4, %edi\n\t"
 	"testl %eax, %eax\n\t"
 	"jl    0f\n\t"
+	"cmpl  " CMANGVAR(callMask) ", %eax\n\t"
+	"jae   1f\n\t"
 	"shll  $2, %eax\n\t"
 	"addl  " CMANGVAR(instructionPointers) ", %eax\n\t"
 	"call  *(%eax)\n\t"
 	"movl  (%edi), %eax\n\t"
-	"andl  " CMANGVAR(callMask) ", %eax\n\t"
 	"ret\n"
+	"1:\n\t" // bad address, leave something on the opstack
+	"call  " CMANGFUNC(ErrJump) "\n\t"
+	//"addl  $4, %edi\n\t"
+	//"movl  $0, (%edi)\n\t"
+	//"ret\n\t"
 	"0:\n\t" // system call
 	"notl  %eax\n\t"
 	"pushl %ebp\n\t"
@@ -249,6 +267,11 @@
 	return v;
 }
 
+static int	NextConstant4( void ) {
+	return (code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24));
+}
+
+
 static int	Constant1( void ) {
 	int		v;
 
@@ -424,6 +447,7 @@
 */
 void VM_Compile( vm_t *vm, vmHeader_t *header ) {
 	int		op;
+	int		op1;
 	int		maxLength;
 	int		v;
 	int		i;
@@ -434,9 +458,17 @@
 	maxLength = header->codeLength * 8;
 	buf = Z_Malloc(maxLength);
 	jused = Z_Malloc(jusedSize);
+	code = Z_Malloc(header->codeLength+32);
 	
 	Com_Memset(jused, 0, jusedSize);
+	Com_Memset(buf, 0, maxLength);
 
+	// copy code in larger buffer and put some zeros at the end
+	// so we can safely look ahead for a few instructions in it
+	// without a chance go get false-positive because of some garbage bytes
+	Com_Memset(code, 0, header->codeLength+32);
+	Com_Memcpy(code, (byte *)header + header->codeOffset, header->codeLength );
+
 	// ensure that the optimisation pass knows about all the jump
 	// table targets
 	for( i = 0; i < vm->numJumpTableTargets; i++ ) {
@@ -452,7 +484,7 @@
 	// translate all instructions
 	pc = 0;
 	instruction = 0;
-	code = (byte *)header + header->codeOffset;
+	//code = (byte *)header + header->codeOffset;
 	compiledOfs = 0;
 
 	LastCommand = LAST_COMMAND_NONE;
@@ -487,7 +519,14 @@
 			Emit4( Constant4() );
 			break;
 		case OP_CONST:
-			if (code[pc+4] == OP_LOAD4) {
+			// we can safely perform optimizations only in case if 
+			// we are 100% sure that next instruction is not a jump label
+			if ( !jused[instruction] && vm->jumpTableTargets )
+				op1 = code[pc+4];
+			else
+				op1 = OP_UNDEF;
+
+			if ( op1 == OP_LOAD4 ) {
 				EmitAddEDI4(vm);
 				EmitString( "BB" );		// mov	ebx, 0x12345678
 				Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
@@ -497,7 +536,7 @@
 				instruction += 1;
 				break;
 			}
-			if (code[pc+4] == OP_LOAD2) {
+			if ( op1 == OP_LOAD2 ) {
 				EmitAddEDI4(vm);
 				EmitString( "BB" );		// mov	ebx, 0x12345678
 				Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
@@ -507,7 +546,7 @@
 				instruction += 1;
 				break;
 			}
-			if (code[pc+4] == OP_LOAD1) {
+			if ( op1 == OP_LOAD1 ) {
 				EmitAddEDI4(vm);
 				EmitString( "BB" );		// mov	ebx, 0x12345678
 				Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase);
@@ -517,7 +556,7 @@
 				instruction += 1;
 				break;
 			}
-			if (code[pc+4] == OP_STORE4) {
+			if ( op1 == OP_STORE4 ) {
 				opt = EmitMovEBXEDI(vm, (vm->dataMask & ~3));
 				EmitString( "B8" );			// mov	eax, 0x12345678
 				Emit4( Constant4() );
@@ -532,7 +571,7 @@
 				instruction += 1;
 				break;
 			}
-			if (code[pc+4] == OP_STORE2) {
+			if ( op1 == OP_STORE2 ) {
 				opt = EmitMovEBXEDI(vm, (vm->dataMask & ~1));
 				EmitString( "B8" );			// mov	eax, 0x12345678
 				Emit4( Constant4() );
@@ -547,7 +586,7 @@
 				instruction += 1;
 				break;
 			}
-			if (code[pc+4] == OP_STORE1) {
+			if ( op1 == OP_STORE1 ) {
 				opt = EmitMovEBXEDI(vm, vm->dataMask);
 				EmitString( "B8" );			// mov	eax, 0x12345678
 				Emit4( Constant4() );
@@ -562,20 +601,117 @@
 				instruction += 1;
 				break;
 			}
-			if (code[pc+4] == OP_ADD) {
+			if ( op1 == OP_ADD ) {
+				v = NextConstant4();
+				if ( v == 1 ) {
+					EmitString( "FF 07" );	// inc dword ptr [edi]
+					pc += 5;				// OP_CONST + OP_ADD
+					instruction += 1;
+					break;
+				}
 				EmitString( "81 07" );		// add dword ptr [edi], 0x1234567
 				Emit4( Constant4() );
 				pc++;						// OP_ADD
 				instruction += 1;
 				break;
 			}
-			if (code[pc+4] == OP_SUB) {
+			if ( op1 == OP_SUB ) {
+				v = NextConstant4();
+				if ( v == 1 ) {
+					EmitString( "FF 0F" );	// dec dword ptr [edi]
+					pc += 5;				// OP_CONST + OP_SUB
+					instruction += 1;
+					break;
+				}
 				EmitString( "81 2F" );		// sub dword ptr [edi], 0x1234567
 				Emit4( Constant4() );
 				pc++;						// OP_ADD
 				instruction += 1;
 				break;
 			}
+			if ( op1 == OP_LSH ) {
+				v = NextConstant4();
+				if ( v >=1 && v <= 31 ) {
+					EmitString( "C1 27" );	// shl dword ptr [edi], 0x12
+					Emit1( v );
+					pc += 5;				// OP_CONST + OP_LSH
+					instruction += 1;
+					break;
+				}
+			}
+			if ( op1 == OP_RSHI ) {
+				v = NextConstant4();
+				if ( v >=1 && v <= 31 ) {
+					EmitString( "C1 3F" );	// sar dword ptr [edi], 0x12
+					Emit1( v );
+					pc += 5;				// OP_CONST + OP_RSHI
+					instruction += 1;
+					break;
+				}
+			}
+			if ( op1 == OP_RSHU ) {
+				v = NextConstant4();
+				if ( v >=1 && v <= 31 ) {
+					EmitString( "C1 2F" );	// shr dword ptr [edi], 0x12
+					Emit1( v );
+					pc += 5;				// OP_CONST + OP_RSHU
+					instruction += 1;
+					break;
+				}
+			}
+			if ( op1 == OP_BAND ) {
+				v = NextConstant4();
+				// try to generate shorter version
+				if ( v >= 0 && v <= 127 ) {
+					EmitString( "83 27" ); // and dword ptr[edi], 0x7F
+					Emit1( v );
+				} else {
+					EmitString( "81 27" ); // and dword ptr[edi], 0x7FFFF
+					Emit4( v );
+				}
+				pc += 5;				   // OP_CONST + OP_BAND
+				instruction += 1;
+				break;
+			}
+			if ( op1 == OP_BOR ) {
+				v = NextConstant4();
+				// try to generate shorter version
+				if ( v >= 0 && v <= 127 ) {
+					EmitString( "83 0F" ); // or dword ptr[edi], 0x7F
+					Emit1( v );
+				} else {
+					EmitString( "81 0F" ); // or dword ptr[edi], 0x7FFFF
+					Emit4( v );
+				}
+				pc += 5;				   // OP_CONST + OP_BOR
+				instruction += 1;
+				break;
+			}
+			if ( op1 == OP_JUMP ) {
+				v = Constant4();
+				JUSED(v);
+				EmitString( "FF 25" );    // jmp dword ptr [instructionPointers + 0x12345678]
+				Emit4( (int)vm->instructionPointers + v*4 );
+				pc += 1;                  // OP_JUMP
+				instruction += 1;
+				break;
+			}
+
+			if ( op1 == OP_CALL && NextConstant4() >= 0 ) {
+				v = Constant4();
+				JUSED(v);
+				// FIXME: not needed?
+				//EmitString( "C7 86" );    // mov dword ptr [esi+database],0x12345678
+				//Emit4( (int)vm->dataBase );
+				//Emit4( pc );
+				EmitString( "FF 15" );    // call dword ptr [instructionPointers + 0x12345678]
+				Emit4( (int)vm->instructionPointers + v*4 );
+				EmitString( "8B 07" );    // mov eax, dword ptr [edi]
+				pc += 1;                  // OP_CALL
+				instruction += 1;
+				break;
+			}
+
 			EmitAddEDI4(vm);
 			EmitString( "C7 07" );		// mov	dword ptr [edi], 0x12345678
 			lastConst = Constant4();
@@ -1076,11 +1212,15 @@
 			break;
 
 		case OP_JUMP:
-			EmitCommand(LAST_COMMAND_SUB_DI_4);		// sub edi, 4
-			EmitString( "8B 47 04" );	// mov eax,dword ptr [edi+4]
-			// FIXME: range check
-			EmitString( "FF 24 85" );	// jmp dword ptr [instructionPointers + eax * 4]
+			EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4
+			EmitString( "8B 47 04" );           // mov eax,dword ptr [edi+4]
+			EmitString( "3B 05" );              // cmp eax,[callMask]
+			Emit4( (int)&callMask );
+			EmitString( "73 07" );              // jae +7
+			EmitString( "FF 24 85" );           // jmp dword ptr [instructionPointers + eax * 4]
 			Emit4( (int)vm->instructionPointers );
+			EmitString( "FF 15" );              // call errJumpPtr
+			Emit4( (int)&errJumpPtr );
 			break;
 		default:
 		        VMFREE_BUFFERS();
@@ -1123,6 +1263,7 @@
 	}
 #endif
 
+	Z_Free( code );
 	Z_Free( buf );
 	Z_Free( jused );
 	Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs );
@@ -1161,8 +1302,10 @@
 	byte	*image;
 	void	*opStack;
 	int		*oldInstructionPointers;
+	int		oldCallMask;
 
 	oldInstructionPointers = instructionPointers;
+	oldCallMask	= callMask;
 
 	currentVM = vm;
 	instructionPointers = vm->instructionPointers;
@@ -1170,7 +1313,7 @@
 	// interpret the code
 	vm->currentlyInterpreting = qtrue;
 
-	callMask = vm->dataMask;
+	callMask = vm->instructionCount;
 
 	// we might be called recursively, so this might not be the very top
 	programStack = vm->programStack;
@@ -1241,6 +1384,7 @@
 
 	// in case we were recursively called by another vm
 	instructionPointers = oldInstructionPointers;
+	callMask = oldCallMask;
 
 	return *(int *)opStack;
 }