Update of /cvsroot/monetdb/MonetDB5/src/mal
In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv14108/src/mal

Modified Files:
        mal_builder.mx mal_import.mx mal_instruction.mx 
        mal_interpreter.mx mal_module.mx mal_parser.mx mal_resolve.mx 
        mal_session.mx 
Log Message:
lots of leak fixes (thanks to valgrind)
        defConstant now clears the passed valRecord when it reuses
        a constant (same in mal_parser of constants)
callstring/compile now properly use pushClintInput and pop ClientInput

constants are now copied on to the stack without creating duplicate values.
This because in most cases these constants on the stk were never freed.





Index: mal_parser.mx
===================================================================
RCS file: /cvsroot/monetdb/MonetDB5/src/mal/mal_parser.mx,v
retrieving revision 1.207
retrieving revision 1.208
diff -u -d -r1.207 -r1.208
--- mal_parser.mx       25 Dec 2007 13:08:47 -0000      1.207
+++ mal_parser.mx       30 Dec 2007 18:21:13 -0000      1.208
@@ -423,8 +423,8 @@
        case '"':
                cst->vtype= TYPE_str;
                i= stringLength(cntxt);
-               cst->val.sval =strCopy(cntxt, i);
-               cst->len= strlen(cst->val.sval);
+               cst->val.sval = strCopy(cntxt, i);
+               cst->len = strlen(cst->val.sval);
                return i;
        case '\'':
                return charCst(cntxt,cst);
@@ -1527,6 +1527,7 @@
 
                cstidx = fndConstant(curBlk,&cst);
                if( cstidx >= 0){
+                       int free = 1;
                        advance(cntxt,i);
                        if( currChar(cntxt)==':') {
                                csttpe = 
typeElm(cntxt,getVarType(curBlk,cstidx));
@@ -1536,12 +1537,16 @@
                                        cstidx = 
defConstant(curBlk,csttpe,&cst);
                                        setPolymorphic(curInstr,csttpe, FALSE);
                                        freezeVarType(curBlk,cstidx);
+                                       free = 0;
                                }
-                       } else
-                       if( cst.vtype != getVarType(curBlk,cstidx)){
-                                       cstidx = 
defConstant(curBlk,cst.vtype,&cst);
-                                       setPolymorphic(curInstr,cst.vtype, 
FALSE);
+                       } else if( cst.vtype != getVarType(curBlk,cstidx)){
+                               cstidx = defConstant(curBlk,cst.vtype,&cst);
+                               setPolymorphic(curInstr,cst.vtype, FALSE);
+                               free = 0;
                        } 
