// File: /workspace/github_cpp_makefile_star2_O2/marxn[P]pupp/src/parser/expression.cpp
// Function: FunctionExpression::Calculate(NodeContext*)
ConstValue * FunctionExpression::Calculate(NodeContext * context)
{
        ConstValue * result = NULL;
        FuncValue * func = static_cast<FuncValue*>(this->FuncObj->Calculate(context));

        if(func==NULL)
        {
                cerr<<"pupp runtime error: Not a qualified function."<<endl;
                return NULL;
        }

        if(func->GetType()==Null)
        {
                cerr<<"pupp runtime error: Function object has not been initialized."<<endl;
                return NULL;
        }

        FunctionNode * funcnode = func->GetFuncNode();

        if(funcnode)
        {
                if(funcnode->GetArgList()->size()!=this->ExprList->size())
                {
                        cerr<<"pupp runtime error: The number of arguments does not match"<<endl;
                        return NULL;
                }

                list<Expression*>::iterator i;
                list<FuncArgDef*>::iterator j;

                for(i = this->ExprList->begin(), j = funcnode->GetArgList()->begin();
                        i!=this->ExprList->end() && j!=funcnode->GetArgList()->end(); i++,j++)
                {
                        if((*j)->isRef())
                        {
                                if((*i)->isLValue()==false)
                                {
                                        cerr<<"pupp runtime error: Cannot pass any expression other than an lvalue to a reference:"<<(*j)->GetName()<<endl;
                                        return NULL;
                                }
                        }
                }

                int rtn = 0;

                NodeContext * new_ctx = new NodeContext;
                new_ctx->AddFrame(funcnode);

                for(i = this->ExprList->begin(), j = funcnode->GetArgList()->begin(); 
                        i!=this->ExprList->end() && j!=funcnode->GetArgList()->end(); i++,j++)
                {
                        if((*j)->isRef())
                        {
                                VarExpression * exp = static_cast<VarExpression*>(*i);
                                ValueBox * vbox = exp->GetVarRef(context);
                                unsigned long index = (*j)->GetArgIndex();
                                Variable * avatar = new_ctx->GetVariable(0, index);

                                if(avatar)
                                {
                                        if(vbox->GetVal()->GetType() != avatar->GetVarType())
                                        {
                                                cerr<<"pupp runtime error: variable type mismatch when passing args to the function."<<endl;
                                                return NULL;
                                        }

                                        delete avatar->GetVBox();
                                        avatar->SetVBox(vbox);
                                        avatar->GetVBox()->IncRefCount();
                                }
                        }
                        else
                        {
                                ConstValue * value = (*i)->Calculate(context);
                                if(value->GetType()!=(*j)->GetType())
                                {
                                        delete new_ctx;
                                        cerr<<"pupp runtime error: data type mismatch when calling a function."<<endl;
                                        return NULL;
                                }

                                Variable * localvar = new_ctx->GetVariable(0, (*j)->GetArgIndex());
                                if(localvar)
                                {
                                        localvar->SetValue(value);
                                }

                                delete value;
                        }
                }

                list<Variable*> * closurevars = func->GetClosureVars();

                if(closurevars!=NULL)
                {
                        //Put closure variables into the new context.
                        new_ctx->ReplaceVariable(funcnode->GetClosureVarStartIndex(), closurevars);
                }
                
                if(this->ThreadNum==-1)
                {
                        //Donot need to launch a new thread. Let's rock!
                        rtn = funcnode->Run(new_ctx);

                        //Check the result of the function.
                        if(rtn==NODE_RET_NEEDRETURN)
                        {
                                if(funcnode->GetRtnType()==Null)
                                {
                                        delete new_ctx;
                                        cerr<<"pupp runtime error: function does not have a return value."<<endl;
                                        return NULL;
                                }
                                
                                result = new_ctx->FunctionRet;
                                if(funcnode->GetRtnType()!=result->GetType())
                                {
                                        ConstValue * ret = ConstValueCast(result, funcnode->GetRtnType());
                                        delete result;
                                        result = ret;
                                }
                        }
                        else
                        {
                                result = new NullValue;
                        }

                        delete new_ctx;
                }
                else if(this->ThreadNum==0)
                {
                        AsynFuncCallContext * asyncallctx = new AsynFuncCallContext(funcnode, new_ctx);        
                        if(asyncallctx)
                        {
                            asyncallctx->AsynCall();
                        }
                               
                        result = new NullValue;
                }
                else
                {
                        pthread_mutex_lock(&this->AccessLock);
                        
                        if(this->ThreadCount < this->ThreadNum)
                        {
                                AsynFuncCallContext * asyncallctx = new AsynFuncCallContext(funcnode, new_ctx);
                                
                                if(asyncallctx)
                                {
                                    this->ThreadCount++;
                                    asyncallctx->AsynCall();
                                }
                        }
                        
                        pthread_mutex_unlock(&this->AccessLock);
                               
                        result = new NullValue;
                }
        }
        else
        {
                cerr<<"pupp runtime error: cannot call a null function"<<endl;
                return NULL;
        }
        
        delete func;
        return result;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rsi, %rbx
movq %rdi, %r12
movq 0x50(%rdi), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
testq %rax, %rax
je 0x9522
movq %rax, %r15
movq %rax, %rdi
callq 0x6cbc
testl %eax, %eax
je 0x9532
movq %r15, %rdi
callq 0x1529e
testq %rax, %rax
je 0x9542
movq %rax, %rbp
movq %rax, %rdi
callq 0xa5cc
movq 0x10(%rax), %rcx
movq 0x60(%r12), %rax
cmpq 0x10(%rax), %rcx
jne 0x9552
movq %rbx, (%rsp)
movq (%rax), %r14
movq %rbp, %rdi
callq 0xa5cc
movq %rax, %rbx
cmpq 0x60(%r12), %r14
je 0x9582
movq (%rbx), %rbx
movq %rbp, %rdi
callq 0xa5cc
cmpq %rax, %rbx
je 0x9582
movq 0x10(%rbx), %rdi
callq 0xa4a6
testb %al, %al
je 0x951d
movq 0x10(%r14), %rax
cmpb $0x0, 0x8(%rax)
je 0x983b
movq (%r14), %r14
jmp 0x94e3
movq 0x39ac7(%rip), %rdi     # 0x42ff0
leaq 0x25cf9(%rip), %rsi     # 0x2f229
jmp 0x9560
movq 0x39ab7(%rip), %rdi     # 0x42ff0
leaq 0x25d17(%rip), %rsi     # 0x2f257
jmp 0x9560
movq 0x39aa7(%rip), %rdi     # 0x42ff0
leaq 0x25e9d(%rip), %rsi     # 0x2f3ed
jmp 0x9560
movq 0x39a97(%rip), %rdi     # 0x42ff0
leaq 0x25d35(%rip), %rsi     # 0x2f295
callq 0x6240
movq %rax, %rdi
callq 0x6140
xorl %r12d, %r12d
movq %r12, %rax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r15, 0x10(%rsp)
pushq $0x70
popq %rdi
callq 0x6260
movq %rax, %r13
movq %rax, %rdi
callq 0xab3c
movq %r13, %rdi
movq %rbp, %rsi
callq 0xac22
movq 0x60(%r12), %rax
movq (%rax), %r15
movq %rbp, 0x8(%rsp)
movq %rbp, %rdi
callq 0xa5cc
movq %rax, %rbp
movq (%rsp), %r14
movq %r12, 0x20(%rsp)
movq %r13, 0x18(%rsp)
cmpq 0x60(%r12), %r15
je 0x9704
movq (%rbp), %rbp
movq 0x8(%rsp), %rdi
callq 0xa5cc
cmpq %rax, %rbp
je 0x9704
movq 0x10(%rbp), %rdi
callq 0xa4a6
movq 0x10(%r15), %rdi
testb %al, %al
je 0x969b
movq %r14, %rsi
callq 0x8e4c
movq %rax, %r12
movq 0x10(%rbp), %rdi
callq 0xa4ca
movq %r13, %rdi
xorl %esi, %esi
movq %rax, %rdx
callq 0xad28
testq %rax, %rax
je 0x96f7
movq %rax, %rbx
movq %r12, %r14
movq %r12, %rdi
callq 0x6d66
movq %rax, %rdi
callq 0x6cbc
movl %eax, %r13d
movq %rbx, %rdi
callq 0x14f12
cmpl %eax, %r13d
jne 0x98de
movq %rbx, %rdi
callq 0x14db6
movq %rax, %r13
testq %rax, %rax
je 0x966e
movq %r13, %rdi
callq 0x6cf2
movq %r13, %rdi
pushq $0x10
popq %rsi
callq 0x6270
movq %rbx, %rdi
movq %r14, %rsi
callq 0x14db0
movq %rbx, %rdi
callq 0x14db6
movq %rax, %rdi
callq 0x6d10
movq 0x18(%rsp), %r13
jmp 0x96f3
movq (%rdi), %rax
movq %r14, %rsi
callq *0x10(%rax)
movq %rax, %rbx
movq %rax, %rdi
callq 0x6cbc
movl %eax, %r14d
movq 0x10(%rbp), %rdi
callq 0xa4b8
cmpl %eax, %r14d
jne 0x9884
movq 0x10(%rbp), %rdi
callq 0xa4ca
movq %r13, %rdi
xorl %esi, %esi
movq %rax, %rdx
callq 0xad28
testq %rax, %rax
je 0x96ea
movq %rax, %rdi
movq %rbx, %rsi
callq 0x14e0e
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
movq (%rsp), %r14
movq (%r15), %r15
movq 0x20(%rsp), %r12
jmp 0x95cb
movq 0x10(%rsp), %r15
movq %r15, %rdi
callq 0x152a4
testq %rax, %rax
movq 0x8(%rsp), %rbp
je 0x9734
movq %rax, %rbx
movq %rbp, %rdi
callq 0xa8ba
movq %r13, %rdi
movq %rax, %rsi
movq %rbx, %rdx
callq 0xacdc
movq 0x18(%r12), %rax
testq %rax, %rax
je 0x97b1
cmpq $-0x1, %rax
jne 0x97e3
movq %rbp, %rdi
movq %r13, %rsi
callq 0xa5b6
cmpl $0x3, %eax
jne 0x98aa
movq %rbp, %rdi
callq 0xa600
testl %eax, %eax
je 0x98f1
movq 0x50(%r13), %r12
movq %rbp, %rdi
callq 0xa600
movl %eax, %ebx
movq %r12, %rdi
callq 0x6cbc
cmpl %eax, %ebx
je 0x98bd
movq %rbp, %rdi
callq 0xa600
movq %r12, %rdi
movl %eax, %esi
callq 0x7fa3
movq %rax, %rbx
movq (%r12), %rax
movq %r12, %rdi
callq *0x8(%rax)
movq %rbx, %r12
jmp 0x98bd
pushq $0x10
popq %rbx
movq %rbx, %rdi
callq 0x6260
movq %rbp, (%rax)
movq %r13, 0x8(%rax)
movq %rax, %rdi
callq 0x9f4c
movq %rbx, %rdi
callq 0x6260
movq %rax, %r12
movq %rax, %rdi
callq 0x6da8
jmp 0x98d0
leaq 0x28(%r12), %rbx
movq %rbx, %rdi
callq 0x63c0
movq 0x20(%r12), %r14
cmpq 0x18(%r12), %r14
jge 0x981b
pushq $0x10
popq %rdi
callq 0x6260
movq %rbp, (%rax)
movq %r13, 0x8(%rax)
incq %r14
movq %r14, 0x20(%r12)
movq %rax, %rdi
callq 0x9f4c
movq %rbx, %rdi
callq 0x61d0
pushq $0x10
popq %rdi
callq 0x6260
movq %rax, %r12
movq %rax, %rdi
callq 0x6da8
jmp 0x98d0
movq 0x397ae(%rip), %rdi     # 0x42ff0
leaq 0x25a87(%rip), %rsi     # 0x2f2d0
callq 0x6240
movq %rax, %r14
movq 0x10(%rbx), %rsi
leaq 0x28(%rsp), %rbx
movq %rbx, %rdi
callq 0xa4aa
movq %r14, %rdi
movq %rbx, %rsi
callq 0x6210
movq %rax, %rdi
callq 0x6140
leaq 0x28(%rsp), %rdi
callq 0x6130
jmp 0x956d
movq %r13, %rdi
callq 0xab84
pushq $0x70
popq %rsi
movq %r13, %rdi
callq 0x6270
movq 0x39752(%rip), %rdi     # 0x42ff0
leaq 0x25acd(%rip), %rsi     # 0x2f372
jmp 0x9560
pushq $0x10
popq %rdi
callq 0x6260
movq %rax, %r12
movq %rax, %rdi
callq 0x6da8
movq %r13, %rdi
callq 0xab84
pushq $0x70
popq %rsi
movq %r13, %rdi
callq 0x6270
movq (%r15), %rax
movq %r15, %rdi
callq *0x8(%rax)
jmp 0x9570
movq 0x3970b(%rip), %rdi     # 0x42ff0
leaq 0x25a38(%rip), %rsi     # 0x2f324
jmp 0x9560
movq %r13, %rdi
callq 0xab84
pushq $0x70
popq %rsi
movq %r13, %rdi
callq 0x6270
movq 0x396e5(%rip), %rdi     # 0x42ff0
leaq 0x25aa0(%rip), %rsi     # 0x2f3b2
jmp 0x9560
jmp 0x991b
jmp 0x991b
movq %rax, %rbx
pushq $0x10
popq %rsi
movq %r12, %rdi
jmp 0x993e
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x6130
jmp 0x9943
movq %rax, %rbx
pushq $0x70
popq %rsi
movq %r13, %rdi
callq 0x6270
movq %rbx, %rdi
callq 0x6460
nop