Function parameter problem

Started by
18 comments, last by Heuristics 11 years, 5 months ago
Hello!

I am new to angelscript and I have a problem where the first parameter to a registered object method is always the object itself. What can I do to fix this? Here is some example code:

[source lang="cpp"]void MessageCallback_(const asSMessageInfo *msg, void *param) {
const char *type = "ERR ";
if( msg->type == asMSGTYPE_WARNING )
type = "WARN";
else if( msg->type == asMSGTYPE_INFORMATION )
type = "INFO";
printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}
[/source]

[source lang="cpp"]class Person {
public:
Person() {}
void printTwoInts(int a, int b);
void AddRef() {}
void ReleaseRef() {}
static Person *refFactory() {
return new Person();
};

};
Person::printTwoInts(int a, int b){
cout (int)this " " a " " b endl;
}
(had to remove left arrows for cout in the above code above)
[/source]

[source lang="cpp"]int main() {
asIScriptEngine *scriptEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
int r = scriptEngine->SetMessageCallback(asFUNCTION(MessageCallback_), 0, asCALL_CDECL);assert( r >= 0 );
r = scriptEngine->RegisterObjectType("Person", sizeof(Person), asOBJ_REF); assert( r >= 0 );
r = scriptEngine->RegisterObjectBehaviour("Person", asBEHAVE_FACTORY, "Person @f()", asFUNCTION(Person::refFactory), asCALL_CDECL); assert( r >= 0 );
r = scriptEngine->RegisterObjectBehaviour("Person", asBEHAVE_ADDREF, "void f()", asMETHOD(Person, AddRef), asCALL_THISCALL); assert( r >= 0 );
r = scriptEngine->RegisterObjectBehaviour("Person", asBEHAVE_RELEASE, "void f()", asMETHOD(Person, ReleaseRef), asCALL_THISCALL); assert( r >= 0 );

r = scriptEngine->RegisterObjectMethod("Person", "void printTwoInts(int a, int b)", asMETHOD(Person, printTwoInts), asCALL_THISCALL);assert( r >= 0 );

CScriptBuilder builder;
r = builder.StartNewModule(scriptEngine, "Test"); assert( r >= 0 );
r = builder.AddSectionFromFile("./Test.as"); assert( r >= 0 );
r = builder.BuildModule();if( r < 0 ); assert( r >= 0 );

asIScriptModule *mod = scriptEngine->GetModule("Test");
asIScriptFunction *func = mod->GetFunctionByDecl("void main()");
asIScriptContext *ctx = scriptEngine->CreateContext();
ctx->Prepare(func);
r = ctx->Execute();
return 0;
}[/source]


The Test.as script is as:

[source lang="cpp"]void main() {
Person p;
p.printTwoInts(999,55);
}[/source]


When run this outputs: "8097752 8097752 999" Meaning the first parameter is not an int but an object pointer. So the function calling is done wrong? But when I try to change asCALL_THISCALL to asCALL_CDECL, asCALL_STDCALL, asCALL_CDECL_OBJLAST, asCALL_CDECL_OBJFIRST or asCALL_GENERIC I get an error code: -24. -24 is asWRONG_CALLING_CONV but I don't know how to fix that. Do I need to use something else other then asMETHOD when registering the function? If so what?

I am using mingw 4.7.0.

Thanks.
Advertisement
You did everything correctly.

I think this might be a problem with the native calling conventions support specifically for MinGW. Possibly just for the version of MinGW that you're using.

Until I've figured out what the problem is, I suggest you work around it by using the auto wrappers. To do this, include the /sdk/add_on/autowrapper/aswrappedcall.h header, replace the asMETHOD macro with WRAP_MFN, and asCALL_THISCALL with asCALL_GENERIC.

Or switch to Microsoft Visual C++. The Express version is free, and can be downloaded from Microsoft's home page. Unless you have a very specific motive for using MinGW, I recommend looking into using MSVC even if you weren't facing the problem above.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

