Jump to content

  • Log In with Google      Sign In   
  • Create Account

Jason Goepel

Member Since 15 May 2013
Offline Last Active Today, 06:19 AM

Topics I've Started

JIT Compiler Suspend / BlindMindStudios

08 April 2016 - 07:40 AM

When using the BlindMindStudio JIT compiler, functions that suspect the active context are called twice.  The first time within a JIT block, the second from the AngelScript VM, and with the stack not properly set up for the call.


I suspect this issue is a bug in BlindMindStudio's JIT compiler rather than in AngelScript, but I don't know quite enough yet to be sure.


When a context is suspended from a function called with a JIT block, it appears that the program pointer doesn't properly advance to the "next line."  The VM advances from the asBC_JitEntry instruction to the asBC_CALLSYS instruction.  If I remove the call to asIScriptContext::Suspend, then the VM doesn't ever process the asBC_CALLSYS instruction.


I have included an example below that demonstrates the problem.

#include <iostream>
#include "angelscript.h"
#include "as_jit.h"
using namespace std;

void Yield(int arg)
	cout << "Performing Yield... arg = " << arg << endl;

int main(int argc, char* argv[])
	asIScriptEngine* engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	asCJITCompiler* jit = new asCJITCompiler(0);
	engine->SetEngineProperty(asEP_INCLUDE_JIT_INSTRUCTIONS, 1);

	int r;
	r = engine->RegisterGlobalFunction("void Yield(int)", asFUNCTION(Yield), asCALL_CDECL);
	asIScriptModule* mod = engine->GetModule("module", asGM_ALWAYS_CREATE);

	const char* sz_code = "int main() { Yield(5); return 0; }";

	mod->AddScriptSection("main", sz_code);
	r = mod->Build();

	asIScriptContext* ctx = engine->CreateContext();
	asIScriptFunction* func = mod->GetFunctionByName("main");
		r = ctx->Execute();
	} while (r == asEXECUTION_SUSPENDED);

	int return_value = ctx->GetReturnDWord();

	delete jit;
	return return_value;

CallFuction Exceptions

07 December 2015 - 01:59 PM

The call to CallSystemFunctionNative is wrapped in a try/catch block so that it can catch exceptions thrown by a registered function.  However, if the function is registered with asCALL_GENERIC then there is no try/catch block.  Is this intentional or an oversight?  My application has a mix of function registrations, some of them using asCALL_GENERIC, so the effect is that some exceptions thrown by a registered function are caught while others are not.

Unsafe const &in

25 September 2015 - 03:40 PM

Turning on unsafe references allows in-out references to be used for primitives and value types, meaning a function prototyped like:

   void func(const ValueType &inout x) 

will pass a reference to the function and not make a copy.  This works just fine, but it seems like this should also work for a constant in reference:

   void func(const ValueType &in x)


However, a copy will always be made for a value type passed to an in reference, even if the in reference is constant.  This construct causes my users confusion, so I took a quick look at trying to modify the code in asCCompiler::PrepareArgument. The solution looks like it would be more complicated than simply changing what PrepareArgument does in response to an in reference.  It looks like there are a lot of checks in the compiler that check the reference type and make assumptions about what an argument is allowed to be.  Is this an accurate understanding?


It seems like the checks against the reference type in asCCompiler::MoveArgsToStack would also need to be modified, but I don't quite grasp what the new tests would be.


I would appreciate any help, thanks.


(P.S. It would also be nice to have a constant in-out reference be able to construct a temporary object if the argument passed in is found in the parameter type's constructor)


Calling Convention Bug?

27 April 2015 - 12:26 PM

I've discovered some sort of bug in the "CallSystemFunction."  I have only encountered it in x64 Windows builds (Visual Studio 2013).


It looks like the code cleaning up the arguments incorrectly attempts to clean up the return variable.  To trigger the bug, I register a class with a destructor and register a function that returns an instance of this object and takes one as an argument, so that the argument needs to be cleaned up.  The cleanup code will then attempt to free the argument, but it will mistakenly pass a pointer to the return variable to be freed.  This pointer is not a valid heap pointer, so there is a crash.


The attached file can be added to the test project to demonstrate the problem.


The fix may be something as simple as adding the following code the the cleanup section, but I am not familiar enough with how the AngelScript compiler manages its memory and sets up function calls to make that judgement.



// Clean up arguments
const asUINT cleanCount = sysFunc->cleanArgs.GetLength();
if( cleanCount )
    args = context->m_regs.stackPointer;
    if( callConv >= ICC_THISCALL )
        args += AS_PTR_SIZE;

    //** New code to address bug **/
    if( descr->DoesReturnOnStack() )
        args += AS_PTR_SIZE;

    asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf();
    for( asUINT n = 0; n < cleanCount; n++, clean++ )
        void **addr = (void**)&args[clean->off];
        if( clean->op == 0 )
            if( *addr != 0 )
                engine->CallObjectMethod(*addr, clean->ot->beh.release);
                *addr = 0;
            asASSERT( clean->op == 1 || clean->op == 2 );
            asASSERT( *addr );

            if( clean->op == 2 )
                engine->CallObjectMethod(*addr, clean->ot->beh.destruct);

"Null pointer access" putting object type in exception info

01 April 2015 - 12:20 PM

In an effort to provide more helpful error messages to my script writers, I have been looking for a way to make "null pointer access" a little more descriptive.  Most of my script writers are technical people, but their programming training is very thin.  "Null pointer access" pretty much doesn't mean anything to them.  I am hoping to provide something like "Instance of CDemoClass has not been properly initialized" or something, potentially varying based on the object.


I don't have a good way of accomplishing this within the Exception callback framework, short of analyzing the line where an exception occurred.  I have been considering adding object information, when it exists, to the context (something like m_exceptionObjectType) which could be read during the exception callback.


I know there are many instances where the object type is not readily available (like asBC_CHKREF), so I was wondering if you had any thoughts about this.