• No results found

The following macros are used in various parts of the machine. The main reason for using macros is that we get a program where it is easy to change representation as well as functionality. The other reason is that we get safer code, we only have to change the code once instead of changing the code at every place the macro is used.

ArityOf(F) (term.h)

Returns the arity of the functor F.

((int) (((F) & ARITYMASK) >> ARITYOFFSET)) Arityfy(N,A) (term.h)

Returns a functor with the name N (a TAGGED atom) and the arity A (untagged integer).

(((u32)(N)) | (((u32)(A)) << ARITYOFFSET)) Bind(V,VAL,FAILCODE) (bind.h)

Bind the variable V to VAL, trail if necessary. In the sequential version FAILCODE is ignored, in the parallel version FAILCODE is executed if V cannot be bound because another processor has bound V. This can only happen with heap variables (HVA) since stack variables are not shared.

{ register TAGGED EVALED_V = (V);

register TAGGED EVALED_VAL = (VAL);

if (IsHVA(EVALED_V))

{ Bind_HVA(EVALED_V,EVALED_VAL,FAILCODE);

else}

{ Bind_SVA(EVALED_V,EVALED_VAL);

} }

Bind_HVA(V,VAL,FAILCODE) (bind.h)

Bind the heap variable V to VAL, trail if necessary. In the sequential version FAIL-CODE is ignored, in the parallel version FAILFAIL-CODE is executed if V cannot be bound because another processor has bound V.

#ifdef PARALLEL

{ register TAGGED EVALED_V = (V),

BH_T;

Swap_Bind(OffsetBase(EVALED_V), EVALED_V, VAL, BH_T,

Trail_HVA(EVALED_V,BH_T), FAILCODE);

}#else

{ Trail_HVA(V);

*((TAGGED *) OffsetBase(V)) = (VAL);

}#endif

Bind_SVA(V,VAL) (bind.h)

Bind the stack variable V to VAL, trail if necessary.

{ Trail_SVA(V);

*(RemoveTag(V,SVA)) = (VAL);

}

CreateHVA(S,W) (storage.h)

Creates an unbound heap variable on the location given by S.

{#ifdef UNBOUND

register TAGGED dummy;

InitHVA(S,dummy,W);

#else

InitHVA(S,*S,W);

#endif

(S) += VARSIZE;

}

Deref(Xderefed,X) (deref.h)

Puts the dereferenced value of X in Xderefed. In the presence of unbound tagged variables (UVA) Xderefed should be bound to a pointer to the unbound variable instead of the UVA tagged object. The reason for this is that we need to know the location of the variable in order to bind it.

#ifdef UNBOUND

{ register TAGGED v, vp;

v = (X);

while(TRUE) { if(IsVar(v))

{ RefVAR(vp,v);

if((v != vp) && (!IsUVA(vp))) { v = vp;

continue;

} } break;

}

Xderefed = v;

}#else

{ register TAGGED v, vp;

v = (X);

if(IsVar(v))

do {RefVAR(vp,v);

} while(v != vp && IsVar(v = vp));

Xderefed = v;

}#endif

DerefHVA(Xderefed,X) (deref.h)

Puts the dereferenced value of the heap term X in Xderefed. In the presence of unbound tagged variables (UVA) Xderefed should be bound to a pointer to the unbound variable instead of the UVA tagged object. The reason for this is that we need to know the location of the variable in order to bind it.

#ifdef UNBOUND

{ register TAGGED v, vp;

v = (X);

while(TRUE) { if(IsHVA(v))

{ RefHVA(vp,v);

if(!IsUVA(vp)) { v = vp;

continue;

} } break;

}

Xderefed = v;

}#else

{ register TAGGED v, vp;

v = (X);

if(IsVar(v))

do {RefHVA(vp,v);

} while(v != vp && IsHVA(v = vp));

Xderefed = v;

}#endif

Dispatch(PC,O set) (engine.h)

