/*++ Copyright (c) Ken Johnson (Skywing). All rights reserved. Module Name: NWNScriptJIT.cpp Abstract: This module houses the externally visible interface of the JIT library. N.B. The external interface is native only and may NOT reference any C++/CLI constructs. --*/ #include "Precomp.h" #include "NWNScriptJIT.h" #include "NWScriptJITLib.h" // Not used, but just to make sure we compile. #include "NWScriptProgram.h" #include "NWScriptSavedState.h" using System::Runtime::InteropServices::GCHandle; BOOLEAN NWSCRIPTJITAPI NWScriptGenerateCode( __in NWScriptReaderState * Script, __in_ecount( ActionCount ) PCNWACTION_DEFINITION ActionDefs, __in NWSCRIPT_ACTION ActionCount, __in ULONG AnalysisFlags, __in_opt IDebugTextOut * TextOut, __in ULONG DebugLevel, __in INWScriptActions * ActionHandler, __in NWN::OBJECTID ObjectInvalid, __in_opt PCNWSCRIPT_JIT_PARAMS CodeGenParams, __out PNWSCRIPT_JITPROGRAM GeneratedProgram ) /*++ Routine Description: This routine generates native code for a NWScript program, given an analyzer that defines the program's function. A program handle is returned to the caller, for use with the NWScriptExecuteScript API. The caller bears responsibility for deleting the generated program via a call to the NWScriptDeleteProgram API. Arguments: Script - Supplies a pointer to the script to analyze. ActionDefs - Supplies the action table to use when analyzing the script. ActionCount - Supplies the count of entries in the action table. AnalysisFlags - Supplies flags that control the program analysis. Legal values are drawn from the ANALYZE_FLAGS enumeration: AF_STRUCTURE_ONLY - Only the program structure is analyzed. AF_NO_OPTIMIZATIONS - Skip the optimization pass. TextOut - Optionally supplies an IDebugTextOut interface that receives text debug output from the execution environment. DebugLevel - Supplies the debug output level. Legal values are drawn from the NWScriptVM::ExecDebugLevel family of enumerations. ActionHandler - Supplies the engine actions implementation handler. ObjectInvalid - Supplies the object id to reference for the 'object invalid' manifest constant. CodeGenParams - Optionally supplies extension code generation parameters. GeneratedProgram - On success, receives the program native code handle. Return Value: The routine returns a Boolean value indicating TRUE on success, else FALSE on failure. Environment: User mode, C++/CLI invoked from external caller. --*/ { if ((CodeGenParams != NULL) && (CodeGenParams->Size != sizeof( *CodeGenParams ))) { return FALSE; } try { NWScriptReader Reader( Script->ScriptName, Script->InstructionStream, Script->InstructionStreamSize, Script->SymTab, Script->SymTabSize); NWScriptAnalyzer Analyzer( TextOut, ActionDefs, ActionCount); // // First, generate the IR for the program. // Analyzer.Analyze( &Reader, AnalysisFlags ); // // Now translate the IR into MSIL. // try { NWScriptProgram ^ Program; GCHandle RetHandle; Program = gcnew NWScriptProgram( &Analyzer, TextOut, DebugLevel, ActionHandler, ObjectInvalid, CodeGenParams); RetHandle = GCHandle::Alloc( Program ); *GeneratedProgram = (NWSCRIPT_JITPROGRAM) (IntPtr) RetHandle; return TRUE; } catch (Exception ^) { return FALSE; } } catch (std::exception &e) { if ((TextOut != NULL) && (DebugLevel >= NWScriptVM::EDL_Errors)) { TextOut->WriteText( "NWScriptGenerateCode: Exception '%s' generating code for script '%s'.\n", e.what( ), Script->ScriptName); } return FALSE; } } BOOLEAN NWSCRIPTJITAPI NWScriptDeleteProgram( __in NWSCRIPT_JITPROGRAM GeneratedProgram ) /*++ Routine Description: This routine releases resources allocated by NWScriptGenerateCode. Arguments: GeneratedProgram - Supplies the program to release. Return Value: The routine returns a Boolean value indicating TRUE on success, else FALSE on failure. Environment: User mode, C++/CLI invoked from external caller. --*/ { try { GCHandle Handle = (GCHandle) (IntPtr) GeneratedProgram; Handle.Free( ); return TRUE; } catch (Exception ^) { return FALSE; } } BOOLEAN NWSCRIPTJITAPI NWScriptSaveState( __in NWSCRIPT_JITPROGRAM GeneratedProgram, __out PNWSCRIPT_JITRESUME ResumeState ) /*++ Routine Description: This routine creates a copy of the most recently saved program state and returns it to the caller. The program state can be used to resume the associated program at a SAVE_STATE resume point (via the NWScriptExecuteScriptSituation API). Note that executing the saved state may be performed only once, but it does not delete the saved state. Arguments: GeneratedProgram - Supplies the program to return the last saved state for. ResumeState - On success, receives a new resumed state handle. The state handle may be used only once, after which it must be released via a call to NWScriptDeleteSavedState. Return Value: The routine returns a Boolean value indicating TRUE on success, else FALSE on failure. Environment: User mode, C++/CLI invoked from external caller. --*/ { try { GCHandle Handle = (GCHandle) (IntPtr) GeneratedProgram; NWScriptProgram ^ Program = (NWScriptProgram ^) Handle.Target; NWScriptSavedState ^ SavedState; GCHandle RetHandle; SavedState = Program->GetSavedState( ); RetHandle = GCHandle::Alloc( SavedState ); *ResumeState = (NWSCRIPT_JITRESUME) (IntPtr) RetHandle; return TRUE; } catch (Exception ^) { return FALSE; } } BOOLEAN NWSCRIPTJITAPI NWScriptDeleteSavedState( __in NWSCRIPT_JITRESUME ResumeState ) /*++ Routine Description: This routine releases resources allocated by NWScriptSaveState. Arguments: ResumeState - Supplies the saved state to release. Return Value: The routine returns a Boolean value indicating TRUE on success, else FALSE on failure. Environment: User mode, C++/CLI invoked from external caller. --*/ { try { GCHandle Handle = (GCHandle) (IntPtr) ResumeState; Handle.Free( ); return TRUE; } catch (Exception ^) { return FALSE; } } int NWSCRIPTJITAPI NWScriptExecuteScript( __in NWSCRIPT_JITPROGRAM GeneratedProgram, __in INWScriptStack * VMStack, __in NWN::OBJECTID ObjectSelf, __in_ecount_opt( ParamCount ) const NWScriptParamString * Params, __in size_t ParamCount, __in int DefaultReturnCode, __in ULONG Flags ) /*++ Routine Description: This routine executes a script main routine. The main routine is either a "void main(void)" or an "int StartingConditional(Params)" routine. In the latter case, a return value may be supplied as an integer. Otherwise zero is returned. Arguments: GeneratedProgram - Supplies the script program handle to execute. VMStack - Supplies the stack instance that is used to pass parameters to action service handlers. ObjectSelf - Supplies the object id to reference for the 'object self' manifest constant. Params - Supplies an optional parameter set to pass to the script StartingConditional entry point. ParamCount - Supplies the count of parameters to the entry point. DefaultReturnCode - Supplies the default return code on an error condition, or if the script did not return a value. Flags - Supplies flags that control the execution environment of the script. The flags are the same as those that are accepted by the NWScriptVM::ExecuteScript API. Return Value: If the script is a StartingConditional, its return value is returned. Otherwise, the default return code is returned. Environment: User mode, C++/CLI invoked from external caller. --*/ { try { GCHandle Handle = (GCHandle) (IntPtr) GeneratedProgram; NWScriptProgram ^ Program = (NWScriptProgram ^) Handle.Target; return Program->ExecuteScript( VMStack, ObjectSelf, Params, ParamCount, DefaultReturnCode, Flags); } catch (Exception ^) { return DefaultReturnCode; } } BOOLEAN NWSCRIPTJITAPI NWScriptExecuteScriptSituation( __in NWSCRIPT_JITRESUME ResumeState ) /*++ Routine Description: This routine executes a script situation, which is a saved portion of a script that is later run (such as a delayed action). Arguments: ResumeState - Supplies the state of the script to execute. Return Value: The routine returns a Boolean value that indicates TRUE on success, else FALSE on failure. Environment: User mode, C++/CLI invoked from external caller. --*/ { try { GCHandle Handle = (GCHandle) (IntPtr) ResumeState; NWScriptSavedState ^ State = (NWScriptSavedState ^) Handle.Target; NWScriptProgram ^ Program = State->GetProgram( ); Program->ExecuteScriptSituation( State ); return TRUE; } catch (Exception ^) { return FALSE; } } BOOLEAN NWSCRIPTJITAPI NWScriptAbortScript( __in NWSCRIPT_JITPROGRAM GeneratedProgram ) /*++ Routine Description: This routine aborts a script prematurely. Once control returns to the script execution environment, the executed program terminates and returns to its caller. This routine may only be invoked within the context of an action service handler. Arguments: GeneratedProgram - Supplies the program to abort. Return Value: The routine returns a Boolean value that indicates TRUE on success, else FALSE on failure. Environment: User mode, C++/CLI invoked from external caller. --*/ { try { GCHandle Handle = (GCHandle) (IntPtr) GeneratedProgram; NWScriptProgram ^ Program = (NWScriptProgram ^) Handle.Target; Program->AbortScript( ); return TRUE; } catch (Exception ^) { return FALSE; } } BOOLEAN NWSCRIPTJITAPI NWScriptIsScriptAborted( __in NWSCRIPT_JITPROGRAM GeneratedProgram ) /*++ Routine Description: This routine returns whether a script program has been flagged for early termination. Arguments: GeneratedProgram - Supplies the program to inquire about the abortion status for. Return Value: The routine returns a Boolean value that indicates TRUE should the script program have been flagged for abort, else FALSE if it has not been flagged for abort. Note that the abort flag is reset to FALSE once the script program has been actually aborted. Environment: User mode, C++/CLI invoked from external caller. --*/ { try { GCHandle Handle = (GCHandle) (IntPtr) GeneratedProgram; NWScriptProgram ^ Program = (NWScriptProgram ^) Handle.Target; if (Program->IsScriptAborted( )) return TRUE; else return FALSE; } catch (Exception ^) { return FALSE; } } BOOLEAN NWSCRIPTJITAPI NWScriptCheckVersion( __in NWSCRIPT_JIT_VERSION Version, __in ULONG VersionValue ) /*++ Routine Description: This routine compares a version value with that supplied by the user of the library. Its purpose is to provide early detection of some (but not all) errors that might be introduced by compilation differences in the exposed C+++ interface. Arguments: Version - Supplies the version class to compare. Legal values are drawn from the NWSCRIPT_JIT_VERSION family of enumerations. VersionValue - Supplies the version value to check. Return Value: The routine returns a Boolean value that indicates TRUE should the version value be compatible, else FALSE if it is incompatible. Should the routine return FALSE, the caller must not make use of the library, as it is incompatible with the caller's requirements. Environment: User mode, C++/CLI invoked from external caller. --*/ { try { switch (Version) { case NWScriptJITVersion_APIVersion: return (VersionValue == NWSCRIPTJITAPI_CURRENT); case NWScriptJITVersion_NWScriptReaderState: return (VersionValue == sizeof( NWScriptReaderState )); case NWScriptJITVersion_NWScriptStack: return (VersionValue == sizeof( NWScriptStack )); case NWScriptJITVersion_NWScriptParamVec: return (VersionValue == sizeof( NWScriptParamVec )); case NWScriptJITVersion_NWACTION_DEFINITION: return (VersionValue == sizeof( NWACTION_DEFINITION )); case NWScriptJITVersion_NeutralString: return (VersionValue == sizeof( NeutralString )); default: return FALSE; } } catch (Exception ^) { return FALSE; } }