It looks like MinGW may have changed the way they implement the thiscall calling convention in this version. Earlier versions of MinGW used to work like GNUC does on Linux, in that the object pointer is put in the ECX register and pushed on the stack. Probably the MinGW developers decided to change this to work like MSVC do, i.e. only move the object pointer into the ECX register. Presumably they did this to make MinGW generated code compatible with MSVC generated dlls.

If I'm right, I'll have to make some changes in AngelScript to verify the version of MinGW used and adapt the code accordingly.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

The release notification to the MinGW mailing lists, confirms that version 4.7.0 changed the C++ ABI for thiscall methods. So that explains why you're facing the problem that you do.

I believe the change to make AngelScript compatible with the new version of MinGW is simple, but unfortunately I will not have time to validate it myself right now, as I'm about to leave for vacation.

If you feel like giving it a try yourself the changes I believe are needed are to remove a few lines from the as_callfunc_x86.cpp file:

In function CallThisCallFunction, remove the lines:

1094: "pushl %%ecx \n" // push obj on the stack
1097: "addl $4, %%esp \n" // pop obj

In function CallThisCallFunctionRetByRef, remove the lines:

1218: "pushl %%ecx \n" // push obj on the stack
1225: "addl $4, %%esp \n" // pop the object pointer


Removing these 4 lines should hopefully make things work again in MinGW 4.7.0.

Of course, before I check-in these changes to the SVN I need to confirm that they actually work, and the change also needs to made in such a way that only MinGW 4.7.0 is affected, otherwise it will break for earlier versions of MinGW and gcc.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game



Removing these 4 lines should hopefully make things work again in MinGW 4.7.0.


Thank you! I tested this (with my simple example above in mingw 4.7.0) and it appears to work. Hope you have a nice vacation :)
I've checked in the fix with revision 1428.

Thanks for the help in confirming the fix.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game


I've checked in the fix with revision 1428.

Thanks for the help in confirming the fix.


Hello again. Thanks for doing these changes.

I have been looking in to this a bit more and I am starting to wonder if the addref/releaserefs are called correctly (I haven't yet checked this for when registering as value).

Here is the code example again: http://pastebin.com/KjsSrJPP this time in compilable form in case you want to test this yourself.

What happens when I run this with mingw 4.7.0 is that some of the output of the application is correct (the class constructor is called and the class executes its printTwoInts function correctly) but ReleaseRef does not get called, also ctx->Execute() crashes with eip having the value 0xababababa.

when compiling and running it with mingw 4.6.2 the ReleaseRef function gets called correctly and no crash (that is everything is fine).
MinGW 4.7 probably has more changes to the ABI then.

Can you run the test_feature project with MinGW 4.7 and tell me which tests pass, and which don't? Especifically the tests focused on the native calling conventions (starting at line 324 in main.cpp). You'll find the code for the project in the SVN.

This will help me figure out what needs to be modified to add compatibility for MinGW 4.7.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game


MinGW 4.7 probably has more changes to the ABI then.

Can you run the test_feature project with MinGW 4.7 and tell me which tests pass, and which don't? Especifically the tests focused on the native calling conventions (starting at line 324 in main.cpp). You'll find the code for the project in the SVN.

This will help me figure out what needs to be modified to add compatibility for MinGW 4.7.


I am unable to get that project to compile, I tried the codeblocks, cmake and mingw projects. The mingw one gives: 4.6.3/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible ./libangelscript.a when searching for -langelscript
The codeblocks project is unable to find 3 .o files and the cmake project cannot find the angelscript.h file
The project files needs adjusting. I only use the MSVC6, MSVC9, and gnuc projects myself so those are the only ones I can guarantee are working out-of-the-box.

Looks like the mingw project is trying to compile the test project with a different target architecture than the library was compiled with.

The codeblocks project obviously need to have the files updated. There has several additions and changes since that project was last updated.

The cmake appears to lack information about the search path. Possibly and environment variable needs to be set in order to use it.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement