// File: /workspace/github_cpp_makefile_star2_O3/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 0xaff6
movq %rax, %r15
movq %rax, %rdi
callq 0x7da6
testl %eax, %eax
je 0xb00b
movq %r15, %rdi
callq 0x18b82
testq %rax, %rax
je 0xb020
movq %rax, %rbp
movq %rax, %rdi
callq 0xbd6a
movq 0x10(%rax), %rcx
movq 0x60(%r12), %rax
cmpq 0x10(%rax), %rcx
jne 0xb035
movq %rbx, 0x8(%rsp)
movq (%rax), %r14
movq %rbp, %rdi
callq 0xbd6a
cmpq 0x60(%r12), %r14
je 0xadb2
movq %rax, %rbx
movq (%rbx), %rbx
movq %rbp, %rdi
callq 0xbd6a
cmpq %rax, %rbx
je 0xadb2
movq 0x10(%rbx), %rdi
callq 0xbbe4
testb %al, %al
je 0xada8
movq 0x10(%r14), %rax
cmpb $0x0, 0x8(%rax)
je 0xb11b
movq (%r14), %r14
cmpq 0x60(%r12), %r14
jne 0xad7d
movq %r15, 0x18(%rsp)
movl $0x70, %edi
callq 0x6260
movq %rax, %r14
movq %rax, %rdi
callq 0xc586
movq %r14, (%rsp)
movq %r14, %rdi
movq %rbp, %rsi
callq 0xc6ae
movq 0x60(%r12), %rax
movq (%rax), %r15
movq %rbp, 0x10(%rsp)
movq %rbp, %rdi
callq 0xbd6a
cmpq 0x60(%r12), %r15
movq 0x8(%rsp), %r13
je 0xaf41
movq %rax, %rbp
movq %r12, 0x20(%rsp)
movq (%rbp), %rbp
movq 0x10(%rsp), %rdi
callq 0xbd6a
cmpq %rax, %rbp
je 0xaf41
movq 0x10(%rbp), %rdi
callq 0xbbe4
movq 0x10(%r15), %rdi
testb %al, %al
je 0xaed5
movq %r13, %rsi
callq 0xa4bc
movq %rax, %r14
movq 0x10(%rbp), %rdi
callq 0xbc1c
movq (%rsp), %rdi
xorl %esi, %esi
movq %rax, %rdx
callq 0xc7ec
testq %rax, %rax
je 0xaf33
movq %rax, %rbx
movq %r14, %r12
movq %r14, %rdi
callq 0x7e76
movq %rax, %rdi
callq 0x7da6
movl %eax, %r13d
movq %rbx, %rdi
callq 0x18716
cmpl %eax, %r13d
jne 0xb20d
movq %rbx, %rdi
callq 0x185ae
movq %rax, %r13
testq %rax, %rax
je 0xaea1
movq %r13, %rdi
callq 0x7de0
movl $0x10, %esi
movq %r13, %rdi
callq 0x6270
movq %rbx, %rdi
movq %r12, %rsi
callq 0x185a8
movq %rbx, %rdi
callq 0x185ae
movq %rax, %rdi
callq 0x7e18
movq 0x8(%rsp), %r13
movq 0x20(%rsp), %r12
jmp 0xaf33
movq (%rdi), %rax
movq %r13, %rsi
callq *0x10(%rax)
movq %rax, %rbx
movq %rax, %rdi
callq 0x7da6
movl %eax, %r14d
movq 0x10(%rbp), %rdi
callq 0xbc0a
cmpl %eax, %r14d
jne 0xb1dc
movq 0x10(%rbp), %rdi
callq 0xbc1c
movq (%rsp), %rdi
xorl %esi, %esi
movq %rax, %rdx
callq 0xc7ec
testq %rax, %rax
je 0xaf25
movq %rax, %rdi
movq %rbx, %rsi
callq 0x1860a
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x8(%rax)
movq 0x8(%rsp), %r13
movq (%r15), %r15
cmpq 0x60(%r12), %r15
jne 0xae08
movq 0x18(%rsp), %r15
movq %r15, %rdi
callq 0x18b88
testq %rax, %rax
movq 0x10(%rsp), %rbp
movq (%rsp), %r13
je 0xaf75
movq %rax, %rbx
movq %rbp, %rdi
callq 0xc208
movq %r13, %rdi
movq %rax, %rsi
movq %rbx, %rdx
callq 0xc79e
movq 0x18(%r12), %rax
testq %rax, %rax
je 0xb08c
cmpq $-0x1, %rax
jne 0xb0bf
movq %rbp, %rdi
movq %r13, %rsi
callq 0xbd54
cmpl $0x3, %eax
jne 0xb1a4
movq %rbp, %rdi
callq 0xbdb0
testl %eax, %eax
je 0xb222
movq 0x50(%r13), %r12
movq %rbp, %rdi
callq 0xbdb0
movl %eax, %ebx
movq %r12, %rdi
callq 0x7da6
cmpl %eax, %ebx
je 0xb1b9
movq %rbp, %rdi
callq 0xbdb0
movq %r12, %rdi
movl %eax, %esi
callq 0x952b
movq %rax, %rbx
movq (%r12), %rax
movq %r12, %rdi
callq *0x8(%rax)
movq %rbx, %r12
jmp 0xb1b9
movq 0x3bff3(%rip), %rbx     # 0x46ff0
leaq 0x2a225(%rip), %rsi     # 0x35229
movl $0x2d, %edx
jmp 0xb048
movq 0x3bfde(%rip), %rbx     # 0x46ff0
leaq 0x2a23e(%rip), %rsi     # 0x35257
movl $0x3d, %edx
jmp 0xb048
movq 0x3bfc9(%rip), %rbx     # 0x46ff0
leaq 0x2a3bf(%rip), %rsi     # 0x353ed
movl $0x2f, %edx
jmp 0xb048
movq 0x3bfb4(%rip), %rbx     # 0x46ff0
leaq 0x2a252(%rip), %rsi     # 0x35295
movl $0x3a, %edx
movq %rbx, %rdi
callq 0x62f0
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x6220
movsbl %al, %esi
movq %rbx, %rdi
callq 0x6040
movq %rax, %rdi
callq 0x61b0
xorl %r12d, %r12d
movq %r12, %rax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x10, %edi
callq 0x6260
movq %rbp, (%rax)
movq %r13, 0x8(%rax)
movq %rax, %rdi
callq 0xb952
movl $0x10, %edi
callq 0x6260
movq %rax, %r12
movq %rax, %rdi
callq 0x7ed2
jmp 0xb1ce
leaq 0x28(%r12), %rbx
movq %rbx, %rdi
callq 0x63d0
movq 0x20(%r12), %r14
cmpq 0x18(%r12), %r14
jge 0xb0f9
movl $0x10, %edi
callq 0x6260
movq %rbp, (%rax)
movq %r13, 0x8(%rax)
incq %r14
movq %r14, 0x20(%r12)
movq %rax, %rdi
callq 0xb952
movq %rbx, %rdi
callq 0x61e0
movl $0x10, %edi
callq 0x6260
movq %rax, %r12
movq %rax, %rdi
callq 0x7ed2
jmp 0xb1ce
movq 0x3bece(%rip), %r14     # 0x46ff0
leaq 0x2a1a7(%rip), %rsi     # 0x352d0
movl $0x53, %edx
movq %r14, %rdi
callq 0x62f0
movq 0x10(%rbx), %rsi
leaq 0x28(%rsp), %rbx
movq %rbx, %rdi
callq 0xbbe8
movq (%rbx), %rsi
movq 0x8(%rbx), %rdx
movq %r14, %rdi
callq 0x62f0
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x6220
movsbl %al, %esi
movq %rbx, %rdi
callq 0x6040
movq %rax, %rdi
callq 0x61b0
leaq 0x38(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0xb077
movq 0x38(%rsp), %rsi
incq %rsi
callq 0x6270
jmp 0xb077
movl $0x10, %edi
callq 0x6260
movq %rax, %r12
movq %rax, %rdi
callq 0x7ed2
movq %r13, %rdi
callq 0xc5e8
movl $0x70, %esi
movq %r13, %rdi
callq 0x6270
movq (%r15), %rax
movq %r15, %rdi
callq *0x8(%rax)
jmp 0xb07a
movq (%rsp), %rbx
movq %rbx, %rdi
callq 0xc5e8
movl $0x70, %esi
movq %rbx, %rdi
callq 0x6270
movq 0x3bdf4(%rip), %rbx     # 0x46ff0
leaq 0x2a16f(%rip), %rsi     # 0x35372
movl $0x3f, %edx
jmp 0xb048
movq 0x3bddc(%rip), %rbx     # 0x46ff0
leaq 0x2a109(%rip), %rsi     # 0x35324
movl $0x4d, %edx
jmp 0xb24a
movq %r13, %rdi
callq 0xc5e8
movl $0x70, %esi
movq %r13, %rdi
callq 0x6270
movq 0x3bdb2(%rip), %rbx     # 0x46ff0
leaq 0x2a16d(%rip), %rsi     # 0x353b2
movl $0x3a, %edx
movq %rbx, %rdi
callq 0x62f0
movq %rbx, %rdi
callq 0x6140
jmp 0xb077
jmp 0xb263
jmp 0xb263
movq %rax, %rbx
movl $0x10, %esi
movq %r12, %rdi
jmp 0xb296
movq %rax, %rbx
leaq 0x38(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0xb29b
movq 0x38(%rsp), %rsi
incq %rsi
jmp 0xb296
movq %rax, %rbx
movl $0x70, %esi
movq %r14, %rdi
callq 0x6270
movq %rbx, %rdi
callq 0x6460
nop