void DaoTaskEvent_Init( DaoTaskEvent *self, int T, int S, DaoFuture *F, DaoChannel *C ) { GC_Assign( & self->future, F ); GC_Assign( & self->channel, C ); self->type = T; self->state = S; }
DaoFuture* DaoProcess_GetInitFuture( DaoProcess *self ) { DaoFuture *future; if( self->future ) return self->future; future = DaoFuture_New( NULL, 1 ); GC_Assign( & self->future, future ); GC_Assign( & future->process, self ); return future; }
DaoCinValue* DaoCinValue_New( DaoCinType *cintype, DaoValue *value ) { DaoCinValue *self = (DaoCinValue*)dao_calloc( 1, sizeof(DaoCinValue) ); DaoValue_Init( self, DAO_CINVALUE ); GC_Assign( & self->cintype, cintype ); GC_Assign( & self->value, value ); #ifdef DAO_USE_GC_LOGGER DaoObjectLogger_LogNew( (DaoValue*) self ); #endif return self; }
static void DaoSTD_Eval( DaoProcess *proc, DaoValue *p[], int N ) { DaoVmSpace *vms = proc->vmSpace; DaoNamespace *ns = proc->activeNamespace; DaoStream *prevStream = proc->stdioStream; DaoStream *redirect = (DaoStream*) p[1]; char *source = DaoValue_TryGetChars( p[0] ); if( redirect != prevStream ) GC_Assign( & proc->stdioStream, redirect ); DaoProcess_Eval( proc, ns, source ); DaoProcess_PutValue( proc, proc->stackValues[0] ); if( redirect != prevStream ) GC_Assign( & proc->stdioStream, prevStream ); }
void DaoValue_SetType( DaoValue *to, DaoType *tp ) { DaoVmSpace *vms; DaoType *tp2; DNode *it; if( to->type != tp->tid && tp->tid != DAO_ANY ) return; if( tp->attrib & DAO_TYPE_SPEC ) return; switch( to->type ){ #ifdef DAO_WITH_NUMARRAY case DAO_ARRAY : if( to->xArray.size ) return; if( tp->tid != DAO_ARRAY || tp->args == NULL || tp->args->size == 0 ) break; tp = tp->args->items.pType[0]; if( tp->tid == DAO_NONE || tp->tid > DAO_COMPLEX ) break; DaoArray_SetNumType( (DaoArray*) to, tp->tid ); break; #endif case DAO_LIST : /* var x: any = {}, x->ctype should be list<any> */ if( tp->tid == DAO_ANY ){ vms = DaoType_GetVmSpace( tp ); tp = vms->typeListAny; } if( to->xList.ctype && !(to->xList.ctype->attrib & DAO_TYPE_UNDEF) ) break; GC_Assign( & to->xList.ctype, tp ); break; case DAO_MAP : if( tp->tid == DAO_ANY ){ vms = DaoType_GetVmSpace( tp ); tp = vms->typeMapAny; } if( to->xMap.ctype && !(to->xMap.ctype->attrib & DAO_TYPE_UNDEF) ) break; GC_Assign( & to->xMap.ctype, tp ); break; case DAO_TUPLE : tp2 = to->xTuple.ctype; if( tp->tid == DAO_ANY ) break; if( tp->args->size ==0 ) break; /* not to the generic tuple type */ if( tp2 == NULL || tp2->mapNames == NULL || tp2->mapNames->size ==0 ){ GC_Assign( & to->xTuple.ctype, tp ); break; } if( tp->mapNames == NULL || tp->mapNames->size ) break; for(it=DMap_First(tp2->mapNames); it!=NULL; it=DMap_Next(tp2->mapNames, it)){ if( DMap_Find( tp->mapNames, it->key.pVoid ) == NULL ) break; } if( it ) break; GC_Assign( & to->xTuple.ctype, tp ); break; default : break; } }
void DaoxGraphData_Reset( DaoxGraphData *self, DaoxGraph *graph, int nodeSize, int edgeSize ) { daoint i, M, N; char *data; if( self->graph ){ N = self->graph->nodes->size; M = self->graph->edges->size; for(i=0; i<N; i++){ DaoxNode *node = self->graph->nodes->items.pgNode[i]; node->X.Void = NULL; } for(i=0; i<N; i++){ DaoxEdge *edge = self->graph->edges->items.pgEdge[i]; edge->X.Void = NULL; } } GC_Assign( & self->graph, graph ); if( graph == NULL ) return; N = graph->nodes->size; M = graph->edges->size; DString_Reserve( self->nodeData, N * nodeSize ); DString_Reserve( self->edgeData, M * edgeSize ); for(i=0, data=self->nodeData->chars; i<N; i++, data+=nodeSize){ DaoxNode *node = graph->nodes->items.pgNode[i]; node->X.Void = data; } for(i=0, data=self->edgeData->chars; i<M; i++, data+=edgeSize){ DaoxEdge *edge = graph->edges->items.pgEdge[i]; edge->X.Void = data; } }
void DaoMT_Select( DaoProcess *proc, DaoValue *par[], int n ) { DNode *it; DaoTaskEvent *event = NULL; DaoFuture *future = DaoProcess_GetInitFuture( proc ); DaoMap *selects = (DaoMap*) par[0]; float timeout = par[1]->xFloat.value; for(it=DaoMap_First(selects); it; it=DaoMap_Next(selects,it)){ DaoValue *value = it->key.pValue; int isfut = DaoValue_CheckCtype( value, dao_type_future ); int ischan = DaoValue_CheckCtype( value, dao_type_channel ); if( isfut == 0 && ischan == 0 ){ DaoProcess_RaiseError( proc, "Param", "invalid type selection" ); return; } } event = DaoCallServer_MakeEvent(); DaoTaskEvent_Init( event, DAO_EVENT_WAIT_SELECT, DAO_EVENT_WAIT, future, NULL ); GC_Assign( & event->selects, selects ); proc->status = DAO_PROCESS_SUSPENDED; proc->pauseType = DAO_PAUSE_CHANFUT_SELECT; DaoCallServer_AddTimedWait( proc, event, timeout ); /* Message may have been sent before this call: */ DMutex_Lock( & daoCallServer->mutex ); DaoChannel_ActivateEvent( NULL, DAO_EVENT_WAIT_SELECT ); DCondVar_Signal( & daoCallServer->condv ); DMutex_Unlock( & daoCallServer->mutex ); }
void DaoObject_Init( DaoObject *self, DaoObject *that, int offset ) { DaoClass *klass = self->defClass; daoint i; self->isAsync = (klass->attribs & DAO_CLS_ASYNCHRONOUS) != 0; if( that ){ GC_Assign( & self->rootObject, that ); self->objValues = that->objValues + offset; }else if( self->rootObject == NULL ){ GC_Assign( & self->rootObject, self ); if( self->isNull ){ /* no value space is allocated for null object yet! */ self->valueCount = klass->objDataName->size; self->objValues = (DaoValue**) dao_calloc( self->valueCount, sizeof(DaoValue*) ); } } offset += self->defClass->objDefCount; if( klass->parent != NULL && klass->parent->type == DAO_CLASS ){ DaoObject *sup = NULL; if( self->isNull ){ sup = & klass->parent->xClass.objType->value->xObject; }else{ sup = DaoObject_Allocate( (DaoClass*) klass->parent, 0 ); sup->isRoot = 0; DaoObject_Init( sup, self->rootObject, offset ); } GC_Assign( & self->parent, sup ); } GC_Assign( & self->objValues[0], self ); if( self->isRoot == 0 ) return; for(i=1; i<klass->instvars->size; i++){ DaoVariable *var = klass->instvars->items.pVar[i]; DaoValue **value = self->objValues + i; /* for data type such as list/map/array, * its .ctype may need to be set properaly */ if( var->value ){ DaoValue_Move( var->value, value, var->dtype ); }else if( *value == NULL && var->dtype && var->dtype->value ){ DaoValue_Copy( var->dtype->value, value ); } } }
static void COROUT_Suspend( DaoProcess *proc, DaoValue *p[], int N ) { DaoxCoroutine *self = (DaoxCoroutine*) p[0]; DaoValue *value = N > 1 ? p[1] : DaoValue_MakeNone(); if( self->process != proc ){ DaoProcess_RaiseError( proc, NULL, "coroutine cannot suspend in alien process." ); return; } GC_Assign( & proc->stackValues[0], value ); proc->status = DAO_PROCESS_SUSPENDED; proc->pauseType = DAO_PAUSE_COROUTINE_YIELD; }
static DaoValue* DaoValue_DeepCopy( DaoValue *self ) { DNode *it; daoint i; if( self == NULL ) return NULL; if( self->type <= DAO_ENUM ) return self; /* simple types will be copied at use; */ if( self->type == DAO_ARRAY ) return (DaoValue*) DaoArray_Copy( (DaoArray*) self ); if( self->type == DAO_LIST ){ DaoList *list = (DaoList*) self; DaoList *copy = DaoList_New(); GC_Assign( & copy->ctype, list->ctype ); for(i=0; i<list->value->size; ++i){ DaoValue *value = DaoValue_DeepCopy( list->value->items.pValue[i] ); DaoList_Append( copy, value ); } return (DaoValue*) copy; }else if( self->type == DAO_MAP ){ DaoMap *map = (DaoMap*) self; DaoMap *copy = DaoMap_New( map->value->hashing ); GC_Assign( & copy->ctype, map->ctype ); for(it=DMap_First(map->value); it; it=DMap_Next(map->value,it)){ DaoValue *key = DaoValue_DeepCopy( it->key.pValue ); DaoValue *value = DaoValue_DeepCopy( it->value.pValue ); DaoMap_Insert( copy, key, value ); } return (DaoValue*) copy; }else if( self->type == DAO_TUPLE ){ DaoTuple *tuple = (DaoTuple*) self; DaoTuple *copy = DaoTuple_New( tuple->size ); GC_Assign( & copy->ctype, tuple->ctype ); for(i=0; i<tuple->size; ++i){ DaoValue *value = DaoValue_DeepCopy( tuple->values[i] ); DaoTuple_SetItem( copy, value, i ); } return (DaoValue*) copy; } return NULL; }
void DaoValue_MoveCinValue( DaoCinValue *S, DaoValue **D ) { DaoValue *D2 = *D; if( D2 == (DaoValue*) S ) return; if( D2 == NULL || D2->type != DAO_CINVALUE || D2->xCinValue.refCount > 1 ){ S = DaoCinValue_Copy( S ); DaoGC_Assign( D, (DaoValue*) S ); return; } if( D2->xCinValue.cintype != S->cintype ){ GC_Assign( & D2->xCinValue.cintype, S->cintype ); } DaoValue_Copy( S->value, & D2->xCinValue.value ); }
void DaoVmSpace_AddTaskletWait( DaoVmSpace *self, DaoProcess *wait, DaoFuture *pre, double timeout ) { DaoTaskletEvent *event; DaoTaskletServer *server = DaoTaskletServer_TryInit( self ); DaoFuture *future = DaoProcess_GetInitFuture( wait ); GC_Assign( & future->precond, pre ); future->state = DAO_TASKLET_PAUSED; event = DaoTaskletServer_MakeEvent( server ); DaoTaskletEvent_Init( event, DAO_EVENT_WAIT_TASKLET, DAO_EVENT_WAIT, future, NULL ); DaoTaskletServer_AddTimedWait( server, wait, event, timeout ); }
void DaoCallServer_AddWait( DaoProcess *wait, DaoFuture *pre, double timeout ) { DaoTaskEvent *event; DaoCallServer *server = DaoCallServer_TryInit( mainVmSpace );; DaoFuture *future = DaoProcess_GetInitFuture( wait ); GC_Assign( & future->precond, pre ); future->state = DAO_CALL_PAUSED; event = DaoCallServer_MakeEvent(); DaoTaskEvent_Init( event, DAO_EVENT_WAIT_TASKLET, DAO_EVENT_WAIT, future, NULL ); DaoCallServer_AddTimedWait( wait, event, timeout ); }
static int DaoValue_TryCastTuple( DaoValue *src, DaoValue **dest, DaoType *tp ) { DaoTuple *tuple; DaoType **item_types = tp->args->items.pType; DaoType *totype = src->xTuple.ctype; DaoValue **data = src->xTuple.values; DMap *names = totype ? totype->mapNames : NULL; DNode *node, *search; daoint i, T = tp->args->size; int tm, eqs = 0; /* // Auto-cast tuple type, on the following conditions: // (1) the item values of "dest" must match exactly to the item types of "tp"; // (2) "tp->mapNames" must contain "(*dest)->xTuple.ctype->mapNames"; */ if( src->xTuple.ctype == NULL ){ GC_IncRC( tp ); src->xTuple.ctype = tp; return 1; } if( DaoType_MatchValue( tp, src, NULL ) < DAO_MT_SIM ) return 1; /* Redundant? */ /* // Casting is not necessary if the tuple's field names are a superset of the // field names of the target type: */ if( tp->mapNames == NULL || tp->mapNames->size ==0 ) goto Finalize; if( names ){ daoint count = 0; for(node=DMap_First(names); node; node=DMap_Next(names,node)){ search = DMap_Find( tp->mapNames, node->key.pVoid ); if( search && node->value.pInt != search->value.pInt ) return 0; count += search != NULL; } /* be superset of the field names of the target type: */ if( count == tp->mapNames->size ) goto Finalize; } Finalize: tuple = DaoTuple_New( T ); for(i=0; i<T; i++){ DaoType *it = item_types[i]; if( it->tid == DAO_PAR_NAMED ) it = & it->aux->xType; DaoValue_Move( data[i], tuple->values+i, it ); } GC_IncRC( tp ); tuple->ctype = tp; GC_Assign( dest, tuple ); return 1; }
void DaoObject_SetParentCdata( DaoObject *self, DaoCdata *parent ) { DaoObject *child = NULL; DaoObject *obj = (DaoObject*) self->parent; DaoValue *sup = self->defClass->parent; if( parent == NULL ) return; if( sup == NULL ) return; if( obj && obj->type == DAO_OBJECT ){ DaoObject_SetParentCdata( obj, parent ); }else if( sup->type == DAO_CTYPE ){ DaoCdata *cdata = (DaoCdata*)sup; if( DaoType_ChildOf( cdata->ctype, parent->ctype ) ){ GC_Assign( & self->parent, parent ); } } }
static void DaoMT_Start( DaoProcess *proc, DaoValue *p[], int n ) { DaoProcess *clone; DaoVmCode *vmc, *end, *sect; DaoType *type = DaoProcess_GetReturnType( proc ); DaoFuture *future = DaoFuture_New( type, 0 ); int entry, nop = proc->activeCode[1].code == DVM_NOP; DaoProcess_PutValue( proc, (DaoValue*) future ); sect = DaoProcess_InitCodeSection( proc, 0 ); if( sect == NULL ) return; entry = proc->topFrame->entry; end = proc->activeRoutine->body->vmCodes->data.codes + proc->activeCode[nop+1].b; clone = DaoVmSpace_AcquireProcess( proc->vmSpace ); DaoProcess_PopFrame( proc ); DaoMT_InitProcess( proc, clone, 0 ); clone->topFrame->entry = entry; /* // Use the cloned process instead of the parent process, in case that // the cloned process will not be joined by the parent process: */ clone->topFrame->outer = clone; future->process = clone; GC_IncRC( clone ); GC_Assign( & clone->future, future ); future->state = DAO_CALL_RUNNING; for(vmc=sect; vmc!=end; vmc++){ int i = -1, code = vmc->code; if( code == DVM_GETVH || (code >= DVM_GETVH_I && code <= DVM_GETVH_C) ){ i = vmc->b; }else if( code == DVM_SETVH || (code >= DVM_SETVH_II && code <= DVM_SETVH_CC) ){ i = vmc->b; } if( i >= 0 ) DaoValue_Move( proc->activeValues[i], & clone->activeValues[i], NULL ); } DaoCallServer_AddTask( DaoMT_Start0, clone, p[0]->xEnum.value ? clone : NULL ); }
void DaoValue_CopyX( DaoValue *src, DaoValue **dest, DaoType *cst ) { DaoValue *dest2 = *dest; if( src == dest2 ) return; if( dest2 && dest2->xBase.refCount >1 ){ GC_DecRC( dest2 ); *dest = dest2 = NULL; } if( src->type == DAO_CSTRUCT || src->type == DAO_CDATA ){ DaoValue_MoveCstruct( src, dest, cst != NULL && cst->invar != 0 ); return; }else if( src->type == DAO_CINVALUE ){ DaoValue_MoveCinValue( (DaoCinValue*) src, dest ); return; } if( dest2 == NULL ){ src = DaoValue_SimpleCopyWithTypeX( src, NULL, cst ); GC_IncRC( src ); *dest = src; return; } if( src->type != dest2->type || src->type > DAO_ENUM ){ src = DaoValue_SimpleCopyWithTypeX( src, NULL, cst ); GC_Assign( dest, src ); return; } switch( src->type ){ case DAO_ENUM : DaoEnum_SetType( & dest2->xEnum, src->xEnum.etype ); DaoEnum_SetValue( & dest2->xEnum, & src->xEnum ); break; case DAO_BOOLEAN : dest2->xBoolean.value = src->xBoolean.value; break; case DAO_INTEGER : dest2->xInteger.value = src->xInteger.value; break; case DAO_FLOAT : dest2->xFloat.value = src->xFloat.value; break; case DAO_COMPLEX : dest2->xComplex.value = src->xComplex.value; break; case DAO_STRING : DString_Assign( dest2->xString.value, src->xString.value ); break; } }
static DaoFuture* DaoCallServer_GetNextFuture() { DaoCallServer *server = daoCallServer; DaoFuture *first, *future, *precond; DList *events = server->events; DMap *pending = server->pending; DMap *active = server->active; DNode *it; daoint i, j; for(i=0; i<events->size; i++){ DaoTaskEvent *event = (DaoTaskEvent*) events->items.pVoid[i]; DaoFuture *future = event->future; DaoObject *actor = future->actor; DaoChannel *channel = event->channel; DaoChannel *closed = NULL; DaoChannel *chselect = NULL; DaoFuture *futselect = NULL; DaoValue *selected = NULL; DaoValue *message = NULL; int type = event->type; if( event->state == DAO_EVENT_WAIT && future->precond != NULL ){ if( future->precond->state != DAO_CALL_FINISHED ) goto MoveToWaiting; } switch( event->type ){ case DAO_EVENT_WAIT_SENDING : if( channel->buffer->size >= channel->cap ){ if( event->state == DAO_EVENT_WAIT ){ DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_RECEIVING ); DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SELECT ); goto MoveToWaiting; } } event->type = DAO_EVENT_RESUME_TASKLET; break; case DAO_EVENT_WAIT_RECEIVING : if( channel->buffer->size == 0 ){ if( channel->cap > 0 && event->state == DAO_EVENT_WAIT ){ DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SENDING ); goto MoveToWaiting; } message = dao_none_value; }else{ message = channel->buffer->items.pValue[0]; } GC_Assign( & event->message, message ); event->auxiliary = channel->cap <= 0 && channel->buffer->size == 0; event->type = DAO_EVENT_RESUME_TASKLET; DList_PopFront( channel->buffer ); if( channel->buffer->size < channel->cap ) DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_SENDING ); if( channel->buffer->size ) DaoChannel_ActivateEvent( channel, DAO_EVENT_WAIT_RECEIVING ); break; case DAO_EVENT_WAIT_SELECT : message = dao_none_value; for(it=DaoMap_First(event->selects); it; it=DaoMap_Next(event->selects,it)){ if( DaoValue_CheckCtype( it->key.pValue, dao_type_channel ) ){ DaoChannel *chan = (DaoChannel*) it->key.pValue; if( chan->buffer->size > 0 ){ chselect = chan; selected = it->key.pValue; message = chan->buffer->items.pValue[0]; closed = NULL; break; }else if( chan->cap == 0 ){ closed = chan; } }else{ DaoFuture *fut = (DaoFuture*) it->key.pValue; if( fut->state == DAO_CALL_FINISHED ){ futselect = fut; selected = it->key.pValue; message = fut->value; break; } } } if( selected == NULL ) selected = (DaoValue*) closed; if( event->state == DAO_EVENT_WAIT && event->selects->value->size ){ if( selected == NULL ) goto MoveToWaiting; } GC_Assign( & event->message, message ); GC_Assign( & event->selected, selected ); event->auxiliary = event->selects->value->size == 0; event->type = DAO_EVENT_RESUME_TASKLET; /* change status to not finished: */ if( chselect != NULL || futselect != NULL ) event->auxiliary = 0; if( chselect ){ DList_PopFront( chselect->buffer ); if( chselect->buffer->size < chselect->cap ) DaoChannel_ActivateEvent( chselect, DAO_EVENT_WAIT_SENDING ); if( chselect->buffer->size ) DaoChannel_ActivateEvent( chselect, DAO_EVENT_WAIT_SELECT ); } if( futselect != NULL || closed != NULL ){ void *key = futselect ? (void*)futselect : (void*)closed; DMap_Erase( event->selects->value, key ); } break; default: break; } if( actor ){ DNode *it = DMap_Find( active, actor->rootObject ); if( actor->rootObject->isAsync ){ if( it && it->value.pVoid != (void*) future ) continue; }else if( it ){ continue; } } if( future->process && DMap_Find( active, future->process ) ) continue; DList_Erase( events, i, 1 ); DMap_Erase( pending, event ); if( actor ){ void *value = actor->rootObject->isAsync ? future : NULL; DMap_Insert( active, actor->rootObject, value ); } if( future->process ){ DMap_Insert( active, future->process, NULL ); future->process->active = 1; } /* // DaoValue_Move() should be used instead of GC_Assign() for thread safety. // Because using GC_Assign() here, may caused "future->message" of primitive // type being deleted, right after DaoFuture_GetGCFields() has retrieved it // for GC scanning. */ DaoValue_Move( event->message, & future->message, NULL ); DaoValue_Move( event->selected, & future->selected, NULL ); future->aux1 = event->auxiliary; future->timeout = event->timeout; GC_IncRC( future ); /* To be decreased at the end of tasklet; */ DaoCallServer_CacheEvent( event ); return future; MoveToWaiting: if( event->expiring >= 0.0 && event->expiring < MIN_TIME ) continue; if( event->expiring >= MIN_TIME ){ dao_complex com = {0.0,0.0}; com.real = event->expiring; DMap_Insert( server->waitings, & com, event ); DCondVar_Signal( & server->condv2 ); }else{ DList_Append( server->events2, event ); } DList_Erase( server->events, i, 1 ); i -= 1; } return NULL; }
void DaoCallServer_AddCall( DaoProcess *caller ) { DaoFuture *future; DaoTaskEvent *event; DaoProcess *callee = DaoVmSpace_AcquireProcess( caller->vmSpace ); DaoStackFrame *frame = caller->topFrame; DaoRoutine *routine = frame->routine; DaoType *type = (DaoType*) routine->routType->aux; DaoValue **params = caller->stackValues + caller->topFrame->stackBase; int i, count = caller->topFrame->parCount; if( caller->activeCode->b & DAO_CALL_BLOCK ){ DaoValue **calleeValues, **callerValues = caller->activeValues; DaoStackFrame *sectFrame = DaoProcess_FindSectionFrame( caller ); DaoStackFrame *callerFrame = caller->topFrame->prev; DaoVmCode *vmc, *end, *sect; if( sectFrame != callerFrame ){ DaoVmSpace_ReleaseProcess( caller->vmSpace, callee ); DaoProcess_RaiseError( caller, NULL, "Invalid code section" ); return; } if( routine->body ){ DaoProcess_PushRoutine( callee, callerFrame->routine, callerFrame->object ); callerValues = caller->stackValues + callerFrame->stackBase; }else{ DaoProcess_PushRoutine( callee, caller->activeRoutine, caller->activeObject ); } DaoProcess_SetActiveFrame( callee, callee->topFrame ); calleeValues = callee->stackValues + callee->topFrame->stackBase; callee->activeCode = caller->activeCode; vmc = callerFrame->routine->body->vmCodes->data.codes + callerFrame->entry; end = callerFrame->routine->body->vmCodes->data.codes + vmc->b; sect = vmc + 1; for(vmc=sect; vmc!=end; vmc++){ int i = -1, code = vmc->code; if( code == DVM_GETVH || (code >= DVM_GETVH_I && code <= DVM_GETVH_C) ){ i = vmc->b; }else if( code == DVM_SETVH || (code >= DVM_SETVH_II && code <= DVM_SETVH_CC) ){ i = vmc->b; } if( i >= 0 ) DaoValue_Move( callerValues[i], & calleeValues[i], NULL ); } } future = DaoFuture_New( type, 1 ); future->state = DAO_CALL_PAUSED; future->actor = caller->topFrame->object; GC_IncRC( future->actor ); GC_Assign( & future->process, callee ); GC_Assign( & callee->future, future ); callee->parCount = count; /* Use routine->parCount instead of caller->topFrame->parCount, for default parameters: */ for(i=0; i<routine->parCount; ++i) DaoValue_Copy( params[i], & callee->paramValues[i] ); if( routine->body ){ DaoProcess_PushRoutine( callee, routine, future->actor ); }else{ DaoProcess_PushFunction( callee, routine ); callee->activeNamespace = caller->activeNamespace; } if( caller->activeCode->b & DAO_CALL_BLOCK ){ callee->topFrame->host = callee->topFrame; callee->topFrame->retmode = DVM_RET_PROCESS; callee->topFrame->returning = 0; } #ifdef DAO_WITH_CONCURRENT DaoCallServer_TryInit( mainVmSpace ); event = DaoCallServer_MakeEvent(); DaoTaskEvent_Init( event, DAO_EVENT_RESUME_TASKLET, DAO_EVENT_RESUME, future, NULL ); DaoProcess_PopFrame( caller ); DaoProcess_PutValue( caller, (DaoValue*) future ); DaoCallServer_Add( event ); #else DaoProcess_PopFrame( caller ); DaoProcess_PutValue( caller, (DaoValue*) future ); DaoProcess_InterceptReturnValue( callee ); DaoProcess_Execute( callee ); DaoProcess_ReturnFutureValue( callee, future ); DaoVmSpace_ReleaseProcess( caller->vmSpace, callee ); #endif }
int DaoValue_Move4( DaoValue *S, DaoValue **D, DaoType *T, DaoType *C, DMap *defs ) { DaoCinType *cintype; int tm = 1; switch( (T->tid << 8) | S->type ){ case (DAO_BOOLEAN << 8) | DAO_BOOLEAN : case (DAO_BOOLEAN << 8) | DAO_INTEGER : case (DAO_BOOLEAN << 8) | DAO_FLOAT : case (DAO_INTEGER << 8) | DAO_BOOLEAN : case (DAO_INTEGER << 8) | DAO_INTEGER : case (DAO_INTEGER << 8) | DAO_FLOAT : case (DAO_FLOAT << 8) | DAO_BOOLEAN : case (DAO_FLOAT << 8) | DAO_INTEGER : case (DAO_FLOAT << 8) | DAO_FLOAT : case (DAO_COMPLEX << 8) | DAO_COMPLEX : case (DAO_STRING << 8) | DAO_STRING : case (DAO_CINVALUE<< 8) | DAO_CINVALUE : S = DaoValue_SimpleCopyWithTypeX( S, T, C ); GC_Assign( D, S ); return 1; } switch( S->type ){ case DAO_ENUM : if( S->xEnum.subtype == DAO_ENUM_SYM && T->realnum ) return 0; break; case DAO_OBJECT : if( S->xObject.isNull ) return 0; break; case DAO_CDATA : if( S->xCdata.data == NULL && ! DaoType_IsNullable(T) ) return 0; break; } if( !(S->xBase.trait & DAO_VALUE_CONST) ){ DaoVmSpace *vms; DaoType *ST = NULL; switch( (S->type << 8) | T->tid ){ case (DAO_ARRAY<<8)|DAO_ARRAY : vms = DaoType_GetVmSpace( T ); ST = vms->typeArrays[ S->xArray.etype ]; break; case (DAO_TUPLE<<8)|DAO_TUPLE : ST = S->xTuple.ctype; break; case (DAO_LIST <<8)|DAO_LIST : ST = S->xList.ctype; break; case (DAO_MAP <<8)|DAO_MAP : ST = S->xMap.ctype; break; case (DAO_CDATA<<8)|DAO_CDATA : ST = S->xCdata.ctype; break; case (DAO_CSTRUCT<<8)|DAO_CSTRUCT : ST = S->xCstruct.ctype; break; case (DAO_OBJECT<<8)|DAO_OBJECT : ST = S->xObject.defClass->objType; break; } if( ST == T ){ if( ST->tid == DAO_CSTRUCT || ST->tid == DAO_CDATA ){ DaoValue_MoveCstruct( S, D, C != NULL && C->invar != 0 ); }else{ GC_Assign( D, S ); } return 1; } } if( (T->tid == DAO_OBJECT || T->tid == DAO_CSTRUCT || T->tid == DAO_CDATA) && S->type == DAO_OBJECT ){ if( S->xObject.defClass != & T->aux->xClass ){ S = DaoObject_CastToBase( S->xObject.rootObject, T ); if( S != NULL && S->type == DAO_CDATA && S->xCdata.data == NULL ){ if( ! DaoType_IsNullable( T ) ) return 0; } tm = (S != NULL); } }else if( (T->tid == DAO_CLASS || T->tid == DAO_CTYPE) && S->type == DAO_CLASS ){ if( S->xClass.clsType != T && T->aux != NULL ){ /* T->aux == NULL for "class"; */ S = DaoClass_CastToBase( (DaoClass*)S, T ); tm = (S != NULL); } }else if( T->tid == DAO_CTYPE && S->type == DAO_CTYPE ){ if( S->xCtype.classType != T ){ S = DaoType_CastToParent( S, T ); tm = (S != NULL); } }else if( T->tid == DAO_ROUTINE && T->subtid != DAO_ROUTINES && S->type == DAO_ROUTINE && S->xRoutine.overloads ){ DList *routines = S->xRoutine.overloads->routines; int i, k, n; /* // Do not use DaoRoutine_ResolveByType( S, ... ) // "S" should match to "T", not the other way around! */ tm = 0; for(i=0,n=routines->size; i<n; i++){ DaoRoutine *rout = routines->items.pRoutine[i]; k = rout->routType == T ? DAO_MT_EQ : DaoType_MatchTo( rout->routType, T, defs ); if( k > tm ) tm = k; if( rout->routType == T ){ S = (DaoValue*) rout; break; } } }else{ tm = DaoType_MatchValue( T, S, defs ); } #if 0 if( tm ==0 ){ printf( "T = %p; S = %p, type = %i %i\n", T, S, S->type, DAO_ROUTINE ); printf( "T: %s %i %i\n", T->name->chars, T->tid, tm ); if( S->type == DAO_LIST ) printf( "%s\n", S->xList.ctype->name->chars ); if( S->type == DAO_TUPLE ) printf( "%p\n", S->xTuple.ctype ); } printf( "S->type = %p %s %i\n", S, T->name->chars, tm ); #endif if( tm == 0 ) return 0; /* // Composite types must match exactly. Example, // where it will not work if composite types are allowed to match loosely. // d : list<list<int>> = {}; // e : list<float> = { 1.0 }; // d.append( e ); // // But if d is of type list<list<any>>, // the matching do not necessary to be exact. */ cintype = NULL; if( T->tid == DAO_CINVALUE ){ if( DaoType_MatchValue( T->aux->xCinType.target, S, NULL ) >= DAO_MT_CIV ){ cintype = (DaoCinType*) T->aux; } }else if( T->tid == DAO_INTERFACE && T->aux->xInterface.concretes ){ DaoInterface *inter = (DaoInterface*) T->aux; DaoType *st = DaoValue_GetType( S, inter->nameSpace->vmSpace ); DNode *it; cintype = DaoInterface_GetConcrete( inter, st ); if( cintype == NULL ){ for(it=DMap_First(inter->concretes); it; it=DMap_Next(inter->concretes,it)){ if( DaoType_MatchValue( it->key.pType, S, NULL ) >= DAO_MT_CIV ){ cintype = (DaoCinType*) it->value.pVoid; break; } } } } if( cintype ){ S = (DaoValue*) DaoCinValue_New( cintype, S ); }else if( S->type == DAO_CSTRUCT || S->type == DAO_CDATA ){ DaoValue_MoveCstruct( S, D, C != NULL && C->invar != 0 ); return 1; }else{ S = DaoValue_SimpleCopyWithTypeX( S, T, C ); } GC_Assign( D, S ); if( S->type == DAO_TUPLE && S->xTuple.ctype != T && tm == DAO_MT_SIM ){ return DaoValue_TryCastTuple( S, D, T ); }else if( T && T->tid == S->type && !(T->attrib & DAO_TYPE_SPEC) ){ DaoValue_SetType( S, T ); } return 1; }
int DaoValue_Move5( DaoValue *S, DaoValue **D, DaoType *T, DaoType *C, DMap *defs ) { DaoValue *D2 = *D; if( S == D2 && (S == NULL || DaoValue_FastMatchTo( S, T )) ) return 1; if( S == NULL ){ GC_DecRC( *D ); *D = NULL; return 0; } if( T == NULL ){ DaoValue_CopyX( S, D, C ); return 1; } if( T->valtype ){ if( DaoValue_Compare( S, T->value ) !=0 ) return 0; DaoValue_CopyX( S, D, C ); return 1; } switch( T->tid ){ case DAO_UDT : DaoValue_CopyX( S, D, C ); return 1; case DAO_THT : if( T->aux ) return DaoValue_Move5( S, D, (DaoType*) T->aux, C, defs ); DaoValue_CopyX( S, D, C ); return 1; case DAO_ANY : DaoValue_CopyX( S, D, C ); DaoValue_SetType( *D, T ); return 1; case DAO_VARIANT : return DaoValue_MoveVariant( S, D, T, C ); default : break; } if( S->type >= DAO_OBJECT || !(S->xBase.trait & DAO_VALUE_CONST) || T->invar ){ if( DaoValue_FastMatchTo( S, T ) ){ if( S->type == DAO_CDATA && S->xCdata.data == NULL ){ if( ! DaoType_IsNullable( T ) ) return 0; } if( S->type == DAO_CSTRUCT || S->type == DAO_CDATA ){ DaoValue_MoveCstruct( S, D, C != NULL && C->invar != 0 ); }else if( S->type == DAO_CINVALUE ){ DaoValue_MoveCinValue( (DaoCinValue*) S, D ); }else{ GC_Assign( D, S ); } return 1; } } if( S->type == DAO_CINVALUE ){ if( S->xCinValue.cintype->target == T ){ S = S->xCinValue.value; }else if( DaoType_MatchTo( S->xCinValue.cintype->target, T, NULL ) >= DAO_MT_EQ ){ S = S->xCinValue.value; } } if( D2 && D2->xBase.refCount > 1 ){ GC_DecRC( D2 ); *D = D2 = NULL; } #if 0 if( D2 && S->type == D2->type && S->type == T->tid && S->type <= DAO_ENUM ){ switch( S->type ){ case DAO_ENUM : DaoEnum_SetType( & D2->xEnum, T->subtid == DAO_ENUM_ANY ? S->xEnum.etype : T ); return DaoEnum_SetValue( & D2->xEnum, & S->xEnum ); case DAO_BOOLEAN : case DAO_INTEGER : D2->xInteger.value = S->xInteger.value; break; case DAO_FLOAT : D2->xFloat.value = S->xFloat.value; break; case DAO_COMPLEX : D2->xComplex.value = S->xComplex.value; break; case DAO_STRING : DString_Assign( D2->xString.value, S->xString.value ); break; } return 1; } #endif if( D2 == NULL || D2->type != T->tid ) return DaoValue_Move4( S, D, T, C, defs ); switch( (S->type << 8) | T->tid ){ case (DAO_STRING<<8)|DAO_STRING : DString_Assign( D2->xString.value, S->xString.value ); break; case (DAO_ENUM<<8)|DAO_ENUM : DaoEnum_SetType( & D2->xEnum, T->subtid == DAO_ENUM_ANY ? S->xEnum.etype : T ); DaoEnum_SetValue( & D2->xEnum, & S->xEnum ); break; case (DAO_CINVALUE<<8)|DAO_CINVALUE : if( S->xCinValue.cintype->vatype != T ) return DaoValue_Move4( S, D, T, C, defs ); DaoValue_MoveCinValue( (DaoCinValue*) S, D ); break; case (DAO_BOOLEAN<<8)|DAO_BOOLEAN : D2->xBoolean.value = S->xBoolean.value; break; case (DAO_BOOLEAN<<8)|DAO_INTEGER : D2->xInteger.value = S->xBoolean.value; break; case (DAO_BOOLEAN<<8)|DAO_FLOAT : D2->xFloat.value = S->xBoolean.value; break; case (DAO_INTEGER<<8)|DAO_BOOLEAN : D2->xBoolean.value = S->xInteger.value; break; case (DAO_INTEGER<<8)|DAO_INTEGER : D2->xInteger.value = S->xInteger.value; break; case (DAO_INTEGER<<8)|DAO_FLOAT : D2->xFloat.value = S->xInteger.value; break; case (DAO_FLOAT <<8)|DAO_BOOLEAN : D2->xBoolean.value = S->xFloat.value; break; case (DAO_FLOAT <<8)|DAO_INTEGER : D2->xInteger.value = S->xFloat.value; break; case (DAO_FLOAT <<8)|DAO_FLOAT : D2->xFloat.value = S->xFloat.value; break; case (DAO_COMPLEX<<8)|DAO_COMPLEX : D2->xComplex.value = S->xComplex.value; break; default : return DaoValue_Move4( S, D, T, C, defs ); } return 1; }
static void WIN_Show( DaoProcess *proc, DaoValue *p[], int N ) { DaoxWindow *self = (DaoxWindow*) p[0]; DaoxCanvas *canvas = (DaoxCanvas*) DaoValue_CastCstruct( p[1], daox_type_canvas ); DaoxScene *scene = (DaoxScene*) DaoValue_CastCstruct( p[1], daox_type_scene ); DaoxFont *font = DaoxFont_GetDefault(); int fpsLimit = p[2]->xInteger.value; int fpsTest = p[3]->xBoolean.value; double fpsTestTime = 0.0; double timeInterval = 0.0; double lastFrameStart = 0.0; float currentFPS = 0.0; size_t fpsCount = 0; char chars[32]; if( fpsTest && self->widget == NULL ){ char *fpsText = "FPS: "; DaoxColor bgcolor = {0.0,0.0,0.0,0.0}; DaoxBrush *brush; self->widget = DaoxCanvas_New( NULL ); self->widget->viewport.right = self->width; self->widget->viewport.top = self->height; DaoGC_IncRC( (DaoValue*) self->widget ); DaoxCanvas_SetBackground( self->widget, bgcolor ); brush = DaoxCanvas_PushBrush( self->widget, 0 ); brush->strokeColor.blue = 1.0; brush->fillColor.blue = 1.0; brush->fillColor.alpha = 1.0; brush->fontSize = 20; self->fpsLabel = DaoxCanvas_AddText( self->widget, fpsText, 10, self->height - 20, 0 ); } if( self->painter == NULL && (canvas != NULL || self->widget != NULL) ){ self->painter = DaoxPainter_New( self->context ); DaoGC_IncRC( (DaoValue*) self->painter ); } if( self->renderer == NULL && scene != NULL ){ self->renderer = DaoxRenderer_New( self->context ); DaoGC_IncRC( (DaoValue*) self->renderer ); } if( canvas != NULL ){ float dm = sqrt(self->width*self->width + self->height*self->height ); float cx = 0.5*(canvas->viewport.left + canvas->viewport.right); float cy = 0.5*(canvas->viewport.top + canvas->viewport.bottom); float w = canvas->viewport.right - canvas->viewport.left; float h = canvas->viewport.top - canvas->viewport.bottom; float d = sqrt(w*w + h*h); w = 0.5 * self->width * d / dm; h = 0.5 * self->height * d / dm; canvas->viewport.left = cx - w; canvas->viewport.right = cx + w; canvas->viewport.bottom = cy - h; canvas->viewport.top = cy + h; } GC_Assign( & self->model, p[1] ); self->visible = 1; glfwShowWindow( self->handle ); glfwMakeContextCurrent( self->handle ); glfwSetKeyCallback( self->handle, DaoxWindow_KeyCallback ); glfwSetCursorPosCallback( self->handle, DaoxWindow_CursorMoveCallback ); glfwSetCursorEnterCallback( self->handle, DaoxWindow_CursorEnterCallback ); glfwSetWindowFocusCallback( self->handle, DaoxWindow_FocusCallback ); #ifdef SAVE_RENDERED_SCENE char name[50]; int frame = 1; DaoxImage *image = DaoxImage_New(); image->depth = DAOX_IMAGE_BIT32; DaoxImage_Resize( image, self->width, self->height ); #endif while( self->visible && ! glfwWindowShouldClose( self->handle ) ){ double frameStartTime = 0.0; double frameEndTime = 0.0; frameStartTime = glfwGetTime(); if( canvas ) DaoxPainter_Paint( self->painter, canvas, canvas->viewport ); if( scene ){ #ifdef SAVE_RENDERED_SCENE DaoxScene_Update( scene, 1.0/30.0 ); glReadBuffer( GL_BACK ); glPixelStorei( GL_UNPACK_ALIGNMENT, 4 ); glPixelStorei( GL_PACK_ROW_LENGTH, image->width ); DaoxRenderer_Render( self->renderer, scene, scene->camera ); glReadPixels( 0, 0, self->width, self->height, GL_RGBA, GL_UNSIGNED_BYTE, image->imageData ); sprintf( name, "rama_attack_frame_%03i.png", frame ); DaoxImage_SavePNG( image, name ); frame += 1; if( frame > 155 ) break; #else DaoxScene_Update( scene, frameStartTime - lastFrameStart ); DaoxRenderer_Render( self->renderer, scene, scene->camera ); #endif } lastFrameStart = frameStartTime; if( fpsTest ){ if( fpsCount % 10 == 0 ){ int i, n = sprintf( chars, "%.1f", currentFPS ); for(i=0; i<n; ++i){ DaoxGlyph *glyph = DaoxFont_GetGlyph( font, chars[i] ); DaoxCanvasNode *chnode = self->fpsLabel->children->items.pCanvasNode[i+5]; DaoxPath *path = DaoxPathCache_FindPath( self->widget->pathCache, glyph->shape ); GC_Assign( & chnode->path, path ); DaoxCanvasNode_MarkDataChanged( chnode ); } } DaoxPainter_Paint( self->painter, self->widget, self->widget->viewport ); } glfwSwapBuffers( self->handle ); glfwPollEvents(); if( fpsTest == 0 ) continue; frameEndTime = glfwGetTime(); timeInterval = frameEndTime - frameStartTime; if( timeInterval < 1.0/fpsLimit ) usleep( 1000000 * (1.0/fpsLimit - timeInterval) ); fpsCount += 1; currentFPS = fpsCount / (frameEndTime - fpsTestTime); if( frameEndTime > (fpsTestTime + 3) ){ fpsTestTime = frameEndTime - 1.0; fpsCount = currentFPS; /* Frame count estimation in the past second; */ } } glfwHideWindow( self->handle ); }
void DaoxGraph_ConnectedComponents( DaoxGraph *self, DList *cclist ) { DList *nodes; DaoxGraph *subgraph; daoint i, j, k, n; if( self->nodes->size == 0 ){ DList_PushBack( cclist, self ); return; } for(i=0; i<self->nodes->size; i++){ DaoxNode *node = (DaoxNode*) self->nodes->items.pVoid[i]; node->state = 0; } nodes = DList_New(0); while( self->nodes->size ){ DaoxNode_BreadthFirstSearch( (DaoxNode*) self->nodes->items.pVoid[0], nodes ); #if 0 printf( "self->nodes->size = %i, %i\n", self->nodes->size, nodes->size ); #endif if( nodes->size == self->nodes->size ){ DList_PushBack( cclist, self ); break; } subgraph = DaoxGraph_New( self->ctype, self->directed ); DList_PushBack( cclist, subgraph ); for(i=0,n=nodes->size; i<n; i++){ DaoxNode *node = (DaoxNode*) nodes->items.pVoid[i]; GC_Assign( & node->graph, subgraph ); DList_PushBack( subgraph->nodes, node ); for(j=0; j<node->outs->size; j++){ DaoxEdge *edge = (DaoxEdge*) node->outs->items.pVoid[j]; if( edge->graph == subgraph ) continue; GC_Assign( & edge->graph, subgraph ); DList_PushBack( subgraph->edges, edge ); } } for(i=0,k=0,n=self->nodes->size; i<n; i++){ DaoxNode *node = (DaoxNode*) self->nodes->items.pVoid[i]; /* Ensure no duplication of the reference (for the Concurrent GC): */ self->nodes->items.pVoid[i] = NULL; if( node->graph != self ){ GC_DecRC( node ); continue; } self->nodes->items.pVoid[k++] = node; } self->nodes->size = k; for(i=0,k=0,n=self->edges->size; i<n; i++){ DaoxNode *edge = (DaoxNode*) self->edges->items.pVoid[i]; /* Ensure no duplication of the reference (for the Concurrent GC): */ self->edges->items.pVoid[i] = NULL; if( edge->graph != self ){ GC_DecRC( edge ); continue; } self->edges->items.pVoid[k++] = edge; } self->edges->size = k; } DList_Delete( nodes ); }
static void DaoMT_Functional( DaoProcess *proc, DaoValue *P[], int N, int F ) { DMutex mutex; DCondVar condv; DaoTaskData *tasks; DaoValue *param = P[0]; DaoValue *result = NULL; DaoList *list = NULL; DaoArray *array = NULL; DaoVmCode *sect = NULL; DaoStackFrame *frame = DaoProcess_FindSectionFrame( proc ); int i, entry, threads = P[1]->xInteger.value; daoint index = -1, status = 0, joined = 0; DNode *node = NULL; switch( F ){ case DVM_FUNCT_MAP : if( param->type == DAO_ARRAY ){ array = DaoProcess_PutArray( proc ); result = (DaoValue*) array; }else{ list = DaoProcess_PutList( proc ); result = (DaoValue*) list; } break; case DVM_FUNCT_FIND : DaoProcess_PutValue( proc, dao_none_value ); break; } if( threads <= 0 ) threads = 2; if( frame != proc->topFrame->prev ){ DaoProcess_RaiseError( proc, NULL, "Invalid code section from non-immediate caller" ); return; } sect = DaoProcess_InitCodeSection( proc, 0 ); if( sect == NULL ) return; if( list ){ DList_Clear( list->value ); if( param->type == DAO_LIST ) DList_Resize( list->value, param->xList.value->size, NULL ); if( param->type == DAO_MAP ) DList_Resize( list->value, param->xMap.value->size, NULL ); #ifdef DAO_WITH_NUMARRAY }else if( array && F == DVM_FUNCT_MAP ){ DaoArray_GetSliceShape( (DaoArray*) param, & array->dims, & array->ndim ); DaoArray_ResizeArray( array, array->dims, array->ndim ); #endif } DMutex_Init( & mutex ); DCondVar_Init( & condv ); entry = proc->topFrame->entry; tasks = (DaoTaskData*) dao_calloc( threads, sizeof(DaoTaskData) ); DaoProcess_PopFrame( proc ); for(i=0; i<threads; i++){ DaoTaskData *task = tasks + i; task->param = param; task->result = result; task->proto = proc; task->sect = sect; task->funct = F; task->entry = entry; task->first = i; task->step = threads; task->index = & index; task->node = & node; task->joined = & joined; task->condv = & condv; task->mutex = & mutex; task->clone = DaoVmSpace_AcquireProcess( proc->vmSpace ); if( i ) DaoCallServer_AddTask( DaoMT_RunFunctional, task, task->clone ); } DaoMT_RunFunctional( tasks ); DMutex_Lock( & mutex ); while( joined < threads ) DCondVar_TimedWait( & condv, & mutex, 0.01 ); DMutex_Unlock( & mutex ); for(i=0; i<threads; i++){ DaoTaskData *task = tasks + i; DaoVmSpace_ReleaseProcess( proc->vmSpace, task->clone ); status |= task->status; } if( F == DVM_FUNCT_FIND ){ DaoTuple *tuple = DaoProcess_PutTuple( proc, 2 ); if( param->type == DAO_LIST && index != -1 ){ DaoValue **items = param->xList.value->items.pValue; GC_Assign( & tuple->values[1], items[index] ); tuple->values[0]->xInteger.value = index; }else if( param->type == DAO_MAP && node ){ GC_Assign( & tuple->values[0], node->key.pValue ); GC_Assign( & tuple->values[1], node->value.pValue ); } } if( status ) DaoProcess_RaiseError( proc, NULL, "code section execution failed!" ); DMutex_Destroy( & mutex ); DCondVar_Destroy( & condv ); dao_free( tasks ); }