Increment PC by the value found at o set O set from PC. If the label at O set is NULL, we should fail.

{ register int p1 = *(PC + O set);

if(p1 == NULL) goto fail;

elsePC = ((code *) (((int) PC) + p1)) + O;

}

DispatchLabel(PC,O set) (engine.h)

Increments PC by the value found at the o set O set from PC. No check of NULL is needed.

(((code *) (((int) PC) + ((int) *(PC+O set)))) + O set)

DispatchUp(K) (engine.h)

Pops an old S (structure read/write) pointer from then deep uni cation stack and continues in write mode if there are more structures to write (K > 0), in read mode otherwise.

{ S = PopCont;

if((K) > 0)

goto write_start;

elsegoto read_start;

} GetArg(S,I) (term.h)

Returns a pointer the Ith argument to the structure pointed to by the TAGGED pointer S. (&(((structure) RemoveTag(S,STR))->arg[(I)*VARSIZE]))

GetArity(S) (term.h)

Returns the arity of the structure pointed to by S.

(ArityOf(GetFunctor(S)))

GetCar(L) (term.h)

Returns a pointer to the rst argument of the list cell pointed to by the TAGGED pointer L.

TagToPointer(L)

GetCdr(L) (term.h)

Returns a pointer to the second argument of the list cell pointed to by the TAGGED pointer L.

(TagToPointer(L)+VARSIZE)

GetFunctor(S) (term.h)

Returns the functor of the structure pointed to by S.

(((structure) RemoveTag(S,STR))->functor) GetInlineArity(F) (inline.h)

Returns the arity of the inlineable predicate numbered F.

inline_table[F].arity

GetInlineFnk(F) (inline.h)

Returns a pointer to the C function that de nes the inlineable predicate F.

inline_table[F].fnk

GetMethod(M,G) (term.h)

Returns a pointer to the C function that executes the method M on the generic object G.

(((generic) RemoveTag(G,GEN))->method->M)

GetNumber(N) (term.h)

Returns the number stored in the TAGGED object N.

((int) (((int) ((N) << GCBITS)) >> (TAGBITS+GCBITS))) Get_Local_Stack_Top (engine.h)

Returns a pointer to the top of the local stack.

Get_Stack_Top(FrameSize(w->next_instr)) Get_Stack_Top(S) (engine.h)

Returns a pointer to the top of the local stack given the size of the current environment.

( ((choicepoint *) w->frame) > w->choice ? EnvTop(w->frame,S) :

CpTop(w->choice) )

Get_UseArgs(PC) (engine.h)

Returns a pointer of arguments to use when calling inlineable predicates.

(TAGGED *) (PC)

InitCont (engine.h)

Initializes the push down stack used when doing open coded deep uni cation.

{ cont = w->rdstack;

} IsATM(T) (term.h)

Returns TRUE if the term T is an atom, FALSE otherwise.

IsHVA(T) (term.h)

Returns TRUE if the term T is a heap variable, FALSE otherwise.

IsLST(T) (term.h)

Returns TRUE if the term T is a list, FALSE otherwise.

IsNumber(T) (term.h)

Returns TRUE if the term T is a number ( oat or integer), FALSE otherwise.

IsSTR(T) (term.h)

Returns TRUE if the term T is a structure, FALSE otherwise.

IsUnsafe(V) (unify.h)

This is true i the stack variable X is in the current environment.

(((environment *) RemoveTag(V,SVA)) > w->frame) IsVar(T) (term.h)

Return TRUE if the term T is a variable (stack or heap), FALSE otherwise.

LoadHVA(S,V,W) (storage.h)

Creates an unbound heap variable at S and store a pointer in V.

{ InitHVA(S,V,W);

(S) += VARSIZE;

}

LoadSVA(V) (storage.h)

This initializes the stack variable V.

{ V = Tagify((TAGGED) &(V),SVA);

}

Make_LST(H,To) (storage.h)

