Jump to content

  • Log In with Google      Sign In   
  • Create Account


- - - - -

Function parameter problem


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
19 replies to this topic

#1 Heuristics   Members   -  Reputation: 147

Like
0Likes
Like

Posted 23 September 2012 - 01:17 AM

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.

Edited by Andreas Jonsson, 14 October 2012 - 05:25 PM.


Sponsor:

#2 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 23 September 2012 - 05:04 AM

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

#3 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 23 September 2012 - 05:23 AM

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

#4 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 23 September 2012 - 06:23 AM

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.

Edited by Andreas Jonsson, 23 September 2012 - 06:24 AM.

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

#5 Heuristics   Members   -  Reputation: 147

Like
0Likes
Like

Posted 23 September 2012 - 07:46 AM

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 :)

#6 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 07 October 2012 - 11:29 AM

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

#7 Heuristics   Members   -  Reputation: 147

Like
0Likes
Like

Posted 09 October 2012 - 02:59 AM

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).

Edited by Heuristics, 09 October 2012 - 03:09 AM.


#8 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 09 October 2012 - 08:03 AM

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

#9 Heuristics   Members   -  Reputation: 147

Like
0Likes
Like

Posted 10 October 2012 - 02:27 AM

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

#10 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 10 October 2012 - 07:00 PM

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

#11 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 12 October 2012 - 05:53 PM

I've updated the code::blocks project files in revision 1431.

I tried installing mingw too, but the installer from the mingw site appears to only install version 4.6, not 4.7. The mingw version that comes with code::blocks is even older.

Where do you get version 4.7 from? Is it necessary to download each file manually?
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#12 Heuristics   Members   -  Reputation: 147

Like
0Likes
Like

Posted 13 October 2012 - 01:20 AM

I think I did something like getting this file: http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/mingw-get-inst-20120426/
and during the installation I picked "download latest repository catalogues". From checking now that appears to download mingw 4.7

#13 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 13 October 2012 - 11:41 AM

Thanks, I'll give that a try.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#14 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 14 October 2012 - 11:37 AM

I'm making some progress.

However, there are more changes in MinGW 4.7 than I had expected. It will be a while longer before I can complete all the changes and tests needed to get this fully working.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#15 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
1Likes
Like

Posted 14 October 2012 - 05:30 PM

It appears that I made a break-through. As of revision 1435, all tests pass successfully with MinGW32 4.7.0 and 4.6.2.

The MinGW developers made some strange choices with the new ABI. For the most part they seem to have wanted to more closely follow the MS ABI, most likely to make it easier to use the many dlls available, but in some cases they ended up with something that is neither like the MS ABI nor the GNUC ABI. This doesn't make any sense at all to me, and quite frankly I believe they may very well change it again with a future version.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#16 Heuristics   Members   -  Reputation: 147

Like
0Likes
Like

Posted 15 October 2012 - 12:26 PM

Great to hear!

I tested it as well with my own code and it does indeed appear to work. Thanks a lot, I very much appreciate the very quick fix to this issue. I now get to use fancy c++11 features with angelscript :)

Strange about the ABI though, but then again I know little about such things. But I do know that it is sometimes hard to understand how the GNU devs pick their priorities.

#17 Heuristics   Members   -  Reputation: 147

Like
0Likes
Like

Posted 21 October 2012 - 01:14 PM

Hello again.

I extended my little test code with using a class as value instead of as reference and then it crashes in mingw 4.7.0 but works fine in 4.6.0. Perhaps this is another problem? (or I might just be doing it wrong :) )

Here is the modified example: http://pastebin.com/27BzeQcy

#18 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 21 October 2012 - 02:58 PM

That it works on 4.6, but not on 4.7 does seem to indicate the problem is related to the changes done in MinGW, but I'll need to investigate it to be sure.

I'll let know when I figure it out. Thanks.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#19 Andreas Jonsson   Moderators   -  Reputation: 3241

Like
0Likes
Like

Posted 21 October 2012 - 05:32 PM

The problem was not with MinGW after all.

You've implemented the constructor and destructor incorrectly. They should be global functions, or static members, and registered with asCALL_CDECL_OBJLAST instead of asCALL_THISCALL.

It didn't crash on MinGW 4.6.0 because before 4.7 the thiscall was practically identical to the cdecl calling convention.

class Person {
    public:
	    Person() {cout<<(int)this<<endl;this->counter = 1;}
	    static void Constructor(void *memory) {new(memory) Person();}
	    static void Destructor(void *memory) {((Person*)memory)->~Person();}
	    void printTwoInts(int a, int b) { cout << (int)this << " " << a << " " << b << endl; }
	    void AddRef() {cout<<this<<" 1 "<<this->counter;}
	    void ReleaseRef() {cout<<this<<" 2 "<<this->counter;}
	    static Person *refFactory() {
		    return new Person();
	    };
	    int counter;
};

void main()
{
  ...
  asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
  engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
  r = engine->RegisterObjectType("Person", sizeof(Person), asOBJ_VALUE | asOBJ_POD); assert( r >= 0 );
  r = engine->RegisterObjectBehaviour("Person", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Person::Constructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
  r = engine->RegisterObjectBehaviour("Person", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Person::Destructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
 
  r = engine->RegisterObjectMethod("Person", "void printTwoInts(int a, int b)", asMETHOD(Person, printTwoInts), asCALL_THISCALL);assert( r >= 0 );
}

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

#20 Heuristics   Members   -  Reputation: 147

Like
0Likes
Like

Posted 23 October 2012 - 02:05 AM

Ah!

That makes sense, I feel a bit silly now :) (was mislead by it not crashing on 4.6.0). Sorry about that. But thank you very much for your help again!




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS