jit refactoring branch

--HG--
branch : refac-jit
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/branches/refac-jit%402369
This commit is contained in:
David Anderson
2008-07-06 04:49:55 +00:00
commit 2e7b6b5ba5
879 changed files with 297155 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
# (C)2004-2008 SourceMod Development Team
# Makefile written by David "BAILOPAN" Anderson
SMSDK = ../../..
#####################################
### EDIT BELOW FOR OTHER PROJECTS ###
#####################################
PROJECT = sourcepawn.jit.x86
OBJECTS = dll_exports.cpp jit_x86.cpp opcode_helpers.cpp
##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
##############################################
C_OPT_FLAGS = -DNDEBUG -O3 -funroll-loops -pipe -fno-strict-aliasing
C_DEBUG_FLAGS = -D_DEBUG -DDEBUG -g -ggdb3
C_GCC4_FLAGS = -fvisibility=hidden
CPP_GCC4_FLAGS = -fvisibility-inlines-hidden
CPP = gcc-4.1
LINK = -static-libgcc
INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/jit -I$(SMSDK)/public/jit/x86 \
-I$(SMSDK)/public/sourcepawn
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -DHAVE_STDINT_H \
-m32
CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
################################################
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
################################################
ifeq "$(DEBUG)" "true"
BIN_DIR = Debug
CFLAGS += $(C_DEBUG_FLAGS)
else
BIN_DIR = Release
CFLAGS += $(C_OPT_FLAGS)
endif
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
ifeq "$(GCC_VERSION)" "4"
CFLAGS += $(C_GCC4_FLAGS)
CPPFLAGS += $(CPP_GCC4_FLAGS)
endif
BINARY = $(PROJECT).so
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
$(BIN_DIR)/%.o: %.cpp
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
all:
mkdir -p $(BIN_DIR)
$(MAKE) -f Makefile jit
jit: $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
debug:
$(MAKE) -f Makefile all DEBUG=true
default: all
clean:
rm -rf $(BIN_DIR)/*.o
rm -rf $(BIN_DIR)/$(BINARY)
+99
View File
@@ -0,0 +1,99 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* 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
+47
View File
@@ -0,0 +1,47 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* 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_
+38
View File
@@ -0,0 +1,38 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_JIT_VERSION_H_
#define _INCLUDE_JIT_VERSION_H_
#define SVN_FULL_VERSION "1.1.0-svn"
#define SVN_FILE_VERSION 1,1,0,2218
#endif //_INCLUDE_JIT_VERSION_H_
+38
View File
@@ -0,0 +1,38 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* 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$-svn"
#define SVN_FILE_VERSION $PMAJOR$,$PMINOR$,$PREVISION$,$LOCAL_BUILD$
#endif //_INCLUDE_JIT_VERSION_H_
File diff suppressed because it is too large Load Diff
+162
View File
@@ -0,0 +1,162 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* 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_
+20
View File
@@ -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
+296
View File
@@ -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>
+909
View File
@@ -0,0 +1,909 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* 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);
}
}
}
+321
View File
@@ -0,0 +1,321 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* 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_
+779
View File
@@ -0,0 +1,779 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* 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;
}
+121
View File
@@ -0,0 +1,121 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* 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;
}
+325
View File
@@ -0,0 +1,325 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* 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_
+103
View File
@@ -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