Creates a list cell at H and stores a pointer to it in To.

{ To = Tagify(H,LST);

}

Make_LST_S(H,S,To) (storage.h)

Creates a list cell at H and stores a pointer to the rst argument in S and a tagged pointer in To.

{ To = Tagify(H,LST);

S = H;

H += 2*VARSIZE;

}

Make_STR(H,To,F) (storage.h)

Creates a structure at H with functor F and saves a TAGGED pointer to it in To.

{ S = Tagify(H,STR);

PushOnHeap(H,F);

}

Make_STR_S(H,S,To,F) (storage.h)

Creates a structure at H with functor F and sets S to point to the rst argument of the structure, and To to a tagged pointer to the structure.

{ To = Tagify(H,STR);

PushOnHeap(H,F);

S = H;

H += ArityOf(F)*VARSIZE;

}

PointerToTerm(T) (term.h)

Returns a tagged pointer where the value eld is T.

Tagify(T,NUM) PopCont (engine.h)

Returns a pointer to the structure argument to continue the uni cation with. Used when doing deep uni cation with the new schema.

((TAGGED *) (*(--cont))) PushCont(C) (engine.h)

Saves a pointer to a structure argument C to continue the uni cation with when we have uni ed the current argument depth rst.

{ *(cont++) = (TAGGED) (C);

}

PushOnHeap(H,T) (storage.h)

Push the term T on the heap at location H.

{ *(H) = (T);

*(H)++;

} RefHVA(To,X) (unify.h)

Sets To to the value X points to.

To = *Var(OffsetBase(X))

RefStackUnsafe(H,To,X) (unify.h)

Stores the contents of X into the contents of To, unless X dereferences into the current environment, in which case it is bound to a new global variable created at H.

{ register TAGGED tmp1;

Deref(tmp1,X);

if(IsSVA(tmp1) && IsUnsafe(tmp1)) { LoadHVA(H,To);

SetVar(tmp1, To);

} else {

To = tmp1;

} }

RefVar(To,X) (unify.h)

Sets To to the value X points to.

To = *TagToPointer(X)

Tagify(P,T) (term.h)

Creates a prolog term with value eld P and tag T.

((TAGGED) (BaseOffset((u32) (P)) | (((u32) (T)) << TAGOFFSET))) Tagof(T) (term.h)

Returns the tag of T.

((tagvalue)(((u32)(T))>>TAGOFFSET)) TagToPointer(T) (term.h)

Returns the value eld of the prolog term T.

((TAGGED *) OffsetBase(((u32) POINTMASK)&((u32) (T))))

TidyTrail (trail.h)

Remove unnecessary trail entries. This necessary since the garbage collector imple-ments early reset.

{ register TAGGED *stop = w->choice->trail_top;

register TAGGED *curr = w->trail_top;

register TAGGED *dest = curr;

register TAGGED *stacklim = (TAGGED *)

EnvTop(w->choice->cont_env,FrameSize(w->choice->next_instr));

DeclareUncond(heaplim,w->choice->global_top,w->choice->timestamp);

/* sweep trail */

while(curr > stop) { curr--;

switch(TagOf(*curr)) {case HVA:

TidyHVA(curr,heaplim);

break;

case SVA:

TidySVA(curr,stacklim);

break;

case NUM:

break;

case LST:

TidyValue(curr,heaplim);

break;

case STR:

TidyWorkers(curr);

break;

case GEN:

default:

} }

stop = w->trail_top;

curr = w->choice->trail_top;

dest = w->choice->trail_top;

/* compact trail */

while(curr < stop) { if(*curr == 0)

{ curr++;

else}

{ *dest = *curr;

curr++;

dest++;

} }

w->trail_top = dest;

}

Trail_HVA(V,T) (trail.h)

Trail the value of V if necessary.

