• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Heuristics

Function parameter problem

19 posts in this topic

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
0

Share this post


Link to post
Share on other sites
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 [url="http://www.angelcode.com/angelscript/sdk/docs/manual/doc_addon_autowrap.html"]auto wrappers[/url]. 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.
0

Share this post


Link to post
Share on other sites
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.
0

Share this post


Link to post
Share on other sites
[url="http://lists-archives.com/mingw-users/23557-mingw-gcc-4-7-0-released.html"]The release notification to the MinGW mailing lists, confirms that version 4.7.0 changed the C++ ABI for thiscall methods[/url]. 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
0

Share this post


Link to post
Share on other sites
[quote name='Andreas Jonsson' timestamp='1348403016' post='4982892']

Removing these 4 lines should hopefully make things work again in MinGW 4.7.0.
[/quote]

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

Share this post


Link to post
Share on other sites
[quote name='Andreas Jonsson' timestamp='1349630981' post='4987717']
I've checked in the fix with revision 1428.

Thanks for the help in confirming the fix.
[/quote]

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: [url="http://pastebin.com/KjsSrJPP"]http://pastebin.com/KjsSrJPP[/url] 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
0

Share this post


Link to post
Share on other sites
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.
0

Share this post


Link to post
Share on other sites
[quote name='Andreas Jonsson' timestamp='1349791382' post='4988349']
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.
[/quote]

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
0

Share this post


Link to post
Share on other sites
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.
0

Share this post


Link to post
Share on other sites
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?
0

Share this post


Link to post
Share on other sites
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
0

Share this post


Link to post
Share on other sites
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.
0

Share this post


Link to post
Share on other sites
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.
1

Share this post


Link to post
Share on other sites
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.
0

Share this post


Link to post
Share on other sites
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
0

Share this post


Link to post
Share on other sites
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.
0

Share this post


Link to post
Share on other sites
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.

[code]
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 );
}
[/code]

Regards,
Andreas
0

Share this post


Link to post
Share on other sites
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!
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0