Spring Cleaning, Part Ichi (1)
Various minor things done to project files Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way) Updated regex project file and makefile --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401971
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
#(C)2004-2008 Metamod:Source Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
SRCDS = ~/srcds
|
||||
SMSDK = ../../..
|
||||
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
|
||||
OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing
|
||||
GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
DEBUG_FLAGS = -g -ggdb3
|
||||
CPP = gcc-4.1
|
||||
BINARY = sourcepawn.jit.x86.so
|
||||
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
|
||||
OBJECTS = dll_exports.cpp jit_x86.cpp opcode_helpers.cpp
|
||||
|
||||
LINK = -static-libgcc
|
||||
|
||||
INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn \
|
||||
-I$(SMSDK)/public/jit -I$(SMSDK)/public/jit/x86
|
||||
|
||||
ifeq "$(DEBUG)" "true"
|
||||
BIN_DIR = Debug
|
||||
CFLAGS = $(DEBUG_FLAGS)
|
||||
else
|
||||
BIN_DIR = Release
|
||||
CFLAGS = $(OPT_FLAGS)
|
||||
endif
|
||||
|
||||
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \
|
||||
-Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca \
|
||||
-Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fno-exceptions -fno-rtti \
|
||||
-DHAVE_STDINT_H -m32
|
||||
|
||||
ifeq "$(GCC_VERSION)" "4"
|
||||
CFLAGS += $(GCC4_FLAGS)
|
||||
endif
|
||||
|
||||
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
|
||||
|
||||
$(BIN_DIR)/%.o: %.cpp
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
all:
|
||||
mkdir -p $(BIN_DIR)
|
||||
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
|
||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
|
||||
$(MAKE) binary
|
||||
rm -rf $(BINARY)
|
||||
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
|
||||
|
||||
binary: $(OBJ_LINUX)
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
|
||||
debug:
|
||||
$(MAKE) all DEBUG=true
|
||||
|
||||
default: all
|
||||
|
||||
clean:
|
||||
rm -rf Release/*.o
|
||||
rm -rf Release/$(BINARY)
|
||||
rm -rf Debug/*.o
|
||||
rm -rf Debug/$(BINARY)
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
#include <malloc.h>
|
||||
#include "jit_x86.h"
|
||||
#include "dll_exports.h"
|
||||
|
||||
SourcePawn::ISourcePawnEngine *engine = NULL;
|
||||
JITX86 g_jit;
|
||||
|
||||
EXPORTFUNC int GiveEnginePointer2(SourcePawn::ISourcePawnEngine *engine_p, unsigned int api_version)
|
||||
{
|
||||
engine = engine_p;
|
||||
|
||||
if (api_version > SOURCEPAWN_ENGINE_API_VERSION || api_version < 2)
|
||||
{
|
||||
return SP_ERROR_PARAM;
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
EXPORTFUNC unsigned int GetExportCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXPORTFUNC SourcePawn::IVirtualMachine *GetExport(unsigned int exportnum)
|
||||
{
|
||||
/* Don't return anything if we're not initialized yet */
|
||||
if (!engine)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We only have one export - 0 */
|
||||
if (exportnum)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &g_jit;
|
||||
}
|
||||
|
||||
#if defined __linux__
|
||||
extern "C" void __cxa_pure_virtual(void)
|
||||
{
|
||||
}
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_
|
||||
|
||||
#include <sp_vm_base.h>
|
||||
|
||||
#if defined WIN32
|
||||
#define EXPORTFUNC extern "C" __declspec(dllexport)
|
||||
#elif defined __GNUC__
|
||||
#if __GNUC__ >= 3
|
||||
#define EXPORTFUNC extern "C" __attribute__((visibility("default")))
|
||||
#else
|
||||
#define EXPORTFUNC extern "C"
|
||||
#endif //__GNUC__ >= 3
|
||||
#endif //defined __GNUC__
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_DLL_H_
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_JIT_VERSION_H_
|
||||
#define _INCLUDE_JIT_VERSION_H_
|
||||
|
||||
#define SVN_FULL_VERSION "1.0.0.1919"
|
||||
#define SVN_FILE_VERSION 1,0,0,1919
|
||||
|
||||
#endif //_INCLUDE_JIT_VERSION_H_
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_JIT_VERSION_H_
|
||||
#define _INCLUDE_JIT_VERSION_H_
|
||||
|
||||
#define SVN_FULL_VERSION "$PMAJOR$.$PMINOR$.$PREVISION$.$LOCAL_BUILD$"
|
||||
#define SVN_FILE_VERSION $PMAJOR$,$PMINOR$,$PREVISION$,$LOCAL_BUILD$
|
||||
|
||||
#endif //_INCLUDE_JIT_VERSION_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_H_
|
||||
|
||||
#include <sp_vm_types.h>
|
||||
#include <sp_vm_api.h>
|
||||
#include <jit_helpers.h>
|
||||
|
||||
using namespace SourcePawn;
|
||||
|
||||
#define JIT_INLINE_ERRORCHECKS (1<<0)
|
||||
#define JIT_INLINE_NATIVES (1<<1)
|
||||
#define STACK_MARGIN 64 //8 parameters of safety, I guess
|
||||
#define JIT_FUNCMAGIC 0x214D4148 //magic function offset
|
||||
|
||||
#define JITVARS_TRACKER 0 //important: don't change this to avoid trouble
|
||||
#define JITVARS_FUNCINFO 1 //important: don't change this aWOAWOGJQG I LIKE HAM
|
||||
#define JITVARS_REBASE 2 //important: hi, i'm bail
|
||||
|
||||
#define sDIMEN_MAX 5 //this must mirror what the compiler has.
|
||||
|
||||
typedef struct tracker_s
|
||||
{
|
||||
size_t size;
|
||||
ucell_t *pBase;
|
||||
ucell_t *pCur;
|
||||
} tracker_t;
|
||||
|
||||
typedef struct funcinfo_s
|
||||
{
|
||||
unsigned int magic;
|
||||
unsigned int index;
|
||||
} funcinfo_t;
|
||||
|
||||
typedef struct functracker_s
|
||||
{
|
||||
unsigned int num_functions;
|
||||
unsigned int code_size;
|
||||
} functracker_t;
|
||||
|
||||
struct floattbl_t
|
||||
{
|
||||
floattbl_t()
|
||||
{
|
||||
found = false;
|
||||
index = 0;
|
||||
}
|
||||
bool found;
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
class CompData : public ICompilation
|
||||
{
|
||||
public:
|
||||
CompData() : plugin(NULL),
|
||||
debug(false), profile(0), inline_level(0), rebase(NULL),
|
||||
error_set(SP_ERROR_NONE), func_idx(0)
|
||||
{
|
||||
};
|
||||
public:
|
||||
sp_plugin_t *plugin; /* plugin handle */
|
||||
bool debug; /* whether to compile debug mode */
|
||||
int profile; /* profiling flags */
|
||||
int inline_level; /* inline optimization level */
|
||||
jitcode_t rebase; /* relocation map */
|
||||
int error_set; /* error code to halt process */
|
||||
unsigned int func_idx; /* current function index */
|
||||
jitoffs_t jit_return; /* point in main call to return to */
|
||||
jitoffs_t jit_verify_addr_eax;
|
||||
jitoffs_t jit_verify_addr_edx;
|
||||
jitoffs_t jit_break; /* call to op.break */
|
||||
jitoffs_t jit_sysreq_n; /* call version of op.sysreq.n */
|
||||
jitoffs_t jit_genarray; /* call to genarray intrinsic */
|
||||
jitoffs_t jit_error_bounds;
|
||||
jitoffs_t jit_error_divzero;
|
||||
jitoffs_t jit_error_stacklow;
|
||||
jitoffs_t jit_error_stackmin;
|
||||
jitoffs_t jit_error_memaccess;
|
||||
jitoffs_t jit_error_heaplow;
|
||||
jitoffs_t jit_error_heapmin;
|
||||
jitoffs_t jit_error_array_too_big;
|
||||
jitoffs_t jit_extern_error; /* returning generic error */
|
||||
jitoffs_t jit_sysreq_c; /* old version! */
|
||||
jitoffs_t jit_rounding_table;
|
||||
floattbl_t *jit_float_table;
|
||||
uint32_t codesize; /* total codesize */
|
||||
};
|
||||
|
||||
class JITX86 : public IVirtualMachine
|
||||
{
|
||||
public:
|
||||
const char *GetVMName();
|
||||
ICompilation *StartCompilation(sp_plugin_t *plugin);
|
||||
bool SetCompilationOption(ICompilation *co, const char *key, const char *val);
|
||||
sp_context_t *CompileToContext(ICompilation *co, int *err);
|
||||
void AbortCompilation(ICompilation *co);
|
||||
void FreeContext(sp_context_t *ctx);
|
||||
int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result);
|
||||
unsigned int GetAPIVersion();
|
||||
bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result);
|
||||
bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result);
|
||||
unsigned int FunctionCount(const sp_context_t *ctx);
|
||||
const char *GetVersionString();
|
||||
const char *GetCPUOptimizations();
|
||||
SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
|
||||
void DestroyFakeNative(SPVM_NATIVE_FUNC func);
|
||||
};
|
||||
|
||||
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
|
||||
cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
|
||||
cell_t NativeCallback_Debug_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
|
||||
cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
|
||||
jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false);
|
||||
|
||||
#define AMX_REG_PRI REG_EAX
|
||||
#define AMX_REG_ALT REG_EDX
|
||||
#define AMX_REG_STK REG_EDI
|
||||
#define AMX_REG_DAT REG_EBP
|
||||
#define AMX_REG_TMP REG_ECX
|
||||
#define AMX_REG_INFO REG_ESI
|
||||
#define AMX_REG_FRM REG_EBX
|
||||
|
||||
#define AMX_INFO_FRM AMX_REG_INFO //not relocated
|
||||
#define AMX_INFO_FRAME 0 //(same thing as above)
|
||||
#define AMX_INFO_HEAP 4 //not relocated
|
||||
#define AMX_INFO_RETVAL 8 //physical
|
||||
#define AMX_INFO_CONTEXT 12 //physical
|
||||
#define AMX_INFO_STACKTOP 16 //relocated
|
||||
|
||||
extern ISourcePawnEngine *engine;
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jit-x86", "jit-x86.vcproj", "{6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,296 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="jit-x86"
|
||||
ProjectGUID="{6EF06E6E-0ED5-4E2D-A8F3-01DD1EC25BA7}"
|
||||
RootNamespace="jitx86"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\..\..\public\jit;..\..\..\..\public\jit\x86;..\..\..\..\public\sourcepawn"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;JITX86_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
EnableEnhancedInstructionSet="0"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\sourcepawn.jit.x86.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="LIBC;LIBCD;LIBCMT"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
FavorSizeOrSpeed="1"
|
||||
AdditionalIncludeDirectories="..\..\..\..\public\jit;..\..\..\..\public\jit\x86;..\..\..\..\public\sourcepawn"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;JITX86_EXPORTS"
|
||||
RuntimeLibrary="0"
|
||||
EnableEnhancedInstructionSet="0"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\sourcepawn.jit.x86.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="LIBC;LIBCD;LIBCMTD"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\dll_exports.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\jit_x86.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\opcode_helpers.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\dll_exports.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\public\jit\jit_helpers.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\jit_version.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\jit_x86.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\opcode_helpers.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ungen_opcodes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\public\jit\x86\x86_macros.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\jit_version.tpl"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\opcode_switch.inc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ungen_opcode_switch.inc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\version.rc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="SDK"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\jit_helpers.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\public\sourcepawn\sp_file_headers.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\public\sourcepawn\sp_typeutil.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\public\sourcepawn\sp_vm_api.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\public\sourcepawn\sp_vm_base.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\public\sourcepawn\sp_vm_types.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -0,0 +1,893 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include "jit_x86.h"
|
||||
#include "opcode_helpers.h"
|
||||
#include "x86_macros.h"
|
||||
|
||||
#define NUM_INFO_PARAMS 5
|
||||
|
||||
jitoffs_t Write_Execute_Function(JitWriter *jit)
|
||||
{
|
||||
/**
|
||||
* The variables we're passed in:
|
||||
* sp_context_t *ctx, uint32_t code_idx, cell_t *result
|
||||
*/
|
||||
|
||||
/**
|
||||
* !NOTE!
|
||||
* Currently, we do not accept ctx->frm as the new frame pointer.
|
||||
* Instead, we copy the frame from the stack pointer.
|
||||
* This is because we do not support resuming or sleeping!
|
||||
*/
|
||||
|
||||
//push ebp
|
||||
//mov ebp, esp
|
||||
IA32_Push_Reg(jit, REG_EBP);
|
||||
IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
|
||||
|
||||
//push esi
|
||||
//push edi
|
||||
//push ebx
|
||||
IA32_Push_Reg(jit, REG_ESI);
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
|
||||
//sub esp, 4*n - reserve info array
|
||||
//mov esi, esp - save info pointer
|
||||
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_INFO, REG_ESP, MOD_REG);
|
||||
|
||||
/* Initial memory setup */
|
||||
//mov eax, [ebp+16] - get result pointer
|
||||
//mov [esi+8], eax - store into info pointer
|
||||
//mov eax, [ebp+8] - get context
|
||||
//mov [esi+12], eax - store context into info pointer
|
||||
//mov ecx, [eax+<offs>] - get heap pointer
|
||||
//mov [esi+4], ecx - store heap into info pointer
|
||||
//mov ebp, [eax+<offs>] - get data pointer
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, memory));
|
||||
|
||||
/* Frame setup */
|
||||
//mov edi, [eax+<offs>] - get stack pointer
|
||||
//add edi, ebp - relocate to data section
|
||||
//mov ebx, edi - copy sp to frm
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_STK, REG_EAX, offsetof(sp_context_t, sp));
|
||||
IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG);
|
||||
|
||||
/* Info memory setup */
|
||||
//mov ecx, [eax+<offs>] - copy memsize to temp var
|
||||
//add ecx, ebp - relocate
|
||||
//mov [esi+x], ecx - store relocated
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, mem_size));
|
||||
IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP);
|
||||
|
||||
/* Remaining needed vars */
|
||||
//mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack)
|
||||
//add ecx, [eax+<offs>] - add code base to index
|
||||
IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3)));
|
||||
IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase));
|
||||
|
||||
/* by now, everything is set up, so we can call into the plugin */
|
||||
//call ecx
|
||||
IA32_Call_Reg(jit, REG_ECX);
|
||||
|
||||
/* if the code flow gets to here, there was a normal return */
|
||||
//mov ecx, [esi+8] - get retval pointer
|
||||
//mov [ecx], eax - store retval from PRI
|
||||
//mov eax, SP_ERROR_NONE - set no error
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL);
|
||||
IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERROR_NONE);
|
||||
|
||||
/* save where error checking/halting functions should go to */
|
||||
jitoffs_t offs_return = jit->get_outputpos();
|
||||
//mov esp, esi - restore stack pointer
|
||||
IA32_Mov_Reg_Rm(jit, REG_ESP, REG_ESI, MOD_REG);
|
||||
|
||||
/* _FOR NOW_ ...
|
||||
* We are going to restore SP, HP, and FRM for now. This is for
|
||||
* debugging only, to check for alignment errors. As such:
|
||||
* :TODO: probably remove this.
|
||||
*/
|
||||
//mov ecx, [esi+context]
|
||||
//sub edi, ebp
|
||||
//mov edx, [esi+heap]
|
||||
//mov [ecx+sp], edi
|
||||
//mov [ecx+hp], edx
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT);
|
||||
IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_HEAP);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp));
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDX, offsetof(sp_context_t, hp));
|
||||
|
||||
//add esp, 4*NUM_INFO_PARAMS
|
||||
//pop ebx
|
||||
//pop edi
|
||||
//pop esi
|
||||
//pop ebp
|
||||
//ret
|
||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*NUM_INFO_PARAMS, MOD_REG);
|
||||
IA32_Pop_Reg(jit, REG_EBX);
|
||||
IA32_Pop_Reg(jit, REG_EDI);
|
||||
IA32_Pop_Reg(jit, REG_ESI);
|
||||
IA32_Pop_Reg(jit, REG_EBP);
|
||||
IA32_Return(jit);
|
||||
|
||||
return offs_return;
|
||||
}
|
||||
|
||||
void Write_BreakDebug(JitWriter *jit)
|
||||
{
|
||||
//push edi
|
||||
//mov edi, ecx
|
||||
//mov ecx, [esi+ctx]
|
||||
//cmp [ecx+dbreak], 0
|
||||
//jnz :nocall
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Mov_Reg_Rm(jit, REG_EDI, REG_ECX, MOD_REG);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0);
|
||||
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_Z, 0);
|
||||
|
||||
//:TODO: align the stack to 16bytes like in sysreq.x
|
||||
/* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */
|
||||
//pushad
|
||||
//push [esi+frm]
|
||||
//push ctx
|
||||
//mov ecx, [ecx+dbreak]
|
||||
//call ecx
|
||||
//add esp, 8
|
||||
//popad
|
||||
IA32_Pushad(jit);
|
||||
IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
|
||||
IA32_Push_Reg(jit, AMX_REG_TMP);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak));
|
||||
IA32_Call_Reg(jit, AMX_REG_TMP);
|
||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
|
||||
IA32_Popad(jit);
|
||||
|
||||
//:nocall
|
||||
//pop edi
|
||||
//ret
|
||||
IA32_Pop_Reg(jit, REG_EDI);
|
||||
IA32_Send_Jump8_Here(jit, jmp);
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
void Write_GetError(JitWriter *jit)
|
||||
{
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
//mov eax, [esi+info.context]
|
||||
//mov eax, [eax+ctx.error]
|
||||
//jmp [jit_return]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err));
|
||||
IA32_Jump_Imm32_Abs(jit, data->jit_return);
|
||||
}
|
||||
|
||||
void Write_SetError(JitWriter *jit, int error)
|
||||
{
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
//mov eax, <error>
|
||||
//jmp [jit_return]
|
||||
IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
|
||||
IA32_Jump_Imm32_Abs(jit, data->jit_return);
|
||||
}
|
||||
|
||||
void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
|
||||
{
|
||||
//test reg, reg
|
||||
//jz :error
|
||||
IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
|
||||
}
|
||||
|
||||
void Write_CheckHeap_Min(JitWriter *jit)
|
||||
{
|
||||
/* Check if the stack went beyond the heap low.
|
||||
* This usually means there was a compiler error.
|
||||
* NOTE: Special optimization here.
|
||||
* The heap low is always known ahead of time! :)
|
||||
*/
|
||||
CompData *data = (CompData *)jit->data;
|
||||
//cmp [esi+info.heap], <heaplow>
|
||||
//jb :error
|
||||
IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_B, data->jit_error_heapmin);
|
||||
}
|
||||
|
||||
void Write_CheckHeap_Low(JitWriter *jit)
|
||||
{
|
||||
/* Check if the heap is trying to grow beyond the stack.
|
||||
*/
|
||||
//mov ecx, [esi+info.heap]
|
||||
//lea ecx, [ebp+ecx+STACK_MARGIN]
|
||||
//cmp ecx, edi
|
||||
//ja :error ; I think this is right
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow);
|
||||
}
|
||||
|
||||
void Write_CheckStack_Min(JitWriter *jit)
|
||||
{
|
||||
/* Check if the stack went beyond the stack top
|
||||
* This usually means there was a compiler error.
|
||||
*/
|
||||
//cmp edi, [esi+info.stacktop]
|
||||
//jae :error
|
||||
IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin);
|
||||
}
|
||||
|
||||
void Write_CheckStack_Low(JitWriter *jit)
|
||||
{
|
||||
/* Check if the stack went beyond the heap boundary.
|
||||
* Unfortunately this one isn't as quick as the other check.
|
||||
* The stack margin check is important for sysreq.n having space.
|
||||
*/
|
||||
//mov ecx, [esi+info.heap]
|
||||
//lea ecx, [ebp+ecx+STACK_MARGIN]
|
||||
//cmp edi, ecx
|
||||
//jb :error ; I think this is right
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
|
||||
}
|
||||
|
||||
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
|
||||
{
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
/* :TODO: Should this be checking for below heaplow?
|
||||
* The old JIT did not.
|
||||
*/
|
||||
|
||||
bool call = false;
|
||||
if (!(data->inline_level & JIT_INLINE_ERRORCHECKS))
|
||||
{
|
||||
/* If we're not in the initial generation phase,
|
||||
* Write a call to the actual routine instead.
|
||||
*/
|
||||
if ((reg == REG_EAX) && data->jit_verify_addr_eax)
|
||||
{
|
||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||
IA32_Write_Jump32(jit, call, data->jit_verify_addr_eax);
|
||||
return;
|
||||
} else if ((reg == REG_EDX) && data->jit_verify_addr_edx) {
|
||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||
IA32_Write_Jump32(jit, call, data->jit_verify_addr_edx);
|
||||
return;
|
||||
}
|
||||
call = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* :TODO: If we can't find a nicer way of doing this,
|
||||
* then scrap it on high optimizations. The second portion is not needed at all!
|
||||
*/
|
||||
|
||||
/* Part 1: Check if we're in the memory bounds */
|
||||
//cmp <reg>, <stpu>
|
||||
//jae :error
|
||||
IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->memory);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
|
||||
|
||||
/* Part 2: Check if we're in the invalid region between HP and SP */
|
||||
jitoffs_t jmp;
|
||||
//cmp <reg>, [esi+info.heap]
|
||||
//jb :continue
|
||||
//lea ecx, [ebp+<reg>]
|
||||
//cmp edi, ecx
|
||||
//jb :error
|
||||
//:continue
|
||||
IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0);
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
|
||||
IA32_Send_Jump8_Here(jit, jmp);
|
||||
|
||||
if (call)
|
||||
{
|
||||
IA32_Return(jit);
|
||||
}
|
||||
}
|
||||
|
||||
void Macro_PushN_Addr(JitWriter *jit, int i)
|
||||
{
|
||||
//push eax
|
||||
//mov eax, [esi+frm]
|
||||
//loop i times:
|
||||
// lea ecx, [eax+<val>]
|
||||
// mov [edi-4*i], ecx
|
||||
//sub edi, 4*N
|
||||
//pop eax
|
||||
|
||||
cell_t val;
|
||||
int n = 1;
|
||||
IA32_Push_Reg(jit, AMX_REG_PRI);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
|
||||
do
|
||||
{
|
||||
val = jit->read_cell();
|
||||
if (val < SCHAR_MAX && val > SCHAR_MIN)
|
||||
IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
|
||||
else
|
||||
IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
IA32_Pop_Reg(jit, AMX_REG_PRI);
|
||||
}
|
||||
|
||||
void Macro_PushN_S(JitWriter *jit, int i)
|
||||
{
|
||||
//loop i times:
|
||||
// mov ecx, [ebx+<val>]
|
||||
// mov [edi-4*i], ecx
|
||||
//sub edi, 4*N
|
||||
|
||||
cell_t val;
|
||||
int n = 1;
|
||||
do
|
||||
{
|
||||
val = jit->read_cell();
|
||||
if (val < SCHAR_MAX && val > SCHAR_MIN)
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
|
||||
else
|
||||
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
}
|
||||
|
||||
void Macro_PushN_C(JitWriter *jit, int i)
|
||||
{
|
||||
//loop i times:
|
||||
// mov [edi-4*i], <val>
|
||||
//sub edi, 4*N
|
||||
|
||||
int n = 1;
|
||||
do
|
||||
{
|
||||
IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
}
|
||||
|
||||
void Macro_PushN(JitWriter *jit, int i)
|
||||
{
|
||||
//loop i times:
|
||||
// mov ecx, [ebp+<val>]
|
||||
// mov [edi-4*i], ecx
|
||||
//sub edi, 4*N
|
||||
|
||||
cell_t val;
|
||||
int n = 1;
|
||||
do
|
||||
{
|
||||
val = jit->read_cell();
|
||||
if (val < SCHAR_MAX && val > SCHAR_MIN)
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
|
||||
else
|
||||
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
}
|
||||
|
||||
void WriteOp_Sysreq_C_Function(JitWriter *jit)
|
||||
{
|
||||
/* The small daddy of the big daddy of opcodes.
|
||||
* ecx - native index
|
||||
*/
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
/* save registers we will need */
|
||||
//push edx
|
||||
IA32_Push_Reg(jit, AMX_REG_ALT);
|
||||
|
||||
/* Align the stack to 16 bytes */
|
||||
//push ebx
|
||||
//mov ebx, esp
|
||||
//and esp, 0xFFFFFF0
|
||||
//sub esp, 4
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
|
||||
IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
|
||||
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
|
||||
|
||||
/* push some callback stuff */
|
||||
//push edi ; stack
|
||||
//push ecx ; native index
|
||||
IA32_Push_Reg(jit, AMX_REG_STK);
|
||||
IA32_Push_Reg(jit, REG_ECX);
|
||||
|
||||
/* Relocate stack, heap, frm information, then store back */
|
||||
//mov eax, [esi+context]
|
||||
//mov ecx, [esi+hea]
|
||||
//sub edi, ebp
|
||||
//mov [eax+hp], ecx
|
||||
//mov ecx, [esi]
|
||||
//mov [eax+sp], edi
|
||||
//mov [eax+frm], ecx
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
|
||||
|
||||
/* finally, push the last parameter and make the call */
|
||||
//push eax ; context
|
||||
//call NativeCallback
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||
if (!data->debug)
|
||||
{
|
||||
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
|
||||
} else {
|
||||
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
|
||||
}
|
||||
|
||||
/* Test for error */
|
||||
//mov ecx, [esi+context]
|
||||
//cmp [ecx+err], 0
|
||||
//jnz :error
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
|
||||
|
||||
/* restore what we damaged */
|
||||
//mov esp, ebx
|
||||
//pop ebx
|
||||
//add edi, ebp
|
||||
//pop edx
|
||||
IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
|
||||
IA32_Pop_Reg(jit, REG_EBX);
|
||||
IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Pop_Reg(jit, AMX_REG_ALT);
|
||||
|
||||
//ret
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
typedef struct array_creation_s
|
||||
{
|
||||
const cell_t *dim_list; /* Dimension sizes */
|
||||
cell_t dim_count; /* Number of dimensions */
|
||||
cell_t *data_offs; /* Current offset AFTER the indirection vectors (data) */
|
||||
cell_t *base; /* array base */
|
||||
} array_creation_t;
|
||||
|
||||
cell_t _GenerateArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs)
|
||||
{
|
||||
cell_t write_offs = cur_offs;
|
||||
cell_t *data_offs = ar->data_offs;
|
||||
|
||||
cur_offs += ar->dim_list[dim];
|
||||
|
||||
/**
|
||||
* Dimension n-x where x > 2 will have sub-vectors.
|
||||
* Otherwise, we just need to reference the data section.
|
||||
*/
|
||||
if (ar->dim_count > 2 && dim < ar->dim_count - 2)
|
||||
{
|
||||
/**
|
||||
* For each index at this dimension, write offstes to our sub-vectors.
|
||||
* After we write one sub-vector, we generate its sub-vectors recursively.
|
||||
* At the end, we're given the next offset we can use.
|
||||
*/
|
||||
for (int i = 0; i < ar->dim_list[dim]; i++)
|
||||
{
|
||||
ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t);
|
||||
write_offs++;
|
||||
cur_offs = _GenerateArrayIndirectionVectors(ar, dim + 1, cur_offs);
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* In this section, there are no sub-vectors, we need to write offsets
|
||||
* to the data. This is separate so the data stays in one big chunk.
|
||||
* The data offset will increment by the size of the last dimension,
|
||||
* because that is where the data is finally computed as.
|
||||
*/
|
||||
for (int i = 0; i < ar->dim_list[dim]; i++)
|
||||
{
|
||||
ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t);
|
||||
write_offs++;
|
||||
*data_offs = *data_offs + ar->dim_list[dim + 1];
|
||||
}
|
||||
}
|
||||
|
||||
return cur_offs;
|
||||
}
|
||||
|
||||
static cell_t calc_indirection(const array_creation_t *ar, cell_t dim)
|
||||
{
|
||||
cell_t size = ar->dim_list[dim];
|
||||
|
||||
if (dim < ar->dim_count - 2)
|
||||
{
|
||||
size += ar->dim_list[dim] * calc_indirection(ar, dim + 1);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero)
|
||||
{
|
||||
array_creation_t ar;
|
||||
cell_t data_offs;
|
||||
|
||||
/* Reverse the dimensions */
|
||||
cell_t dim_list[sDIMEN_MAX];
|
||||
int cur_dim = 0;
|
||||
for (int i = _dimcount - 1; i >= 0; i--)
|
||||
{
|
||||
dim_list[cur_dim++] = dims[i];
|
||||
}
|
||||
|
||||
ar.base = arraybase;
|
||||
ar.dim_list = dim_list;
|
||||
ar.dim_count = _dimcount;
|
||||
ar.data_offs = &data_offs;
|
||||
|
||||
data_offs = calc_indirection(&ar, 0);
|
||||
|
||||
_GenerateArrayIndirectionVectors(&ar, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A few notes about this function.
|
||||
* I was more concerned about efficient use of registers here, rather than
|
||||
* fine-tuned optimization. The reason is that the code is already complicated,
|
||||
* and it is very easy to mess up.
|
||||
*/
|
||||
void WriteIntrinsic_GenArray(JitWriter *jit)
|
||||
{
|
||||
/**
|
||||
* save important values
|
||||
*/
|
||||
//push ebx
|
||||
//push eax
|
||||
//push edx
|
||||
//push ecx ;value is referenced on stack
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
IA32_Push_Reg(jit, REG_EDX);
|
||||
IA32_Push_Reg(jit, REG_ECX);
|
||||
|
||||
/**
|
||||
* Calculate how many cells will be needed.
|
||||
*/
|
||||
//mov edx, [edi] ;get last dimension's count
|
||||
//mov eax, 1 ;position at second to last dimension
|
||||
//:loop
|
||||
//cmp eax, [esp] ;compare to # of params
|
||||
//jae :done ;end loop if done
|
||||
//mov ecx, [edi+eax*4] ;get dimension size
|
||||
//imul edx, ecx ;multiply by size
|
||||
//add eax, 1 ;increment
|
||||
//add edx, ecx ;add size (indirection vector)
|
||||
//jmp :loop ;jump back
|
||||
//:done
|
||||
IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, REG_EAX, 1);
|
||||
jitoffs_t loop1 = jit->get_outputpos();
|
||||
IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX);
|
||||
jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
|
||||
IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4);
|
||||
IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
|
||||
IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG);
|
||||
IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
|
||||
IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1);
|
||||
IA32_Send_Jump8_Here(jit, done1);
|
||||
|
||||
/* Test if we have heap space for this */
|
||||
//mov eax, [esi+info.heap] ;get heap pointer
|
||||
//lea eax, [eax+edx*4] ;new heap pointer
|
||||
//cmp eax, <hlw> ;compare to heap low
|
||||
//jbe :error ;die if we hit this (it should always be >)
|
||||
//add eax, ebp ;relocate to stack
|
||||
//cmp eax, edi ;die if above the stack pointer
|
||||
//jae :error
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4);
|
||||
IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_EAX, ((CompData *)jit->data)->plugin->data_size);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_BE, ((CompData *)jit->data)->jit_error_array_too_big);
|
||||
IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_array_too_big);
|
||||
|
||||
/* Prepare for indirection iteration */
|
||||
//mov eax, [esi+info.heap] ;get heap pointer
|
||||
//lea ebx, [eax+edx*4] ;new heap pointer
|
||||
//mov [esi+info.heap], ebx ;store back
|
||||
//push eax ;save heap pointer - we need it
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP);
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
|
||||
WriteOp_Tracker_Push_Reg(jit, REG_EDX);
|
||||
|
||||
/* This part is too messy to do in straight assembly.
|
||||
* I'm letting the compiler handle it and thus it's in C.
|
||||
*/
|
||||
//lea ebx, [ebp+eax] ;get base pointer
|
||||
//push dword [esp-8] ;push autozero
|
||||
//push dword [esp-8] ;push dimension count
|
||||
//push edi ;push dim array
|
||||
//push ebx
|
||||
//call GenerateArrayIndirectionVectors
|
||||
//add esp, 4*4
|
||||
IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE);
|
||||
IA32_Push_Rm_Disp8_ESP(jit, 8);
|
||||
IA32_Push_Rm_Disp8_ESP(jit, 8);
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors);
|
||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
|
||||
|
||||
/* Store the heap pointer back into the stack */
|
||||
//pop eax ;restore heap pointer
|
||||
//pop ecx ;restore param count
|
||||
//lea edi, [edi+ecx*4-4] ;pop params-4 off the stack
|
||||
//mov [edi], eax ;store back the heap pointer
|
||||
IA32_Pop_Reg(jit, REG_EAX);
|
||||
IA32_Pop_Reg(jit, REG_ECX);
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4);
|
||||
IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG);
|
||||
|
||||
/* Return to caller */
|
||||
//pop edx
|
||||
//pop eax
|
||||
//pop ebx
|
||||
//ret
|
||||
IA32_Pop_Reg(jit, REG_ECX);
|
||||
IA32_Pop_Reg(jit, REG_EAX);
|
||||
IA32_Pop_Reg(jit, REG_EBX);
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
void WriteOp_Sysreq_N_Function(JitWriter *jit)
|
||||
{
|
||||
/* The big daddy of opcodes.
|
||||
* eax - num_params
|
||||
* ecx - native index
|
||||
*/
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
/* store the number of parameters on the stack */
|
||||
//mov [edi-4], eax
|
||||
//sub edi, 4
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, REG_EAX, -4);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
|
||||
|
||||
/* save registers we will need */
|
||||
//push eax ; num_params for stack popping
|
||||
//push edx
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
IA32_Push_Reg(jit, AMX_REG_ALT);
|
||||
|
||||
/* Align the stack to 16 bytes */
|
||||
//push ebx
|
||||
//mov ebx, esp
|
||||
//and esp, 0xFFFFFF0
|
||||
//sub esp, 4
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
|
||||
IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
|
||||
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
|
||||
|
||||
/* push some callback stuff */
|
||||
//push edi ; stack
|
||||
//push ecx ; native index
|
||||
IA32_Push_Reg(jit, AMX_REG_STK);
|
||||
IA32_Push_Reg(jit, REG_ECX);
|
||||
|
||||
/* Relocate stack, heap, frm information, then store back */
|
||||
//mov eax, [esi+context]
|
||||
//mov ecx, [esi+hea]
|
||||
//sub edi, ebp
|
||||
//mov [eax+hp], ecx
|
||||
//mov ecx, [esi]
|
||||
//mov [eax+sp], edi
|
||||
//mov [eax+frm], ecx
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
|
||||
|
||||
/* finally, push the last parameter and make the call */
|
||||
//push eax ; context
|
||||
//call NativeCallback
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||
if (!data->debug)
|
||||
{
|
||||
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
|
||||
} else {
|
||||
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Debug);
|
||||
}
|
||||
|
||||
/* Test for error */
|
||||
//mov ecx, [esi+context]
|
||||
//cmp [ecx+err], 0
|
||||
//jnz :error
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_extern_error);
|
||||
|
||||
/* restore what we damaged */
|
||||
//mov esp, ebx
|
||||
//pop ebx
|
||||
//add edi, ebp
|
||||
//pop edx
|
||||
//pop ecx ; num_params
|
||||
IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
|
||||
IA32_Pop_Reg(jit, REG_EBX);
|
||||
IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Pop_Reg(jit, AMX_REG_ALT);
|
||||
IA32_Pop_Reg(jit, REG_ECX);
|
||||
|
||||
/* pop the AMX stack. do not check the margins.
|
||||
* Note that this is not a true macro - we don't bother to
|
||||
* set ALT here because nothing will be using it.
|
||||
*/
|
||||
//lea edi, [edi+ecx*4+4]
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, 4);
|
||||
|
||||
//ret
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg)
|
||||
{
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
/* Save registers that may be damaged by the call */
|
||||
//push eax
|
||||
//push ecx
|
||||
//push edi
|
||||
//lea edi, [<reg>*4] ; we want the count in bytes not in cells
|
||||
IA32_Push_Reg(jit, AMX_REG_PRI);
|
||||
if (reg == REG_ECX)
|
||||
{
|
||||
IA32_Push_Reg(jit, AMX_REG_TMP);
|
||||
}
|
||||
IA32_Push_Reg(jit, AMX_REG_STK);
|
||||
IA32_Lea_Reg_RegMultImm32(jit, REG_EDI, reg, SCALE4, 0);
|
||||
|
||||
/* Get the context ptr, push it and call the check */
|
||||
//mov eax, [esi+context]
|
||||
//push eax
|
||||
//call JIT_VerifyOrAllocateTracker
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||
IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker);
|
||||
|
||||
/* Check for errors */
|
||||
//cmp eax, 0
|
||||
//jnz :error
|
||||
IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_return);
|
||||
|
||||
/* Restore */
|
||||
//pop eax
|
||||
IA32_Pop_Reg(jit, REG_EAX);
|
||||
|
||||
/* Push the register into the stack and increment pCur */
|
||||
//mov edx, [eax+vm[]]
|
||||
//mov eax, [edx+pcur]
|
||||
//add [edx+pcur], 4
|
||||
//mov [eax], edi
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur));
|
||||
IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
|
||||
IA32_Mov_Rm_Reg(jit, REG_EAX, REG_EDI, MOD_MEM_REG);
|
||||
|
||||
/* Restore PRI, ALT and STK */
|
||||
//pop edi
|
||||
//pop ecx
|
||||
//pop eax
|
||||
IA32_Pop_Reg(jit, AMX_REG_STK);
|
||||
if (reg == REG_ECX)
|
||||
{
|
||||
IA32_Pop_Reg(jit, AMX_REG_TMP);
|
||||
}
|
||||
IA32_Pop_Reg(jit, AMX_REG_PRI);
|
||||
}
|
||||
|
||||
int JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
|
||||
{
|
||||
tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
|
||||
|
||||
if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
|
||||
{
|
||||
return SP_ERROR_TRACKER_BOUNDS;
|
||||
}
|
||||
|
||||
if (trk->pCur+1 - (trk->pBase + trk->size) == 0)
|
||||
{
|
||||
size_t disp = trk->size - 1;
|
||||
trk->size *= 2;
|
||||
trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
|
||||
|
||||
if (!trk->pBase)
|
||||
{
|
||||
return SP_ERROR_TRACKER_BOUNDS;
|
||||
}
|
||||
|
||||
trk->pCur = trk->pBase + disp;
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int JIT_VerifyLowBoundTracker(sp_context_t *ctx)
|
||||
{
|
||||
tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
|
||||
|
||||
if (trk->pCur <= trk->pBase)
|
||||
{
|
||||
return SP_ERROR_TRACKER_BOUNDS;
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void Write_RoundingTable(JitWriter *jit)
|
||||
{
|
||||
jit->write_int32(-1);
|
||||
jit->write_int32(0);
|
||||
jit->write_int32(1);
|
||||
}
|
||||
|
||||
void AlignMe(JitWriter *jit)
|
||||
{
|
||||
jitoffs_t cur_offs = jit->get_outputpos();
|
||||
jitoffs_t offset = ((cur_offs & 0xFFFFFFF0) + 16) - cur_offs;
|
||||
|
||||
if (offset)
|
||||
{
|
||||
for (jit_uint32_t i=0; i<offset; i++)
|
||||
{
|
||||
jit->write_ubyte(IA32_INT3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
|
||||
|
||||
#include "../jit_helpers.h"
|
||||
|
||||
/**
|
||||
* This outputs the execution function for a plugin.
|
||||
* It also returns the 'return' offset, which is used for
|
||||
* breaking out of the JIT during runtime.
|
||||
*/
|
||||
jitoffs_t Write_Execute_Function(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Writes the Sysreq.* opcodes as a function call.
|
||||
*/
|
||||
void WriteOp_Sysreq_N_Function(JitWriter *jit);
|
||||
void WriteOp_Sysreq_C_Function(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Write the GENARRAY intrinsic function.
|
||||
*/
|
||||
void WriteIntrinsic_GenArray(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Generates code to set an error state in the VM and return.
|
||||
* This is used for generating the error set points in the VM.
|
||||
* GetError writes the error from the context. SetError hardcodes.
|
||||
*/
|
||||
void Write_GetError(JitWriter *jit);
|
||||
void Write_SetError(JitWriter *jit, int error);
|
||||
|
||||
/**
|
||||
* Checks the stacks for min and low errors.
|
||||
* :TODO: Should a variation of this go in the pushN opcodes?
|
||||
*/
|
||||
void Write_CheckStack_Min(JitWriter *jit);
|
||||
void Write_CheckStack_Low(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Checks the heap for min and low errors.
|
||||
*/
|
||||
void Write_CheckHeap_Min(JitWriter *jit);
|
||||
void Write_CheckHeap_Low(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Verifies an address by register. The address must reside
|
||||
* between DAT and HP and SP and STP.
|
||||
*/
|
||||
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg);
|
||||
|
||||
/**
|
||||
* Checks for division by zero.
|
||||
*/
|
||||
void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg);
|
||||
|
||||
/**
|
||||
* Writes the break debug function.
|
||||
*/
|
||||
void Write_BreakDebug(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* These are for writing the PushN opcodes.
|
||||
*/
|
||||
void Macro_PushN_Addr(JitWriter *jit, int i);
|
||||
void Macro_PushN_S(JitWriter *jit, int i);
|
||||
void Macro_PushN_C(JitWriter *jit, int i);
|
||||
void Macro_PushN(JitWriter *jit, int i);
|
||||
|
||||
/**
|
||||
* Bound checking for the tracker stack,
|
||||
*/
|
||||
int JIT_VerifyLowBoundTracker(sp_context_t *ctx);
|
||||
int JIT_VerifyOrAllocateTracker(sp_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Writes the push into tracker function.
|
||||
*/
|
||||
void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg);
|
||||
|
||||
/**
|
||||
* Writes the rounding table for the float compare opcode.
|
||||
*/
|
||||
void Write_RoundingTable(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Aligns the current code position to 16 bytes.
|
||||
*/
|
||||
void AlignMe(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Legend for Statuses:
|
||||
* ****** *** ********
|
||||
* DONE -> code generation is done
|
||||
* !GEN -> code generation is deliberate skipped because:
|
||||
* (default): compiler does not generate
|
||||
* DEPRECATED: this feature no longer exists/supported
|
||||
* UNSUPPORTED: this opcode is not supported
|
||||
* TODO: done in case needed
|
||||
* VERIFIED -> code generation is checked as run-time working. prefixes:
|
||||
* ! errors are not checked yet.
|
||||
* - non-inline errors are not checked yet.
|
||||
* ~ assumed checked because of related variation, but not actually checked
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OP_NONE, /* invalid opcode */
|
||||
OP_LOAD_PRI, //!VERIFIED
|
||||
OP_LOAD_ALT, //~!VERIFIED (load.pri)
|
||||
OP_LOAD_S_PRI, //VERIFIED
|
||||
OP_LOAD_S_ALT, //VERIFIED
|
||||
OP_LREF_PRI, //VERIFIED
|
||||
OP_LREF_ALT, //~VERIFIED
|
||||
OP_LREF_S_PRI, //VERIFIED
|
||||
OP_LREF_S_ALT, //~VERIFIED (lref.s.pri)
|
||||
OP_LOAD_I, //VERIFIED
|
||||
OP_LODB_I, //VERIFIED
|
||||
OP_CONST_PRI, //VERIFIED
|
||||
OP_CONST_ALT, //~VERIFIED (const.pri)
|
||||
OP_ADDR_PRI, //VERIFIED
|
||||
OP_ADDR_ALT, //VERIFIED
|
||||
OP_STOR_PRI, //VERIFIED
|
||||
OP_STOR_ALT, //~VERIFIED (stor.pri)
|
||||
OP_STOR_S_PRI, //VERIFIED
|
||||
OP_STOR_S_ALT, //~VERIFIED (stor.s.pri)
|
||||
OP_SREF_PRI, //VERIFIED
|
||||
OP_SREF_ALT, //~VERIFIED
|
||||
OP_SREF_S_PRI, //VERIFIED
|
||||
OP_SREF_S_ALT, //~VERIFIED (stor.s.alt)
|
||||
OP_STOR_I, //VERIFIED
|
||||
OP_STRB_I, //VERIFIED
|
||||
OP_LIDX, //VERIFIED
|
||||
OP_LIDX_B, //DONE
|
||||
OP_IDXADDR, //VERIFIED
|
||||
OP_IDXADDR_B, //DONE
|
||||
OP_ALIGN_PRI, // !GEN :TODO: - only used for pack access, drop support in compiler first
|
||||
OP_ALIGN_ALT, // !GEN :TODO: - only used for pack access, drop support in compiler first
|
||||
OP_LCTRL, // !GEN
|
||||
OP_SCTRL, // !GEN
|
||||
OP_MOVE_PRI, //~VERIFIED (move.alt)
|
||||
OP_MOVE_ALT, //VERIFIED
|
||||
OP_XCHG, //DONE
|
||||
OP_PUSH_PRI, //DONE
|
||||
OP_PUSH_ALT, //DONE
|
||||
OP_PUSH_R, // !GEN DEPRECATED
|
||||
OP_PUSH_C, //VERIFIED
|
||||
OP_PUSH, //DONE
|
||||
OP_PUSH_S, //VERIFIED
|
||||
OP_POP_PRI, //VERIFIED
|
||||
OP_POP_ALT, //VERIFIED
|
||||
OP_STACK, //VERIFIED
|
||||
OP_HEAP, //VERIFIED
|
||||
OP_PROC, //VERIFIED
|
||||
OP_RET, // !GEN
|
||||
OP_RETN, //VERIFIED
|
||||
OP_CALL, //VERIFIED
|
||||
OP_CALL_PRI, // !GEN
|
||||
OP_JUMP, //VERIFIED
|
||||
OP_JREL, // !GEN
|
||||
OP_JZER, //VERIFIED
|
||||
OP_JNZ, //DONE
|
||||
OP_JEQ, //VERIFIED
|
||||
OP_JNEQ, //VERIFIED
|
||||
OP_JLESS, // !GEN
|
||||
OP_JLEQ, // !GEN
|
||||
OP_JGRTR, // !GEN
|
||||
OP_JGEQ, // !GEN
|
||||
OP_JSLESS, //VERIFIED
|
||||
OP_JSLEQ, //VERIFIED
|
||||
OP_JSGRTR, //VERIFIED
|
||||
OP_JSGEQ, //VERIFIED
|
||||
OP_SHL, //VERIFIED
|
||||
OP_SHR, //VERIFIED (Note: operator >>>)
|
||||
OP_SSHR, //VERIFIED (Note: operator >>)
|
||||
OP_SHL_C_PRI, //DONE
|
||||
OP_SHL_C_ALT, //DONE
|
||||
OP_SHR_C_PRI, //DONE
|
||||
OP_SHR_C_ALT, //DONE
|
||||
OP_SMUL, //VERIFIED
|
||||
OP_SDIV, //DONE
|
||||
OP_SDIV_ALT, //VERIFIED
|
||||
OP_UMUL, // !GEN
|
||||
OP_UDIV, // !GEN
|
||||
OP_UDIV_ALT, // !GEN
|
||||
OP_ADD, //VERIFIED
|
||||
OP_SUB, //DONE
|
||||
OP_SUB_ALT, //VERIFIED
|
||||
OP_AND, //VERIFIED
|
||||
OP_OR, //VERIFIED
|
||||
OP_XOR, //VERIFIED
|
||||
OP_NOT, //VERIFIED
|
||||
OP_NEG, //VERIFIED
|
||||
OP_INVERT, //VERIFIED
|
||||
OP_ADD_C, //VERIFIED
|
||||
OP_SMUL_C, //VERIFIED
|
||||
OP_ZERO_PRI, //VERIFIED
|
||||
OP_ZERO_ALT, //~VERIFIED
|
||||
OP_ZERO, //VERIFIED
|
||||
OP_ZERO_S, //VERIFIED
|
||||
OP_SIGN_PRI, //DONE
|
||||
OP_SIGN_ALT, //DONE
|
||||
OP_EQ, //VERIFIED
|
||||
OP_NEQ, //VERIFIED
|
||||
OP_LESS, // !GEN
|
||||
OP_LEQ, // !GEN
|
||||
OP_GRTR, // !GEN
|
||||
OP_GEQ, // !GEN
|
||||
OP_SLESS, //VERIFIED
|
||||
OP_SLEQ, //VERIFIED
|
||||
OP_SGRTR, //VERIFIED
|
||||
OP_SGEQ, //VERIFIED
|
||||
OP_EQ_C_PRI, //DONE
|
||||
OP_EQ_C_ALT, //DONE
|
||||
OP_INC_PRI, //VERIFIED
|
||||
OP_INC_ALT, //~VERIFIED (inc.pri)
|
||||
OP_INC, //VERIFIED
|
||||
OP_INC_S, //VERIFIED
|
||||
OP_INC_I, //VERIFIED
|
||||
OP_DEC_PRI, //VERIFIED
|
||||
OP_DEC_ALT, //~VERIFIED (dec.pri)
|
||||
OP_DEC, //VERIFIED
|
||||
OP_DEC_S, //VERIFIED
|
||||
OP_DEC_I, //VERIFIED
|
||||
OP_MOVS, //VERIFIED
|
||||
OP_CMPS, // !GEN
|
||||
OP_FILL, //VERIFIED
|
||||
OP_HALT, //DONE
|
||||
OP_BOUNDS, //VERIFIED
|
||||
OP_SYSREQ_PRI, // !GEN
|
||||
OP_SYSREQ_C, //VERIFIED
|
||||
OP_FILE, // !GEN DEPRECATED
|
||||
OP_LINE, // !GEN DEPRECATED
|
||||
OP_SYMBOL, // !GEN DEPRECATED
|
||||
OP_SRANGE, // !GEN DEPRECATED
|
||||
OP_JUMP_PRI, // !GEN
|
||||
OP_SWITCH, //VERIFIED
|
||||
OP_CASETBL, //VERIFIED
|
||||
OP_SWAP_PRI, //VERIFIED
|
||||
OP_SWAP_ALT, //~VERIFIED (swap.alt)
|
||||
OP_PUSH_ADR, //VERIFIED
|
||||
OP_NOP, //VERIFIED (lol)
|
||||
OP_SYSREQ_N, //VERIFIED
|
||||
OP_SYMTAG, // !GEN DEPRECATED
|
||||
OP_BREAK, //DONE
|
||||
OP_PUSH2_C, //~VERIFIED (push3.c)
|
||||
OP_PUSH2, //VERIFIED
|
||||
OP_PUSH2_S, //VERIFIED
|
||||
OP_PUSH2_ADR, //VERIFIED
|
||||
OP_PUSH3_C, //VERIFIED
|
||||
OP_PUSH3, //~VERIFIED (push2)
|
||||
OP_PUSH3_S, //~VERIFIED (push2.s)
|
||||
OP_PUSH3_ADR, //~VERIFIED (push2.adr)
|
||||
OP_PUSH4_C, //~VERIFIED (push3.c)
|
||||
OP_PUSH4, //~VERIFIED (push2)
|
||||
OP_PUSH4_S, //~VERIFIED (push2.s)
|
||||
OP_PUSH4_ADR, //~VERIFIED (push2.adr)
|
||||
OP_PUSH5_C, //~VERIFIED (push3.c)
|
||||
OP_PUSH5, //~VERIFIED (push2)
|
||||
OP_PUSH5_S, //~VERIFIED (push2.s)
|
||||
OP_PUSH5_ADR, //~VERIFIED (push2.adr)
|
||||
OP_LOAD_BOTH, //VERIFIED
|
||||
OP_LOAD_S_BOTH, //VERIFIED
|
||||
OP_CONST, //VERIFIED
|
||||
OP_CONST_S, //DONE
|
||||
/* ----- */
|
||||
OP_SYSREQ_D, // !GEN UNSUPPORT
|
||||
OP_SYSREQ_ND, // !GEN UNSUPPORT
|
||||
/* ----- */
|
||||
OP_TRACKER_PUSH_C, //DONE
|
||||
OP_TRACKER_POP_SETHEAP, //VERIFIED
|
||||
OP_GENARRAY, //VERIFIED
|
||||
OP_GENARRAY_Z, //-VERIFIED (not tested for 1D arrays)
|
||||
OP_STRADJUST_PRI, //VERIFIED
|
||||
OP_STACKADJUST, //:TODO: VERIFY
|
||||
OP_FABS, //VERIFIED
|
||||
OP_FLOAT, //VERIFIED
|
||||
OP_FLOATADD, //VERIFIED
|
||||
OP_FLOATSUB, //VERIFIED
|
||||
OP_FLOATMUL, //VERIFIED
|
||||
OP_FLOATDIV, //VERIFIED
|
||||
OP_RND_TO_NEAREST, //VERIFIED
|
||||
OP_RND_TO_FLOOR, //VERIFIED
|
||||
OP_RND_TO_CEIL, //VERIFIED
|
||||
OP_RND_TO_ZERO, //VERIFIED
|
||||
OP_FLOATCMP, //VERIFIED
|
||||
/* ----- */
|
||||
OP_NUM_OPCODES
|
||||
} OPCODE;
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
|
||||
@@ -0,0 +1,763 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
case OP_MOVE_PRI:
|
||||
{
|
||||
WriteOp_Move_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_MOVE_ALT:
|
||||
{
|
||||
WriteOp_Move_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_XCHG:
|
||||
{
|
||||
WriteOp_Xchg(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH:
|
||||
{
|
||||
WriteOp_Push(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_S:
|
||||
{
|
||||
WriteOp_Push_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2_C:
|
||||
{
|
||||
WriteOp_Push2_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3_C:
|
||||
{
|
||||
WriteOp_Push3_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4_C:
|
||||
{
|
||||
WriteOp_Push4_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5_C:
|
||||
{
|
||||
WriteOp_Push5_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2_ADR:
|
||||
{
|
||||
WriteOp_Push2_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3_ADR:
|
||||
{
|
||||
WriteOp_Push3_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4_ADR:
|
||||
{
|
||||
WriteOp_Push4_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5_ADR:
|
||||
{
|
||||
WriteOp_Push5_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2_S:
|
||||
{
|
||||
WriteOp_Push2_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3_S:
|
||||
{
|
||||
WriteOp_Push3_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4_S:
|
||||
{
|
||||
WriteOp_Push4_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5_S:
|
||||
{
|
||||
WriteOp_Push5_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5:
|
||||
{
|
||||
WriteOp_Push5(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4:
|
||||
{
|
||||
WriteOp_Push4(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3:
|
||||
{
|
||||
WriteOp_Push3(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2:
|
||||
{
|
||||
WriteOp_Push2(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO_PRI:
|
||||
{
|
||||
WriteOp_Zero_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO_ALT:
|
||||
{
|
||||
WriteOp_Zero_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PROC:
|
||||
{
|
||||
WriteOp_Proc(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHL:
|
||||
{
|
||||
WriteOp_Shl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHR:
|
||||
{
|
||||
WriteOp_Shr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SSHR:
|
||||
{
|
||||
WriteOp_Sshr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHL_C_PRI:
|
||||
{
|
||||
WriteOp_Shl_C_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHL_C_ALT:
|
||||
{
|
||||
WriteOp_Shl_C_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHR_C_PRI:
|
||||
{
|
||||
WriteOp_Shr_C_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHR_C_ALT:
|
||||
{
|
||||
WriteOp_Shr_C_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SMUL:
|
||||
{
|
||||
WriteOp_SMul(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADD:
|
||||
{
|
||||
WriteOp_Add(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SUB:
|
||||
{
|
||||
WriteOp_Sub(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SUB_ALT:
|
||||
{
|
||||
WriteOp_Sub_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_NOP:
|
||||
{
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
case OP_NOT:
|
||||
{
|
||||
WriteOp_Not(jit);
|
||||
break;
|
||||
}
|
||||
case OP_NEG:
|
||||
{
|
||||
WriteOp_Neg(jit);
|
||||
break;
|
||||
}
|
||||
case OP_XOR:
|
||||
{
|
||||
WriteOp_Xor(jit);
|
||||
break;
|
||||
}
|
||||
case OP_OR:
|
||||
{
|
||||
WriteOp_Or(jit);
|
||||
break;
|
||||
}
|
||||
case OP_AND:
|
||||
{
|
||||
WriteOp_And(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INVERT:
|
||||
{
|
||||
WriteOp_Invert(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADD_C:
|
||||
{
|
||||
WriteOp_Add_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SMUL_C:
|
||||
{
|
||||
WriteOp_SMul_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SIGN_PRI:
|
||||
{
|
||||
WriteOp_Sign_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SIGN_ALT:
|
||||
{
|
||||
WriteOp_Sign_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_EQ:
|
||||
{
|
||||
WriteOp_Eq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_NEQ:
|
||||
{
|
||||
WriteOp_Neq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SLESS:
|
||||
{
|
||||
WriteOp_Sless(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SLEQ:
|
||||
{
|
||||
WriteOp_Sleq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SGRTR:
|
||||
{
|
||||
WriteOp_Sgrtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SGEQ:
|
||||
{
|
||||
WriteOp_Sgeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_EQ_C_PRI:
|
||||
{
|
||||
WriteOp_Eq_C_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_EQ_C_ALT:
|
||||
{
|
||||
WriteOp_Eq_C_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_PRI:
|
||||
{
|
||||
WriteOp_Inc_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_ALT:
|
||||
{
|
||||
WriteOp_Inc_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC:
|
||||
{
|
||||
WriteOp_Inc(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_S:
|
||||
{
|
||||
WriteOp_Inc_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_I:
|
||||
{
|
||||
WriteOp_Inc_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_PRI:
|
||||
{
|
||||
WriteOp_Dec_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_ALT:
|
||||
{
|
||||
WriteOp_Dec_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC:
|
||||
{
|
||||
WriteOp_Dec(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_S:
|
||||
{
|
||||
WriteOp_Dec_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_I:
|
||||
{
|
||||
WriteOp_Dec_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_PRI:
|
||||
{
|
||||
WriteOp_Load_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_ALT:
|
||||
{
|
||||
WriteOp_Load_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_S_PRI:
|
||||
{
|
||||
WriteOp_Load_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_S_ALT:
|
||||
{
|
||||
WriteOp_Load_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_PRI:
|
||||
{
|
||||
WriteOp_Lref_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_ALT:
|
||||
{
|
||||
WriteOp_Lref_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_S_PRI:
|
||||
{
|
||||
WriteOp_Lref_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_S_ALT:
|
||||
{
|
||||
WriteOp_Lref_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST_PRI:
|
||||
{
|
||||
WriteOp_Const_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST_ALT:
|
||||
{
|
||||
WriteOp_Const_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADDR_PRI:
|
||||
{
|
||||
WriteOp_Addr_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADDR_ALT:
|
||||
{
|
||||
WriteOp_Addr_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_PRI:
|
||||
{
|
||||
WriteOp_Stor_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_ALT:
|
||||
{
|
||||
WriteOp_Stor_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_S_PRI:
|
||||
{
|
||||
WriteOp_Stor_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_S_ALT:
|
||||
{
|
||||
WriteOp_Stor_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_IDXADDR:
|
||||
{
|
||||
WriteOp_Idxaddr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_PRI:
|
||||
{
|
||||
WriteOp_Sref_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_ALT:
|
||||
{
|
||||
WriteOp_Sref_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_S_PRI:
|
||||
{
|
||||
WriteOp_Sref_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_S_ALT:
|
||||
{
|
||||
WriteOp_Sref_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_POP_PRI:
|
||||
{
|
||||
WriteOp_Pop_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_POP_ALT:
|
||||
{
|
||||
WriteOp_Pop_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWAP_PRI:
|
||||
{
|
||||
WriteOp_Swap_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWAP_ALT:
|
||||
{
|
||||
WriteOp_Swap_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_ADR:
|
||||
{
|
||||
WriteOp_PushAddr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_MOVS:
|
||||
{
|
||||
WriteOp_Movs(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FILL:
|
||||
{
|
||||
WriteOp_Fill(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_C:
|
||||
{
|
||||
WriteOp_Push_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO:
|
||||
{
|
||||
WriteOp_Zero(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO_S:
|
||||
{
|
||||
WriteOp_Zero_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_PRI:
|
||||
{
|
||||
WriteOp_Push_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_ALT:
|
||||
{
|
||||
WriteOp_Push_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_BOTH:
|
||||
{
|
||||
WriteOp_Load_Both(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_S_BOTH:
|
||||
{
|
||||
WriteOp_Load_S_Both(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST:
|
||||
{
|
||||
WriteOp_Const(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST_S:
|
||||
{
|
||||
WriteOp_Const_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_I:
|
||||
{
|
||||
WriteOp_Load_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LODB_I:
|
||||
{
|
||||
WriteOp_Lodb_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_I:
|
||||
{
|
||||
WriteOp_Stor_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STRB_I:
|
||||
{
|
||||
WriteOp_Strb_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LIDX:
|
||||
{
|
||||
WriteOp_Lidx(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LIDX_B:
|
||||
{
|
||||
WriteOp_Lidx_B(jit);
|
||||
break;
|
||||
}
|
||||
case OP_IDXADDR_B:
|
||||
{
|
||||
WriteOp_Idxaddr_B(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STACK:
|
||||
{
|
||||
WriteOp_Stack(jit);
|
||||
break;
|
||||
}
|
||||
case OP_HEAP:
|
||||
{
|
||||
WriteOp_Heap(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SDIV:
|
||||
{
|
||||
WriteOp_SDiv(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SDIV_ALT:
|
||||
{
|
||||
WriteOp_SDiv_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RETN:
|
||||
{
|
||||
WriteOp_Retn(jit);
|
||||
break;
|
||||
}
|
||||
case OP_BOUNDS:
|
||||
{
|
||||
WriteOp_Bounds(jit);
|
||||
break;
|
||||
}
|
||||
case OP_HALT:
|
||||
{
|
||||
WriteOp_Halt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_BREAK:
|
||||
{
|
||||
WriteOp_Break(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JUMP:
|
||||
{
|
||||
WriteOp_Jump(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JZER:
|
||||
{
|
||||
WriteOp_Jzer(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JNZ:
|
||||
{
|
||||
WriteOp_Jnz(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JEQ:
|
||||
{
|
||||
WriteOp_Jeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JNEQ:
|
||||
{
|
||||
WriteOp_Jneq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSLESS:
|
||||
{
|
||||
WriteOp_Jsless(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSGRTR:
|
||||
{
|
||||
WriteOp_JsGrtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSGEQ:
|
||||
{
|
||||
WriteOp_JsGeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSLEQ:
|
||||
{
|
||||
WriteOp_Jsleq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWITCH:
|
||||
{
|
||||
WriteOp_Switch(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CASETBL:
|
||||
{
|
||||
WriteOp_Casetbl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CALL:
|
||||
{
|
||||
WriteOp_Call(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SYSREQ_C:
|
||||
{
|
||||
WriteOp_Sysreq_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SYSREQ_N:
|
||||
{
|
||||
if (data->inline_level & JIT_INLINE_NATIVES)
|
||||
{
|
||||
WriteOp_Sysreq_N(jit);
|
||||
} else {
|
||||
WriteOp_Sysreq_N_NoInline(jit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_TRACKER_PUSH_C:
|
||||
{
|
||||
WriteOp_Tracker_Push_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_TRACKER_POP_SETHEAP:
|
||||
{
|
||||
WriteOp_Tracker_Pop_SetHeap(jit);
|
||||
break;
|
||||
}
|
||||
case OP_GENARRAY:
|
||||
{
|
||||
WriteOp_GenArray(jit, false);
|
||||
break;
|
||||
}
|
||||
case OP_GENARRAY_Z:
|
||||
{
|
||||
WriteOp_GenArray(jit, true);
|
||||
break;
|
||||
}
|
||||
case OP_STRADJUST_PRI:
|
||||
{
|
||||
WriteOp_Stradjust_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FABS:
|
||||
{
|
||||
WriteOp_FloatAbs(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOAT:
|
||||
{
|
||||
WriteOp_Float(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATADD:
|
||||
{
|
||||
WriteOp_FloatAdd(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATSUB:
|
||||
{
|
||||
WriteOp_FloatSub(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATMUL:
|
||||
{
|
||||
WriteOp_FloatMul(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATDIV:
|
||||
{
|
||||
WriteOp_FloatDiv(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RND_TO_NEAREST:
|
||||
{
|
||||
WriteOp_RountToNearest(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RND_TO_FLOOR:
|
||||
{
|
||||
WriteOp_RoundToFloor(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RND_TO_ZERO:
|
||||
{
|
||||
WriteOp_RoundToZero(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RND_TO_CEIL:
|
||||
{
|
||||
WriteOp_RoundToCeil(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATCMP:
|
||||
{
|
||||
WriteOp_FloatCompare(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STACKADJUST:
|
||||
{
|
||||
WriteOp_StackAdjust(jit);
|
||||
break;
|
||||
}
|
||||
#if defined USE_UNGEN_OPCODES
|
||||
#include "ungen_opcode_switch.inc"
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
data->error_set = SP_ERROR_INVALID_INSTRUCTION;
|
||||
break;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
case OP_UMUL:
|
||||
{
|
||||
WriteOp_UMul(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LESS:
|
||||
{
|
||||
WriteOp_Less(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LEQ:
|
||||
{
|
||||
WriteOp_Leq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_GRTR:
|
||||
{
|
||||
WriteOp_Grtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_GEQ:
|
||||
{
|
||||
WriteOp_Geq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ALIGN_PRI:
|
||||
{
|
||||
WriteOp_Align_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ALIGN_ALT:
|
||||
{
|
||||
WriteOp_Align_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LCTRL:
|
||||
{
|
||||
WriteOp_Lctrl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SCTRL:
|
||||
{
|
||||
WriteOp_Sctrl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_UDIV:
|
||||
{
|
||||
WriteOp_UDiv(jit);
|
||||
break;
|
||||
}
|
||||
case OP_UDIV_ALT:
|
||||
{
|
||||
WriteOp_UDiv_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RET:
|
||||
{
|
||||
WriteOp_Ret(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CMPS:
|
||||
{
|
||||
WriteOp_Cmps(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JREL:
|
||||
{
|
||||
WriteOp_JRel(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JLESS:
|
||||
{
|
||||
WriteOp_Jless(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JLEQ:
|
||||
{
|
||||
WriteOp_Jeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JGRTR:
|
||||
{
|
||||
WriteOp_Jgrtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JGEQ:
|
||||
{
|
||||
WriteOp_Jgeq(jit);
|
||||
break;
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourcePawn JIT
|
||||
* Copyright (C)2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is not open source and may not be copied without explicit wriiten
|
||||
* permission of AlliedModders LLC. This file may not be redistributed in whole
|
||||
* or significant part.
|
||||
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_
|
||||
|
||||
inline void WriteOp_UMul(JitWriter *jit)
|
||||
{
|
||||
//mov ecx, edx
|
||||
//mul edx
|
||||
//mov edx, ecx
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mul_Rm(jit, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG);
|
||||
}
|
||||
|
||||
inline void WriteOp_Less(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI < ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//setb al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_B);
|
||||
}
|
||||
|
||||
inline void WriteOp_Leq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI <= ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//setbe al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_BE);
|
||||
}
|
||||
|
||||
inline void WriteOp_Grtr(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI > ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//seta al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_A);
|
||||
}
|
||||
|
||||
inline void WriteOp_Geq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI >= ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//setae al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_AE);
|
||||
}
|
||||
|
||||
inline void WriteOp_Align_Pri(JitWriter *jit)
|
||||
{
|
||||
//xor eax, <cellsize - val>
|
||||
cell_t val = sizeof(cell_t) - jit->read_cell();
|
||||
if (val < SCHAR_MAX && val > SCHAR_MIN)
|
||||
{
|
||||
IA32_Xor_Rm_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val);
|
||||
} else {
|
||||
IA32_Xor_Eax_Imm32(jit, val);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Align_Alt(JitWriter *jit)
|
||||
{
|
||||
//xor edx, <cellsize - val>
|
||||
cell_t val = sizeof(cell_t) - jit->read_cell();
|
||||
if (val < SCHAR_MAX && val > SCHAR_MIN)
|
||||
{
|
||||
IA32_Xor_Rm_Imm8(jit, AMX_REG_ALT, MOD_REG, (jit_int8_t)val);
|
||||
} else {
|
||||
IA32_Xor_Rm_Imm32(jit, AMX_REG_ALT, MOD_REG, val);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Cmps(JitWriter *jit)
|
||||
{
|
||||
//push edi
|
||||
//push esi
|
||||
//lea esi, [ebp+edx]
|
||||
//lea edi, [ebp+eax]
|
||||
//mov ecx, <val>
|
||||
unsigned int val = jit->read_cell();
|
||||
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Push_Reg(jit, REG_ESI);
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
IA32_Mov_Reg_Imm32(jit, REG_ECX, val);
|
||||
|
||||
//xor eax, eax
|
||||
//repe cmpsb
|
||||
//je :cmps1
|
||||
IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
|
||||
IA32_Rep(jit);
|
||||
IA32_Cmpsb(jit);
|
||||
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_E, 0);
|
||||
|
||||
//sbb eax, eax
|
||||
//sbb eax, -1
|
||||
IA32_Sbb_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
|
||||
IA32_Sbb_Rm_Imm8(jit, AMX_REG_PRI, -1, MOD_REG);
|
||||
|
||||
//:cmps1
|
||||
//pop esi
|
||||
//pop edi
|
||||
IA32_Send_Jump8_Here(jit, jmp);
|
||||
IA32_Pop_Reg(jit, REG_ESI);
|
||||
IA32_Pop_Reg(jit, REG_EDI);
|
||||
}
|
||||
|
||||
inline void WriteOp_Lctrl(JitWriter *jit)
|
||||
{
|
||||
cell_t val = jit->read_cell();
|
||||
switch (val)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
//mov ecx, [esi+ctx]
|
||||
//mov eax, [ecx+ctx.codebase]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, codebase));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
//mov eax, ebp
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
//mov eax, [esi+hea]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
//mov ecx, [esi+ctx]
|
||||
//mov eax, [ecx+ctx.memory]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, memory));
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
//mov eax, edi
|
||||
//sub eax, ebp - unrelocate
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_REG);
|
||||
IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
//mov eax, [esi+frm]
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
//mov eax, [cip]
|
||||
jitoffs_t imm32 = IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
jitoffs_t save = jit->get_outputpos();
|
||||
jit->set_outputpos(imm32);
|
||||
jit->write_int32((uint32_t)(jit->outbase + save));
|
||||
jit->set_outputpos(save);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Sctrl(JitWriter *jit)
|
||||
{
|
||||
cell_t val = jit->read_cell();
|
||||
switch (val)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
//mov [esi+hea], eax
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
//lea edi, [ebp+eax]
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, AMX_REG_STK, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
//lea ebx, [ebp+eax] - overwrite frm
|
||||
//mov [esi+frm], eax - overwrite stacked frame
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, AMX_REG_FRM, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_PRI, MOD_MEM_REG);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
IA32_Jump_Reg(jit, AMX_REG_PRI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_UDiv(JitWriter *jit)
|
||||
{
|
||||
//mov ecx, edx
|
||||
//xor edx, edx
|
||||
//div ecx
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG);
|
||||
Write_Check_DivZero(jit, AMX_REG_TMP);
|
||||
IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG);
|
||||
}
|
||||
|
||||
inline void WriteOp_UDiv_Alt(JitWriter *jit)
|
||||
{
|
||||
//mov ecx, eax
|
||||
//mov eax, edx
|
||||
//xor edx, edx
|
||||
//div ecx
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG);
|
||||
Write_Check_DivZero(jit, AMX_REG_TMP);
|
||||
IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG);
|
||||
}
|
||||
|
||||
inline void WriteOp_Ret(JitWriter *jit)
|
||||
{
|
||||
//mov ebx, [edi] - get old FRM
|
||||
//add edi, 4 - pop stack
|
||||
//mov [esi+frm], ebx - restore
|
||||
//add ebx, ebp - relocate
|
||||
//ret
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG);
|
||||
IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
|
||||
IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_FRM, MOD_MEM_REG);
|
||||
IA32_Add_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
inline void WriteOp_JRel(JitWriter *jit)
|
||||
{
|
||||
//jmp <offs> ;relative jump
|
||||
cell_t cip_offs = jit->read_cell();
|
||||
|
||||
/* Note that since code size calculation has to be done in the same
|
||||
* phase as building relocation information, we cannot know the jump size
|
||||
* beforehand. Thus, we always write full 32bit jumps for safety.
|
||||
*/
|
||||
jitoffs_t jmp = IA32_Jump_Imm32(jit, 0);
|
||||
IA32_Write_Jump32(jit, jmp, RelocLookup(jit, cip_offs));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jless(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//jb <target>
|
||||
cell_t target = jit->read_cell();
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32(jit, CC_B, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jleq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//jbe <target>
|
||||
cell_t target = jit->read_cell();
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32(jit, CC_BE, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jgrtr(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//ja <target>
|
||||
cell_t target = jit->read_cell();
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32(jit, CC_A, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jgeq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//jae <target>
|
||||
cell_t target = jit->read_cell();
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32(jit, CC_AE, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_
|
||||
@@ -0,0 +1,103 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
#include "jit_version.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION SVN_FILE_VERSION
|
||||
PRODUCTVERSION SVN_FILE_VERSION
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "000004b0"
|
||||
BEGIN
|
||||
VALUE "Comments", "SourcePawn JIT"
|
||||
VALUE "FileDescription", "SourcePawn JIT/Virtual Machine"
|
||||
VALUE "FileVersion", SVN_FULL_VERSION
|
||||
VALUE "InternalName", "sourcemod"
|
||||
VALUE "LegalCopyright", "Copyright (c) 2004-2008, AlliedModders LLC"
|
||||
VALUE "OriginalFilename", "sourcepawn.jit.x86.dll"
|
||||
VALUE "ProductName", "SourcePawn JIT"
|
||||
VALUE "ProductVersion", SVN_FULL_VERSION
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0, 1200
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
Reference in New Issue
Block a user