you may have code and dbrefs at the same time.
try to expand trail in single sweep git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@769 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
This commit is contained in:
parent
8c2af87600
commit
b37ee94fe9
40
C/dbase.c
40
C/dbase.c
|
@ -1062,11 +1062,11 @@ sf_include(sfp)
|
||||||
inline static DBRef
|
inline static DBRef
|
||||||
check_if_cons(DBRef p, Term to_compare)
|
check_if_cons(DBRef p, Term to_compare)
|
||||||
{
|
{
|
||||||
while (p != NIL
|
while (p != NIL
|
||||||
&& (p->Flags & (DBCode | ErasedMask | DBVar | DBNoVars | DBComplex)
|
&& (p->Flags & (DBCode | ErasedMask | DBVar | DBNoVars | DBComplex)
|
||||||
|| p->Entry != Unsigned(to_compare)))
|
|| p->Entry != Unsigned(to_compare)))
|
||||||
p = NextDBRef(p);
|
p = NextDBRef(p);
|
||||||
return (p);
|
return (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1218,7 +1218,7 @@ CreateDBStruct(Term Tm, DBProp p, int InFlag)
|
||||||
pp->id = FunctorDBRef;
|
pp->id = FunctorDBRef;
|
||||||
pp->Flags = DBVar;
|
pp->Flags = DBVar;
|
||||||
pp->Entry = (CELL) Tm;
|
pp->Entry = (CELL) Tm;
|
||||||
pp->u.Code = NULL;
|
pp->Code = NULL;
|
||||||
pp->NOfCells = 1;
|
pp->NOfCells = 1;
|
||||||
INIT_LOCK(pp->lock);
|
INIT_LOCK(pp->lock);
|
||||||
INIT_DBREF_COUNT(pp);
|
INIT_DBREF_COUNT(pp);
|
||||||
|
@ -1243,7 +1243,7 @@ CreateDBStruct(Term Tm, DBProp p, int InFlag)
|
||||||
pp->id = FunctorDBRef;
|
pp->id = FunctorDBRef;
|
||||||
pp->Flags = flag;
|
pp->Flags = flag;
|
||||||
pp->Entry = (CELL) Tm;
|
pp->Entry = (CELL) Tm;
|
||||||
pp->u.Code = NULL;
|
pp->Code = NULL;
|
||||||
pp->NOfCells = 1;
|
pp->NOfCells = 1;
|
||||||
INIT_LOCK(pp->lock);
|
INIT_LOCK(pp->lock);
|
||||||
INIT_DBREF_COUNT(pp);
|
INIT_DBREF_COUNT(pp);
|
||||||
|
@ -1328,7 +1328,7 @@ CreateDBStruct(Term Tm, DBProp p, int InFlag)
|
||||||
dbr->NOfRefsTo++;
|
dbr->NOfRefsTo++;
|
||||||
pp->Contents[0] = (CELL)NIL;
|
pp->Contents[0] = (CELL)NIL;
|
||||||
pp->Contents[1] = (CELL)dbr;
|
pp->Contents[1] = (CELL)dbr;
|
||||||
pp->u.DBRefs = (DBRef *)(pp->Contents+2);
|
pp->DBRefs = (DBRef *)(pp->Contents+2);
|
||||||
INIT_LOCK(pp->lock);
|
INIT_LOCK(pp->lock);
|
||||||
INIT_DBREF_COUNT(pp);
|
INIT_DBREF_COUNT(pp);
|
||||||
Yap_ReleasePreAllocCodeSpace((ADDR)pp0);
|
Yap_ReleasePreAllocCodeSpace((ADDR)pp0);
|
||||||
|
@ -1512,9 +1512,9 @@ CreateDBStruct(Term Tm, DBProp p, int InFlag)
|
||||||
*rfnar++ = NULL;
|
*rfnar++ = NULL;
|
||||||
while (ptr != tofref)
|
while (ptr != tofref)
|
||||||
*rfnar++ = *--ptr;
|
*rfnar++ = *--ptr;
|
||||||
pp->u.DBRefs = rfnar;
|
pp->DBRefs = rfnar;
|
||||||
} else {
|
} else {
|
||||||
pp->u.DBRefs = NULL;
|
pp->DBRefs = NULL;
|
||||||
}
|
}
|
||||||
Yap_ReleasePreAllocCodeSpace((ADDR)pp0);
|
Yap_ReleasePreAllocCodeSpace((ADDR)pp0);
|
||||||
return (pp);
|
return (pp);
|
||||||
|
@ -1528,7 +1528,7 @@ new_lu_index(LogUpdDBProp AtProp) {
|
||||||
DBRef ref = AtProp->First;
|
DBRef ref = AtProp->First;
|
||||||
DBRef *te;
|
DBRef *te;
|
||||||
|
|
||||||
if (index == NIL) {
|
if (index == NULL) {
|
||||||
DBErrorFlag = OTHER_ERROR_IN_DB;
|
DBErrorFlag = OTHER_ERROR_IN_DB;
|
||||||
DBErrorNumber = SYSTEM_ERROR;
|
DBErrorNumber = SYSTEM_ERROR;
|
||||||
DBErrorTerm = TermNil;
|
DBErrorTerm = TermNil;
|
||||||
|
@ -1632,7 +1632,7 @@ record(int Flag, Term key, Term t_data, Term t_code)
|
||||||
p->Last = x;
|
p->Last = x;
|
||||||
}
|
}
|
||||||
if (Flag & WithRef) {
|
if (Flag & WithRef) {
|
||||||
x->u.Code = (yamop *) IntegerOfTerm(t_code);
|
x->Code = (yamop *) IntegerOfTerm(t_code);
|
||||||
}
|
}
|
||||||
WRITE_UNLOCK(p->DBRWLock);
|
WRITE_UNLOCK(p->DBRWLock);
|
||||||
return (x);
|
return (x);
|
||||||
|
@ -1721,7 +1721,7 @@ record_at(int Flag, DBRef r0, Term t_data, Term t_code)
|
||||||
r0->Next = x;
|
r0->Next = x;
|
||||||
}
|
}
|
||||||
if (Flag & WithRef) {
|
if (Flag & WithRef) {
|
||||||
x->u.Code = (yamop *) IntegerOfTerm(t_code);
|
x->Code = (yamop *) IntegerOfTerm(t_code);
|
||||||
}
|
}
|
||||||
WRITE_UNLOCK(p->DBRWLock);
|
WRITE_UNLOCK(p->DBRWLock);
|
||||||
return (x);
|
return (x);
|
||||||
|
@ -3472,7 +3472,7 @@ ErasePendingRefs(DBRef entryref)
|
||||||
|
|
||||||
if (!(entryref->Flags & DBWithRefs))
|
if (!(entryref->Flags & DBWithRefs))
|
||||||
return;
|
return;
|
||||||
cp = CellPtr(entryref->u.DBRefs);
|
cp = CellPtr(entryref->DBRefs);
|
||||||
while ((ref = (DBRef)(*--cp)) != NULL) {
|
while ((ref = (DBRef)(*--cp)) != NULL) {
|
||||||
if ((ref->Flags & DBClMask) && (--(ref->NOfRefsTo) == 0)
|
if ((ref->Flags & DBClMask) && (--(ref->NOfRefsTo) == 0)
|
||||||
&& (ref->Flags & ErasedMask))
|
&& (ref->Flags & ErasedMask))
|
||||||
|
@ -3581,7 +3581,7 @@ find_next_clause(DBRef ref0)
|
||||||
/* OK, we found a clause we can jump to, do a bit of hanky pancking with
|
/* OK, we found a clause we can jump to, do a bit of hanky pancking with
|
||||||
the choice-point, so that it believes we are actually working from that
|
the choice-point, so that it believes we are actually working from that
|
||||||
clause */
|
clause */
|
||||||
newp = ref->u.Code;
|
newp = ref->Code;
|
||||||
/* and next let's tell the world this clause is being used, just
|
/* and next let's tell the world this clause is being used, just
|
||||||
like if we were executing a standard retry_and_mark */
|
like if we were executing a standard retry_and_mark */
|
||||||
#if defined(YAPOR) || defined(THREADS)
|
#if defined(YAPOR) || defined(THREADS)
|
||||||
|
@ -3703,7 +3703,7 @@ PrepareToEraseLogUpdClause(Clause *clau, DBRef dbr)
|
||||||
WRITE_LOCK(p->PRWLock);
|
WRITE_LOCK(p->PRWLock);
|
||||||
if (p->cs.p_code.FirstClause != cl) {
|
if (p->cs.p_code.FirstClause != cl) {
|
||||||
/* we are not the first clause... */
|
/* we are not the first clause... */
|
||||||
yamop *prev_code_p = (yamop *)(dbr->Prev->u.Code);
|
yamop *prev_code_p = (yamop *)(dbr->Prev->Code);
|
||||||
prev_code_p->u.ld.d = code_p->u.ld.d;
|
prev_code_p->u.ld.d = code_p->u.ld.d;
|
||||||
/* are we the last? */
|
/* are we the last? */
|
||||||
if (p->cs.p_code.LastClause == cl)
|
if (p->cs.p_code.LastClause == cl)
|
||||||
|
@ -3718,7 +3718,7 @@ PrepareToEraseLogUpdClause(Clause *clau, DBRef dbr)
|
||||||
Yap_opcode(TRYCODE(_try_me, _try_me0, p->ArityOfPE));
|
Yap_opcode(TRYCODE(_try_me, _try_me0, p->ArityOfPE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbr->u.Code = NULL; /* unlink the two now */
|
dbr->Code = NULL; /* unlink the two now */
|
||||||
if (p->PredFlags & IndexedPredFlag) {
|
if (p->PredFlags & IndexedPredFlag) {
|
||||||
Yap_RemoveIndexation(p);
|
Yap_RemoveIndexation(p);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3845,8 +3845,8 @@ static void
|
||||||
ErDBE(DBRef entryref)
|
ErDBE(DBRef entryref)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ((entryref->Flags & DBCode) && entryref->u.Code) {
|
if ((entryref->Flags & DBCode) && entryref->Code) {
|
||||||
Clause *clau = ClauseCodeToClause(entryref->u.Code);
|
Clause *clau = ClauseCodeToClause(entryref->Code);
|
||||||
LOCK(clau->ClLock);
|
LOCK(clau->ClLock);
|
||||||
if (CL_IN_USE(clau) || entryref->NOfRefsTo != 0) {
|
if (CL_IN_USE(clau) || entryref->NOfRefsTo != 0) {
|
||||||
PrepareToEraseClause(clau, entryref);
|
PrepareToEraseClause(clau, entryref);
|
||||||
|
@ -3908,8 +3908,8 @@ EraseEntry(DBRef entryref)
|
||||||
entryref->Next = NIL;
|
entryref->Next = NIL;
|
||||||
if (!DBREF_IN_USE(entryref)) {
|
if (!DBREF_IN_USE(entryref)) {
|
||||||
ErDBE(entryref);
|
ErDBE(entryref);
|
||||||
} else if ((entryref->Flags & DBCode) && entryref->u.Code) {
|
} else if ((entryref->Flags & DBCode) && entryref->Code) {
|
||||||
PrepareToEraseClause(ClauseCodeToClause(entryref->u.Code), entryref);
|
PrepareToEraseClause(ClauseCodeToClause(entryref->Code), entryref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4357,7 +4357,7 @@ keepdbrefs(DBRef entryref)
|
||||||
|
|
||||||
if (!(entryref->Flags & DBWithRefs))
|
if (!(entryref->Flags & DBWithRefs))
|
||||||
return;
|
return;
|
||||||
cp = entryref->u.DBRefs;
|
cp = entryref->DBRefs;
|
||||||
while ((ref = *--cp) != NIL) {
|
while ((ref = *--cp) != NIL) {
|
||||||
LOCK(ref->lock);
|
LOCK(ref->lock);
|
||||||
if(!(ref->Flags & InUseMask)) {
|
if(!(ref->Flags & InUseMask)) {
|
||||||
|
|
32
C/heapgc.c
32
C/heapgc.c
|
@ -1135,15 +1135,23 @@ mark_environments(CELL_PTR gc_ENV, OPREG size, CELL *pvbmap)
|
||||||
int tsize = size - EnvSizeInCells;
|
int tsize = size - EnvSizeInCells;
|
||||||
|
|
||||||
currv = sizeof(CELL)*8-tsize%(sizeof(CELL)*8);
|
currv = sizeof(CELL)*8-tsize%(sizeof(CELL)*8);
|
||||||
pvbmap += tsize/(sizeof(CELL)*8);
|
if (pvbmap != NULL) {
|
||||||
bmap = *pvbmap;
|
pvbmap += tsize/(sizeof(CELL)*8);
|
||||||
|
bmap = *pvbmap;
|
||||||
|
} else {
|
||||||
|
bmap = -1L;
|
||||||
|
}
|
||||||
bmap = (Int)(((CELL)bmap) << currv);
|
bmap = (Int)(((CELL)bmap) << currv);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (saved_var = gc_ENV - size; saved_var < gc_ENV - EnvSizeInCells; saved_var++) {
|
for (saved_var = gc_ENV - size; saved_var < gc_ENV - EnvSizeInCells; saved_var++) {
|
||||||
if (currv == sizeof(CELL)*8) {
|
if (currv == sizeof(CELL)*8) {
|
||||||
pvbmap--;
|
if (pvbmap) {
|
||||||
bmap = *pvbmap;
|
pvbmap--;
|
||||||
|
bmap = *pvbmap;
|
||||||
|
} else {
|
||||||
|
bmap = -1L;
|
||||||
|
}
|
||||||
currv = 0;
|
currv = 0;
|
||||||
}
|
}
|
||||||
/* we may have already been here */
|
/* we may have already been here */
|
||||||
|
@ -2087,15 +2095,23 @@ sweep_environments(CELL_PTR gc_ENV, OPREG size, CELL *pvbmap)
|
||||||
|
|
||||||
|
|
||||||
currv = sizeof(CELL)*8-tsize%(sizeof(CELL)*8);
|
currv = sizeof(CELL)*8-tsize%(sizeof(CELL)*8);
|
||||||
pvbmap += tsize/(sizeof(CELL)*8);
|
if (pvbmap != NULL) {
|
||||||
bmap = *pvbmap;
|
pvbmap += tsize/(sizeof(CELL)*8);
|
||||||
|
bmap = *pvbmap;
|
||||||
|
} else {
|
||||||
|
bmap = -1L;
|
||||||
|
}
|
||||||
bmap = (Int)(((CELL)bmap) << currv);
|
bmap = (Int)(((CELL)bmap) << currv);
|
||||||
}
|
}
|
||||||
for (saved_var = gc_ENV - size; saved_var < gc_ENV - EnvSizeInCells; saved_var++) {
|
for (saved_var = gc_ENV - size; saved_var < gc_ENV - EnvSizeInCells; saved_var++) {
|
||||||
|
|
||||||
if (currv == sizeof(CELL)*8) {
|
if (currv == sizeof(CELL)*8) {
|
||||||
pvbmap--;
|
if (pvbmap != NULL) {
|
||||||
bmap = *pvbmap;
|
pvbmap--;
|
||||||
|
bmap = *pvbmap;
|
||||||
|
} else {
|
||||||
|
bmap = -1L;
|
||||||
|
}
|
||||||
currv = 0;
|
currv = 0;
|
||||||
}
|
}
|
||||||
if (bmap < 0) {
|
if (bmap < 0) {
|
||||||
|
|
3
C/init.c
3
C/init.c
|
@ -984,7 +984,8 @@ InitCodes(void)
|
||||||
(DBRef)Yap_AllocCodeSpace(sizeof(DBStruct));
|
(DBRef)Yap_AllocCodeSpace(sizeof(DBStruct));
|
||||||
heap_regs->db_erased_marker->id = FunctorDBRef;
|
heap_regs->db_erased_marker->id = FunctorDBRef;
|
||||||
heap_regs->db_erased_marker->Flags = ErasedMask;
|
heap_regs->db_erased_marker->Flags = ErasedMask;
|
||||||
heap_regs->db_erased_marker->u.Code = NULL;
|
heap_regs->db_erased_marker->Code = NULL;
|
||||||
|
heap_regs->db_erased_marker->DBRefs = NULL;
|
||||||
heap_regs->db_erased_marker->Parent = NULL;
|
heap_regs->db_erased_marker->Parent = NULL;
|
||||||
INIT_LOCK(heap_regs->db_erased_marker->lock);
|
INIT_LOCK(heap_regs->db_erased_marker->lock);
|
||||||
INIT_DBREF_COUNT(heap_regs->db_erased_marker);
|
INIT_DBREF_COUNT(heap_regs->db_erased_marker);
|
||||||
|
|
|
@ -1017,7 +1017,11 @@ SearchForTrailFault(void)
|
||||||
#if OS_HANDLES_TR_OVERFLOW
|
#if OS_HANDLES_TR_OVERFLOW
|
||||||
if ((TR > (tr_fr_ptr)Yap_TrailTop-1024 &&
|
if ((TR > (tr_fr_ptr)Yap_TrailTop-1024 &&
|
||||||
TR < (tr_fr_ptr)Yap_TrailTop+(64*1024))|| Yap_DBTrailOverflow()) {
|
TR < (tr_fr_ptr)Yap_TrailTop+(64*1024))|| Yap_DBTrailOverflow()) {
|
||||||
if (!Yap_growtrail(64 * 1024L)) {
|
long trsize = 64*2014L;
|
||||||
|
while (trsize < ((CELL)TR-(CELL)Yap_TrailTop)) {
|
||||||
|
trsize += 64*2014L;
|
||||||
|
}
|
||||||
|
if (!Yap_growtrail(trsize)) {
|
||||||
Yap_Error(SYSTEM_ERROR, TermNil, "YAP failed to reserve %ld bytes in growtrail", 64*1024L);
|
Yap_Error(SYSTEM_ERROR, TermNil, "YAP failed to reserve %ld bytes in growtrail", 64*1024L);
|
||||||
}
|
}
|
||||||
/* just in case, make sure the OS keeps the signal handler. */
|
/* just in case, make sure the OS keeps the signal handler. */
|
||||||
|
|
21
H/rheap.h
21
H/rheap.h
|
@ -470,19 +470,16 @@ RestoreDBEntry(DBRef dbr)
|
||||||
YP_fprintf(errout, " a var\n");
|
YP_fprintf(errout, " a var\n");
|
||||||
#endif
|
#endif
|
||||||
dbr->Parent = (DBProp)AddrAdjust((ADDR)(dbr->Parent));
|
dbr->Parent = (DBProp)AddrAdjust((ADDR)(dbr->Parent));
|
||||||
if (dbr->Flags & DBCode) {
|
if (dbr->Code != NULL)
|
||||||
if (dbr->u.Code != NULL)
|
dbr->Code = PtoOpAdjust(dbr->Code);
|
||||||
dbr->u.Code = PtoOpAdjust(dbr->u.Code);
|
if (dbr->Flags & DBWithRefs) {
|
||||||
} else {
|
DBRef *cp;
|
||||||
if (dbr->Flags & DBWithRefs) {
|
DBRef tm;
|
||||||
DBRef *cp;
|
|
||||||
DBRef tm;
|
|
||||||
|
|
||||||
dbr->u.DBRefs = DBRefPAdjust(dbr->u.DBRefs);
|
dbr->DBRefs = DBRefPAdjust(dbr->DBRefs);
|
||||||
cp = dbr->u.DBRefs;
|
cp = dbr->DBRefs;
|
||||||
while ((tm = *--cp) != 0)
|
while ((tm = *--cp) != 0)
|
||||||
*cp = DBRefAdjust(tm);
|
*cp = DBRefAdjust(tm);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (dbr->Flags & DBAtomic) {
|
if (dbr->Flags & DBAtomic) {
|
||||||
if (IsAtomTerm(dbr->Entry))
|
if (IsAtomTerm(dbr->Entry))
|
||||||
|
|
|
@ -268,10 +268,8 @@ typedef struct DB_STRUCT {
|
||||||
CELL Flags; /* Term Flags */
|
CELL Flags; /* Term Flags */
|
||||||
CELL NOfRefsTo; /* Number of references pointing here */
|
CELL NOfRefsTo; /* Number of references pointing here */
|
||||||
struct struct_dbentry *Parent; /* key of DBase reference */
|
struct struct_dbentry *Parent; /* key of DBase reference */
|
||||||
union {
|
struct yami *Code; /* pointer to code if this is a clause */
|
||||||
struct yami *Code; /* pointer to code if this is a clause */
|
struct DB_STRUCT **DBRefs; /* pointer to other references */
|
||||||
struct DB_STRUCT **DBRefs; /* pointer to other references */
|
|
||||||
} u;
|
|
||||||
struct DB_STRUCT *Prev; /* Previous element in chain */
|
struct DB_STRUCT *Prev; /* Previous element in chain */
|
||||||
struct DB_STRUCT *Next; /* Next element in chain */
|
struct DB_STRUCT *Next; /* Next element in chain */
|
||||||
#if defined(YAPOR) || defined(THREADS)
|
#if defined(YAPOR) || defined(THREADS)
|
||||||
|
|
|
@ -131,6 +131,7 @@ yap_flag(gc,V) :-
|
||||||
( '$get_value'('$gc',[]) -> V = off ; V = on).
|
( '$get_value'('$gc',[]) -> V = off ; V = on).
|
||||||
yap_flag(gc,on) :- !, '$set_value'('$gc',true).
|
yap_flag(gc,on) :- !, '$set_value'('$gc',true).
|
||||||
yap_flag(gc,off) :- !, '$set_value'('$gc',[]).
|
yap_flag(gc,off) :- !, '$set_value'('$gc',[]).
|
||||||
|
|
||||||
yap_flag(gc_margin,N) :-
|
yap_flag(gc_margin,N) :-
|
||||||
var(N) ->
|
var(N) ->
|
||||||
'$get_value'('$gc_margin',N)
|
'$get_value'('$gc_margin',N)
|
||||||
|
@ -616,7 +617,7 @@ yap_flag(host_type,X) :-
|
||||||
|
|
||||||
'$transl_to_character_escape_modes'(0,off) :- !.
|
'$transl_to_character_escape_modes'(0,off) :- !.
|
||||||
'$transl_to_character_escape_modes'(0,cprolog).
|
'$transl_to_character_escape_modes'(0,cprolog).
|
||||||
'$transl_to_character_escape_modes'(1,on) :- !.
|
'$transl_to_character_escape_modes'(2,on) :- !.
|
||||||
'$transl_to_character_escape_modes'(1,iso).
|
'$transl_to_character_escape_modes'(1,iso).
|
||||||
'$transl_to_character_escape_modes'(2,sicstus).
|
'$transl_to_character_escape_modes'(2,sicstus).
|
||||||
|
|
||||||
|
|
12
pl/init.yap
12
pl/init.yap
|
@ -27,12 +27,12 @@ false :- fail.
|
||||||
(:- G) :- '$execute'(G), !.
|
(:- G) :- '$execute'(G), !.
|
||||||
'$$!'(CP) :- '$cut_by'(CP).
|
'$$!'(CP) :- '$cut_by'(CP).
|
||||||
[] :- true.
|
[] :- true.
|
||||||
','(A,B) :- '$meta_call'((A,B),prolog).
|
','(A,B) :- '$current_module'(Module), '$meta_call'((A,B),Module).
|
||||||
';'(A,B) :- '$meta_call'((A;B),prolog).
|
';'(A,B) :- '$current_module'(Module), '$meta_call'((A;B),Module).
|
||||||
'|'(A,B) :- '$meta_call'((A;B),prolog).
|
'|'(A,B) :- '$current_module'(Module), '$meta_call'((A;B),Module).
|
||||||
'->'(A,B) :- '$meta_call'((A->B),prolog).
|
'->'(A,B) :- '$current_module'(Module), '$meta_call'((A->B),Module).
|
||||||
\+(G) :- '$meta_call'(\+(G),prolog).
|
\+(G) :- '$current_module'(Module), '$meta_call'(\+(G),Module).
|
||||||
not(G) :- '$meta_call'(not(G),prolog).
|
not(G) :- '$current_module'(Module), '$meta_call'(not(G),Module).
|
||||||
|
|
||||||
|
|
||||||
:- '$set_value'('$doindex',true).
|
:- '$set_value'('$doindex',true).
|
||||||
|
|
Reference in New Issue