{#ifdef UNBOUND

{ if(GetHVATime(T) < w->uncond) { PushOnTrail(w->trail_top, T);

PushOnTrail(w->trail_top, V);

} }

#else

{ if(GetHVATime(V) < w->uncond) PushOnTrail(w->trail_top, V);

}#endif

Trail_SVA(V) (trail.h)

Trail the value of the stack variable if it is conditional.

{ if(GetSVATime(V) < (TAGGED *) w->choice) PushOnTrail(w->trail_top, V);

} UnBind_HVA(V) (trail.h)

Makes the heap variable V unconditional.

#ifdef UNBOUND

{ *((TAGGED *) OffsetBase(*V)) = *(V-1);

(V)--;

}#else

*((TAGGED *) OffsetBase(*V)) = (*V)

#endif

UnBind_SVA(V) (trail.h)

Makes the stack variable V unconditional.

*((TAGGED *) RemoveTag(*V,SVA)) = (*V)

UndoValue(T) (trail.h)

Restores the term *T to its previous value saved on the trail.

{ *TagToPointer(*T) = *(T-1);

(T)--;

}

Unify(X,Y) (unify.h)

The general uni cation algorithm is applied to X and Y. If it fails, backtracking is trigged.

{ register TAGGED tmp1,tmp2;

Deref(tmp1,X); Deref(tmp2,Y);

if(!unify(tmp1,tmp2,w)) goto fail;

}

Unwind_Trail(T) (trail.h)

All bindings recorde on the trail are undone. Entries tagged with NUM store a saved heap top value. This is used by the parallel workers to restore the heap top when backtracking. Entries tagged LST are value entries. The following value contains the old value of the heap cell. Entries tagged STR indicate that a parallel execution occured at this point in the computation, the sequential worker tells the parallel workers to backtrack until they nd a NUM tagged cell on their respective trails.

{ register TAGGED *stop = (T);

while(w->trail_top > stop) { w->trail_top--;

switch(TagOf(*(w->trail_top))) {case HVA:

UnBind_HVA(w->trail_top);

break;

case SVA:

UnBind_SVA(w->trail_top);

break;

case NUM: /* Only on workers, ignore here */

break;

case LST:

UndoValue(w->trail_top);

break;

case STR: /* Only in Parallel */

UnwindWorkers;

break;

case GEN:

GetMethod(undo,*(w->trail_top))(*(w->trail_top));

break;

default:

UnBind_SVA(w->trail_top);

} } }

Worker_Unwind_Trail()

Same as Unwind Trail exept this version is used by sleeping workers. SVA entries can be skipped since all environments have been deallocated.

{ register TAGGED *stop = w->trail_start;

while(w->trail_top > stop) { w->trail_top--;

switch(TagOf(*(w->trail_top))) {case HVA:

UnBind_HVA(w->trail_top);

break;

case SVA:

break;

case NUM: /* Only on parallel workers */

stop = w->trail_top;

w->heap_top = TagToPointer(*(w->trail_top));

break;

case LST:

UndoValue(w->trail_top);

break;

case GEN:

GetMethod(undo,*(w->trail_top))(*(w->trail_top));

break;

default:

UnBind_SVA(w->trail_top);

} } } WriteLocalValue(S,X)

Stores X on the heap at S, binding it to a new global variable if necessary.

{ register TAGGED tmp1,tmp2;

Deref(tmp1,X);

if(IsSVA(tmp1)) { LoadHVA(S,tmp2);

SetVar(tmp1,tmp2);

} else {

*(S) = tmp1; (S) += VARSIZE;

} }

6 BuiltinC Predicates

There are two kinds of builtin predicates: normal and inlineable. A normal predicate is called like any other predicate and behaves like any prolog de ned predicate. An inlineable predicate, on the other hand, is called by the WAM instruction builtin. The main di erence between normal and inlineable predicates are that an inlineable predicate preserve registers while a normal don't.

The tables in this chapter are not complete, there are a number of predicates in the emulator not listed.

Related documents