Assertion Error and Other Questions

24 views
Skip to first unread message

Grant Posner

unread,
Oct 10, 2013, 12:10:34 AM10/10/13
to asmji...@googlegroups.com
I'm attempting to use AsmJIT in a stack-based language implementation here (BitBucket) and while running the word compiler on a test word (which will just push 5 and 10, and then add them), I get an assertion error:
 
*** ASSERTION FAILURE at ..\AsmJit\CompilerX86X64.cpp (line 3588)
*** osrc.isVar()
 
A small example of code that will cause this is:
 
#include <AsmJit.h>
using namespace AsmJit;
 
// CompiledFunc: pointer to (nothing -> void)
typedef void (*CompiledFunc)();
 
typedef char byte;
 
struct LObject { byte tag; int value; }
 
#define TAG_INT 0
 
LObject make_lobject(byte tag, int value)
{
    LObject obj;
    obj.tag = tag;
    obj.value = value;
    return obj;
}
 
// should push an object. do nothing...
void push_obj(LObject obj) { }
 
// should pop an object. return the same object every time...
LObject pop_obj() { return make_lobject(TAG_INT, 0); }
 
// a b -- a+b
void add()
{
 LObject right = pop_obj();
 LObject left = pop_obj();
 push_obj(make_lobject(TAG_INT, left.value + right.value));
}
 
void main()
{
    Compiler c;
   
    // create a function to generate code for
    EFunction* func = c.newFunction(CALL_CONV_DEFAULT, FunctionBuilder0<int>());
    // attempt to generate without prologue/epilogue
    func->setHint(FUNCTION_HINT_NAKED, true);
    
    // generate a call that in C would look like: push_obj(TAG_INT, 5);
    ECall* push_int5 = c.call((void*)(&push_obj));
    push_int5->setPrototype(CALL_CONV_DEFAULT, FunctionBuilder2<int, byte, int>());
    push_int5->setArgument(0, imm(TAG_INT)); 
    push_int5->setArgument(1, imm(5));
    
    // generate a call that in C would look like: push_obj(TAG_INT, 10);
    ECall* push_int10 = c.call((void*)(&push_obj));
    push_int10->setPrototype(CALL_CONV_DEFAULT, FunctionBuilder2<int, byte, int>());
    push_int10->setArgument(0, imm(TAG_INT));
    push_int10->setArgument(1, imm(10));
 
    // generate a call call to the add() function above.
    ECall* word_call = c.call(&add);
    FunctionBuilder0<int> x;
    word_call->setPrototype(CALL_CONV_DEFAULT, FunctionBuilder0<int>());
 
    // now finish and compile the function
    c.endFunction();
    CompiledWord word = function_cast<CompiledWord>(c.make());
 
    // and call it
    (*word)();
}
 
I'm not sure what my code is doing incorrectly... any hints?
 
And also, how can I tell AsmJIT to call a function that takes no arguments and returns void (i.e. nothing)? Currently I'm just using FunctionBuilder0<int>, but that feels wrong; the function really is not returning an integer.
Another question: how can I generate a tail-call? I just want to be able to jump to a function, instead of calling it. Does AsmJIT do this? And if so, how do I tell AsmJIT to do the tail-call?
 
Thanks!

Petr Kobalíček

unread,
Oct 10, 2013, 2:09:01 AM10/10/13
to asmjit-dev
Hi Grant,

I'm glad you are using AsmJit.

1. You decided to use Compiler that has some limitations at the moment. One of them is that function-call doesn't accept immediates; it accepts only variables. The solution is to use mov to temporary and then pass the temporary to the setArgument() member function. It generates more code, but it works.

  The issue is reported: https://code.google.com/p/asmjit/issues/detail?id=86 and will be fixed.

2. To set the void return value to the function you can declare function like this:

  FunctionBuilder0<Void>

3. Tail-call.

It's currently not supported, but I'm thinking about it for a new 1.1 alpha version. At the moment you just call and ret.

I hope I didn't forget anything, I'm in hurry today, hope that helps.

Best regards
Petr Kobalicek


--
 
---
You received this message because you are subscribed to the Google Groups "asmjit-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to asmjit-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Grant Posner

unread,
Oct 10, 2013, 9:22:30 AM10/10/13
to asmji...@googlegroups.com
Thank you! You have been very helpful to me!
 
Regarding 1. How much extra code is there? Is it just a couple lines of assembly code? I think that would be fine, then.
2. I didn't see any documentation about that, so I had to ask here. Is there any documentation, other than the wiki pages in code.google.com?
3. When do you think that 1.1 will be released? A couple of months? I think I can just emit a jump to a function label... it's no problem if you don't get to tail-calls anytime soon!
 
Grant Posner

Grant Posner

unread,
Oct 10, 2013, 9:36:50 AM10/10/13
to asmji...@googlegroups.com
When changing my code to emit a jump to a function, instead of a call, I get a different assertion error:
 
*** ASSERTION FAILURE at c:\users\user\desktop\asmjit-1.0-beta4\asmjit\CompilerX86X64.h (line 2040)
*** (id & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_LABEL
 
A test case that will cause this is:
 
#include <AsmJit.h>
using namespace AsmJit;
 
// CompiledFunc: pointer to (nothing -> void)
typedef void (*CompiledFunc)();
 
void doSomething()
{
    printf("doing something...");
}
 
void main()
{
    Compiler c;
    c.newFunction(CALL_CONV_DEFAULT, FunctionBuilder0<Void>());
    c.jmp(&doSomething);
    c.endFunction();
    CompiledWord func = function_cast<CompiledWord>(c.make());
    (*func)();
}
The assertion still fails even if I use a GPVar, mov &doSomething into it, and then c.jmp to that temporary variable. Is there a workaround for this?
 
Thanks for you help, and for your library!
 
Grant Posner

Petr Kobalíček

unread,
Oct 10, 2013, 10:43:25 AM10/10/13
to asmjit-dev
Hi Grant,

you are welcome:)

1. Not much, basically one extra mov instruction per a function-call argument.

2. It's probably not well documented, but it's used by some tests.

3. Well, I have nearly everything I wanted done for 1.1-alpha release, I'm still doing some tests and improving function-call support. I expect to release it in less than 1 month, but I may travel this month so I will see what I can do. But definitely the new version will be announced on the mailing list so stay tuned here.

4. Your last snippet of doing a tail-call can't be recognized by AsmJit at the moment. The reason is that when you use the Compiler it does some kind of analysis to understand a variable life-time even when no variables are used. So basically it's complaining that you are jumping into unknown. If you use function-call and ret combination it will do the job at the cost of emitting more instructions.

Hope that helps

Best regards
Petr Kobalicek

--
Reply all
Reply to author
Forward
0 new messages