+                       /* protect against leaks coming from constant reuse */
+                       if (free && ATOMextern(cst.vtype) && cst.val.pval)
+                               VALclear(&cst);
                        curInstr = pushArgument(curBlk,curInstr,cstidx);
                        @1;
                } else { 

Index: mal_import.mx
===================================================================
RCS file: /cvsroot/monetdb/MonetDB5/src/mal/mal_import.mx,v
retrieving revision 1.72
retrieving revision 1.73
diff -u -d -r1.72 -r1.73
--- mal_import.mx       6 Nov 2007 23:20:54 -0000       1.72
+++ mal_import.mx       30 Dec 2007 18:21:12 -0000      1.73
@@ -126,6 +126,14 @@
        Module oldnspace = c->nspace;
        Symbol oldprg = c->curprg;
        MalStkPtr oldglb = c->glb;
[EMAIL PROTECTED] restoreState3
+       bstream *oldfdin = c->fdin;
+       int oldmode = c->mode;
+       int oldblkmode = c->blkmode;
+       str oldsrcFile = c->srcFile;
+       Module oldnspace = c->nspace;
+       Symbol oldprg = c->curprg;
+       MalStkPtr oldglb = c->glb;
 
 @= restoreClient1
        if (c->fdin) {
@@ -150,6 +158,13 @@
 @= restoreClient
        @:restoreClient1()@
        @:restoreClient2()@
[EMAIL PROTECTED] restoreClient3
+       if (c->fdin) 
+               MCpopClientInput(c);
+       assert(c->fdin == oldfdin); 
+       c->mode = oldmode;
+       c->blkmode = oldblkmode;
+       c->srcFile = oldsrcFile;
 @= runPhase
        if(msg== MAL_SUCCEED && c->[EMAIL PROTECTED] && (msg= (str) (*c->[EMAIL 
PROTECTED])(c)) ){
                /* error occurred  and ignored */
@@ -266,19 +281,13 @@
 str
 compileString(Symbol *fcn, Client c, str s)
 {
-       @:restoreState@
+       @:restoreState3@
        int len = strlen(s);
        buffer *b;
        str msg = MAL_SUCCEED;
        str qry;
        str old = s;
 
-       c->yycur = 0;
-       c->prompt = GDKstrdup("");      /* do not produce visible prompts */
-       c->promptlength = strlen(c->prompt);
-       c->listing = 0;
-       c->bak = NULL;
-       c->fdin = NULL;
        c->srcFile= NULL;
 
        s = mal_cmdline(s, &len);
@@ -289,23 +298,22 @@
        buffer_init(b, qry, len);
        MCpushClientInput(c, bstream_create(buffer_rastream(b, 
"compileString"), b->len), 0, "");
        MSinitClientPrg(c,"user", "main");      /* create new context */
-       /* runPhase(MAL_SCENARIO_READER,restoreClient1) */
        if(msg== MAL_SUCCEED && c->phase[MAL_SCENARIO_READER] && 
                (msg= (str) (*c->phase[MAL_SCENARIO_READER])(c)) ){
-               @:restoreClient1()@
+               @:restoreClient3()@
                return msg;
        }
-       /* runPhase(MAL_SCENARIO_PARSER,restoreClient1) */
        if(msg== MAL_SUCCEED && c->phase[MAL_SCENARIO_PARSER] && 
                (msg= (str) (*c->phase[MAL_SCENARIO_PARSER])(c)) ){
                /* error occurred  and ignored */
                /* stream_printf(GDKout,"%s",msg);*/
-               @:restoreClient1()@
+               @:restoreClient3()@
                return msg;
        }
        *fcn= c->curprg;
        /* restore IO channel */
-       @:restoreClient()@
+       @:restoreClient3()@
+       @:restoreClient2()@
        GDKfree(qry);
        GDKfree(b);
        return MAL_SUCCEED;
@@ -317,18 +325,12 @@
 void
 callString(Client c, str s, int listing)
 {
-       @:restoreState@
+       @:restoreState3@
        int len = strlen(s);
        buffer *b;
        str msg = MAL_SUCCEED,qry;
        str old = s;
 
-       c->yycur = 0;
-       c->prompt = GDKstrdup("");      /* do not produce visible prompts */
-       c->promptlength = strlen(c->prompt);
-       c->listing = listing;
-       c->bak = NULL;
-       c->fdin = NULL;
        c->srcFile= NULL;
 
        s = mal_cmdline(s, &len);
@@ -339,10 +341,10 @@
        buffer_init(b, qry, len);
        MCpushClientInput(c, bstream_create(buffer_rastream(b, "callString"), 
b->len), listing, "");
        MSinitClientPrg(c,"user", "main");      /* create new context */
-       @:runPhase(MAL_SCENARIO_READER,restoreClient1)@
-       @:runPhase(MAL_SCENARIO_PARSER,restoreClient1)@
+       @:runPhase(MAL_SCENARIO_READER,restoreClient3)@
+       @:runPhase(MAL_SCENARIO_PARSER,restoreClient3)@
        /* restore IO channel */
-       @:restoreClient1()@
+       @:restoreClient3()@
        @:runPhase(MAL_SCENARIO_OPTIMIZE,restoreClient2)@
        @:runPhase(MAL_SCENARIO_SCHEDULER,restoreClient2)@
        @:runPhase(MAL_SCENARIO_ENGINE,restoreClient2)@

Index: mal_resolve.mx
===================================================================
RCS file: /cvsroot/monetdb/MonetDB5/src/mal/mal_resolve.mx,v
retrieving revision 1.130
retrieving revision 1.131
diff -u -d -r1.130 -r1.131
--- mal_resolve.mx      9 Dec 2007 16:21:06 -0000       1.130
+++ mal_resolve.mx      30 Dec 2007 18:21:13 -0000      1.131
@@ -460,13 +460,13 @@
 Since we now know the storage type of the receiving variable, we can
 set the garbagge collection flag.
 @= prepostProcess
-       if( findGDKtype(@1) == TYPE_bat){
+       if (findGDKtype(@1) == TYPE_bat){
                setVarCleanup(mb,getArg(p,@2)) = TRUE;
                getInstrPtr(@3,0)->gc |= GARBAGECONTROL;
                p->gc|= QUICKCLEANUP;
-       }
-       else if( !isPolyType(@1)  && @1< TYPE_any && 
-                       @1>=0 && ATOMstorage(@1)== TYPE_str){
+       } else if (!isPolyType(@1)  && @1< TYPE_any && 
+               @1>=0 && ATOMstorage(@1)== TYPE_str &&
+               !isConstant(mb,getArg(p,@2))){
                getInstrPtr(@3,0)->gc |= GARBAGECONTROL;
                setVarCleanup(mb,getArg(p,@2)) = TRUE;
                p->gc|= QUICKCLEANUP;

Index: mal_module.mx
===================================================================
RCS file: /cvsroot/monetdb/MonetDB5/src/mal/mal_module.mx,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -d -r1.64 -r1.65
--- mal_module.mx       24 Dec 2007 12:28:24 -0000      1.64
+++ mal_module.mx       30 Dec 2007 18:21:12 -0000      1.65
@@ -298,10 +298,10 @@
 checked at runtime, without tremendous overhead.
 @c
 void deleteSymbol(Module scope, Symbol prg){
-               InstrPtr sig;
-               int t;
+       InstrPtr sig;
+       int t;
 
-               sig = getSignature(prg);
+       sig = getSignature(prg);
        if( getModuleId(sig) && getModuleId(sig)!= scope->name ){
                /* move the definition to the proper place */
                Module c= findModule(scope,getModuleId(sig));
@@ -310,17 +310,17 @@
                } else scope = c;
        }
        t = getSubScope(getFunctionId(sig));
-       if( scope->subscope[t] == prg){
+       if (scope->subscope[t] == prg) {
                scope->subscope[t] = scope->subscope[t]->peer;
                freeSymbol(prg);
        } else {
                Symbol nxt = scope->subscope[t];
-               while( nxt->peer != NULL){
-                       if( nxt->peer == prg){
-                           nxt->peer = prg->peer;
-                           nxt->skip = prg->peer;
-                           freeSymbol(prg);
-                           return;
+               while (nxt->peer != NULL) {
+                       if (nxt->peer == prg) {
+                               nxt->peer = prg->peer;
+                               nxt->skip = prg->peer;
+                               freeSymbol(prg);
+                               return;
                        }
                        nxt = nxt->peer;
                }

Index: mal_session.mx
===================================================================
RCS file: /cvsroot/monetdb/MonetDB5/src/mal/mal_session.mx,v
retrieving revision 1.146
retrieving revision 1.147
diff -u -d -r1.146 -r1.147
--- mal_session.mx      6 Nov 2007 23:20:55 -0000       1.146
+++ mal_session.mx      30 Dec 2007 18:21:14 -0000      1.147
@@ -383,7 +383,7 @@
        int i;
        InstrPtr p;
 
-       for (i = start; i < mb->stop; i++) {
+       for (i = start; i < mb->ssize; i++) {
                p = getInstrPtr(mb, i);
                if (p)
                        freeInstruction(p);
@@ -404,23 +404,23 @@
 {
        int i, j;
 
-       for (i = j = start; i < mb->vtop;) {
+       for (i = j = start; i < mb->vtop; i++) {
                if (isTmpVar(mb, i) || unknownType(getVarType(mb,i)) ) {
-                       clearVariable(mb, i);
-
                        if (glb) {
-                               garbageElement(&glb->stk[i]);
+                               if (!isConstant(mb,i))
+                                       garbageElement(&glb->stk[i]);
                                /* clean stack entry */
                                glb->stk[i].vtype = TYPE_int;
                                glb->stk[i].val.ival = 0;
                                glb->stk[i].len = 0;
                        }
-                       i++;
+                       clearVariable(mb, i);
                } else {
+                       assert(!mb->var[i]->value.vtype || 
mb->var[i]->isaconstant );
                        if (i != j) {
-                               VarPtr v= getVar(mb,j);
-                               mb->var[j]= mb->var[i];
-                               getVar(mb,i)= v;
+                               VarPtr v = getVar(mb,j);
+                               getVar(mb,j) = getVar(mb,i);
+                               getVar(mb,i) = v;
                                if (glb) {
                                        /* save stack state */
                                        glb->stk[j] = glb->stk[i];
@@ -430,7 +430,6 @@
                                        glb->stk[i].len = 0;
                                }
                        }
-                       i++;
                        j++;
                }
        }

Index: mal_instruction.mx
===================================================================
RCS file: /cvsroot/monetdb/MonetDB5/src/mal/mal_instruction.mx,v
retrieving revision 1.291
retrieving revision 1.292
diff -u -d -r1.291 -r1.292
--- mal_instruction.mx  27 Dec 2007 17:13:14 -0000      1.291
+++ mal_instruction.mx  30 Dec 2007 18:21:12 -0000      1.292
@@ -683,15 +683,15 @@
        int i;
 
        for (i = 0; i < mb->ssize; i++) 
-               if( mb->stmt[i]){
+               if (mb->stmt[i]){
                        freeInstruction(mb->stmt[i]);
                        mb->stmt[i] = NULL;
                }
        mb->stop = 0;
        for (i = 0; i < mb->vsize; i++)
-               if( mb->var[i]){
+               if (mb->var[i]){
                        freeVariable(mb, i);
-                       mb->var[i]=0;
+                       mb->var[i] = 0;
                }
        mb->vtop = 0;
        GDKfree(mb->stmt);
@@ -734,12 +734,12 @@
        mb->history = NULL;
        mb->keephistory= old->keephistory;
        mb->marker = 0;
-       mb->var = (VarPtr *) GDKmalloc(sizeof(VarPtr) * old->vsize);
+       mb->var = (VarPtr *) GDKzalloc(sizeof(VarPtr) * old->vsize);
 
        if (mb->var == NULL)
                GDKfatal("newMalBlk:could not get variable storage\n");
        mb->vsize = old->vsize;
-       memcpy((char *) mb->var, old->var, sizeof(VarPtr) * old->vsize);
+       memcpy((char *) mb->var, old->var, sizeof(VarPtr) * old->vtop);
 
        mb->vtop = 0;
        for (i = 0; i < old->vtop; i++) {
@@ -845,7 +845,7 @@
 {
        VarRecord **v;
        InstrPtr *stmt;
-       int len;
+       int len,i;
 
        assert(varsize > 0 && stmtsize > 0);
        len = sizeof(ValPtr) * (mb->vtop + varsize);
@@ -855,6 +855,9 @@
 
        memcpy((str) v, (str) mb->var, sizeof(ValPtr) * mb->vtop);
 
+       for (i=mb->vtop; i< mb->vsize; i++) 
+               if (mb->var[i])
+                       freeVariable(mb,i);
        if (mb->var)
                GDKfree(mb->var);
        mb->var = v;
@@ -867,6 +870,10 @@
        if (stmt == NULL)
                GDKfatal("newMalBlk:could not get instruction storage\n");
        memcpy((str) stmt, (str) mb->stmt, sizeof(InstrPtr) * mb->stop);
+       for (i=mb->stop; i< mb->ssize; i++) {
+               if (mb->stmt[i])
+                       freeInstruction(mb->stmt[i]);
+       }
        GDKfree(mb->stmt);
        mb->stmt = stmt;
 
@@ -889,8 +896,8 @@
 trimMalBlk(MalBlkPtr mb)
 {
        (void) mb;              /* fool the compiler */
-       /* printf("safe %d %d\n",mb->vtop, (mb->vsize-mb->vtop)*sizeof(VarPtr));
-          trimexpand(mb,0); */
+       /* printf("safe %d %ld\n", mb->vtop, 
(mb->vsize-mb->vtop)*sizeof(VarPtr));
+          trimexpand(mb, mb->vsize, mb->ssize); */
 }
 
 @-
@@ -926,8 +933,10 @@
        if (mb && mb->stop <mb->ssize) {
                p = mb->stmt[mb->stop];
 
-               if (p && p->maxarg < MAXARG)
+               if (p && p->maxarg < MAXARG) {
+                       assert(0);
                        p = NULL;
+               }
                mb->stmt[mb->stop] = NULL;
        }
        if (p == NULL) {
@@ -1042,9 +1051,10 @@
                mb->stmt[i] = mb->stmt[i + 1];
 
        mb->stop--;
-       mb->stmt[i] = p;
+       assert(i==mb->stop);
 
-       /* freeInstruction(p); */
+       /* move statement after stop */
+       mb->stmt[i] = p;
 }
 
 void
@@ -1807,34 +1817,42 @@
 }
 
 int
-defConstant(MalBlkPtr mb, int type, ValPtr cst)
+defConstant(MalBlkPtr mb, int type, ValPtr cst )
 {
        int i, k;
        ValPtr vr;
 
        if (cst->vtype != type && !isaBatType(type) && !isPolyType(type)){
-               int otype= cst->vtype;
+               ValRecord vr = *cst;
+               int otype = cst->vtype;
                i= convertConstant(type, cst);
-               if( i ) {
+               if (i) {
                        str ft,tt;
+
+                       /* free old value */
                        ft= getTypeName(otype);
                        tt= getTypeName(type);
                        showException(SYNTAX, "defConstant", "constant coercion 
error from %s to %s", ft,tt);
                        GDKfree(ft);
                        GDKfree(tt);
                        mb->errors++;
-               } else
+               } else {
                        assert(cst->vtype== type);
+               }
+               VALclear(&vr);
        }
        k= fndConstant(mb,cst);
-       if( k >= 0 )
+       if( k >= 0 ) {
+               /* protect against leaks coming from constant reuse */
+               if (ATOMextern(type) && cst->val.pval)
+                       VALclear(cst);
                return k;
+       }
        k = newTmpVariable(mb, type);
        isConstant(mb, k) = 1;
        setFixed(mb, k);
        vr = &getConstant(mb, k);
        *vr = *cst;
-       /*memcpy((char *) vr, cst, sizeof(ValRecord));*/
        return k;
 }
 

Index: mal_builder.mx
===================================================================
RCS file: /cvsroot/monetdb/MonetDB5/src/mal/mal_builder.mx,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- mal_builder.mx      27 Dec 2007 17:27:07 -0000      1.29
+++ mal_builder.mx      30 Dec 2007 18:21:11 -0000      1.30
@@ -260,15 +260,11 @@
 {
        int _t;
        ValRecord cst;
-       char *val = (char*)Val;
 
        cst.vtype= TYPE_str;
-       cst.val.sval= val;
+       cst.val.sval= GDKstrdup(Val);
        cst.len= strlen(cst.val.sval);
        _t = defConstant(mb,TYPE_str,&cst);
-
-       if (getConstant(mb,_t).val.sval == val) 
-               getConstant(mb,_t).val.sval = GDKstrdup(val);
        return pushArgument(mb, q, _t);
 }
 
@@ -294,14 +290,21 @@
        int _t;
        ValRecord cst;
 
-       if( !isaBatType(tpe) ){
-               cst.vtype=TYPE_void;
-               cst.val.oval= oid_nil;
-               convertConstant(tpe, &cst);
+       if( !isaBatType(tpe) && tpe != TYPE_bat ) {
+               if (!tpe) {
+                       cst.vtype=TYPE_void;
+                       cst.val.oval= oid_nil;
+               } else if (ATOMextern(tpe)) {
+                       ptr p = ATOMnil(tpe);
+                       VALset(&cst, tpe, p);
+               } else {
+                       ptr p = ATOMnilptr(tpe);
+                       VALset(&cst, tpe, p);
+               }
                _t = defConstant(mb,tpe,&cst);
-       } else{
-               cst.vtype=TYPE_bat;
-               cst.val.bval= 0;
+       } else {
+               cst.vtype = TYPE_bat;
+               cst.val.bval = 0;
                _t = defConstant(mb,TYPE_bat,&cst);
        }
        return pushArgument(mb, q, _t);

Index: mal_interpreter.mx
===================================================================
RCS file: /cvsroot/monetdb/MonetDB5/src/mal/mal_interpreter.mx,v
retrieving revision 1.204
retrieving revision 1.205
diff -u -d -r1.204 -r1.205
--- mal_interpreter.mx  17 Dec 2007 20:33:11 -0000      1.204
+++ mal_interpreter.mx  30 Dec 2007 18:21:12 -0000      1.205
@@ -194,15 +194,18 @@
 }
 @-
 Copy the constant values onto the stack frame
+Also we cannot overwrite values on the stack as this maybe part of a 
+sequence of factory calls.
 @= initStack
-       for(i= @1; i< mb->vtop; i++)
-       if( isConstant(mb,i) > 0 ){
-               lhs = &stk->stk[i];
-               rhs = &getConstant(mb,i);
-               VALcopy(lhs,rhs);
-       } else {
+       for(i= @1; i< mb->vtop; i++) {
                lhs = &stk->stk[i];
-               lhs->vtype = getVarGDKType(mb,i);
+               if( isConstant(mb,i) > 0 ){
+                       assert(mb->var[i]->cleanup == 0);
+                       rhs = &getConstant(mb,i);
+                       *lhs = *rhs;
+               } else {
+                       lhs->vtype = getVarGDKType(mb,i);
+               }
        }
 @c
 
@@ -319,8 +322,8 @@
        ret = runMALsequence(cntxt, mb, startpc,  0, stk, env, pcicaller);
 
        /* pass the new debug mode to the caller */
-       if(stk->cmd  && env && stk->cmd!='f') env->cmd = stk->cmd; 
-       if( !stk->keepAlive && garbageControl(getInstrPtr(mb,0)) )
+       if (stk->cmd  && env && stk->cmd!='f') env->cmd = stk->cmd; 
+       if (!stk->keepAlive && garbageControl(getInstrPtr(mb,0)) )
                garbageCollector(mb,stk, env != stk);
        @:endProfile@
        return ret;
@@ -346,8 +349,8 @@
        ret = runMALsequence(cntxt, mb, startpc,  stoppc, stk, env, pcicaller);
 
        /* pass the new debug mode to the caller */
-       if(env && stk->cmd!='f') env->cmd = stk->cmd;
-       if( !stk->keepAlive && garbageControl(getInstrPtr(mb,0)) )
+       if (env && stk->cmd!='f') env->cmd = stk->cmd;
+       if (!stk->keepAlive && garbageControl(getInstrPtr(mb,0)) )
                garbageCollector(mb,stk,env!=stk);
        return ret;
 }
@@ -999,6 +1002,7 @@
                        } else if( stk->stk[getArg(pci,i)].vtype == TYPE_str) {
                                backup[i]= stk->stk[getArg(pci,i)].len;
                                sbackup[i]= stk->stk[getArg(pci,i)].val.sval;
+                               backup[i] += (sbackup[i]!=NULL);
                        } 
                }
        } 
@@ -1472,11 +1476,11 @@
 void garbageElement(ValPtr v)
 {   
        if( v->vtype == TYPE_str) {
-               if(v->len && v->val.pval) {
+               if(v->val.pval) {
                        GDKfree(v->val.pval);
-                       v->val.pval= NULL;
+                       v->val.pval = NULL;
                }
-               v->len= 0;
+               v->len = 0;
                return;
        }
        if( v->vtype== TYPE_bat ) {
@@ -1520,7 +1524,8 @@
 stack frame.
 @c
 void garbageCollector(MalBlkPtr mb, MalStkPtr stk, int flag)
-{   int k;
+{   
+       int k;
        ValPtr v;
 
 #ifdef STACKTRACE
@@ -1528,8 +1533,8 @@
        printStack(GDKout,mb,stk,0);
 #endif
        for(k=0;k<mb->vtop; k++) {
-               if(isVarGarbage(mb,k) && (flag || isTmpVar(mb,k) )){
-                       garbageElement(v= &stk->stk[k]);
+               if (isVarGarbage(mb,k) && (flag || isTmpVar(mb,k) )){
+                       garbageElement(v = &stk->stk[k]);
                        v->vtype= TYPE_int;
                        v->val.ival= int_nil;
                }


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Monetdb-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/monetdb-checkins

Reply via email to