home *** CD-ROM | disk | FTP | other *** search
- #include "Kernel/h/system.h"
- #include "Kernel/h/assert.h"
- #include "Kernel/h/map.h"
- #include "Kernel/h/mmMsgTypes.h"
- #include "Kernel/h/emTypes.h"
- #include "Kernel/h/kmdTypes.h"
- #include "Kernel/h/builtins.h"
- #include "Kernel/h/emkDefs.h"
- #include "Kernel/h/utils.h"
-
- extern SSPtr preemptRunning();
- extern void fail(), schedule();
- extern Boolean LoadRequest();
- extern ODP OTLookup();
- extern AbConPtr OIDOIDOIDToAbCon();
-
- extern char *PPSSPlace(), *PPPOID(), *PPGOID(), *PPOID(), *PPCOID(),
- *PPCodePtr(), *PPFindLineNo();
-
- /*
- * The function conforms takes two abstract type OIDS
- * and determines whether they conform or not. The abstract types are
- * represented
- * by strings (to save space). The format of the strings are:
- *
- * AT ::= CannotBCT IsVector Immutable { operation }
- * CannotBCT ::= ( 'Y' | 'N' )
- * IsVector ::= ( 'Y' | 'N' )
- * Immutable ::= ( 'Y' | 'N' )
- * operation ::= ( 'O' | 'F' ) 'O' 8hexdigits param -> param
- * param ::= '[' [ type { ',' type } ] ']'
- * type ::= 'S' | 'O' 8hexdigits
- */
-
- /*
- * The algorithm is as follows:
- * if we know that at1 conforms to at2, then return TRUE
- * else
- * 1. assume that at1 *> at2.
- * 2. for each operation (o2) in at2
- * a. if no identically named operation exitsts in at1 then retract
- * the assumption and return false.
- * b. if numparams or numresults do not match then retract the
- * assumption and return FALSE.
- * c. for each param(p1, p2),
- * * note that parameters must conform in the backwards
- * direction.
- * i. if p1 *> p2 then continue.
- * ii. else retract the assumption and return FALSE.
- * c. for each result(r1, r2),
- * i. if r2 *> r1 then continue
- * ii. else retract the assumption and return FALSE.
- * d. return true (having proved our current assumption that
- * t1 *> t2)
- *
- * The algorithm for conformity between anything and a type variable is
- * exactly the same, except that at the
- * assumption stage we identify at1 and at2, that is we say that they conform
- * in both directions. When we retract the assumption we must remember to
- * invalidate in both directions.
- */
-
- typedef struct {
- Boolean hasValue : 16;
- Boolean value : 16;
- OID missingAT;
- } ConformsResult;
-
- void ConformInit()
- {
- KMDSetTrace(Conform);
- }
-
- typedef enum { IDENTICAL, CONFORMS, NOTCONFORMS } Relationship;
- #define opnameSame(p, q) (!strncmp((p)+2, (q)+2, 8))
- #define paramsOf(p) ((p)+10)
- #define opsOf(p) ((p) + 1+1+1)
-
- char *resultsOf(p)
- register char *p;
- {
- p += 12;
- while (*p && *p != '>') p++;
- assert(*p == '>');
- return(p+1);
- }
-
- char *skipOp(p)
- register char *p;
- {
- p += 9;
- while (*p && *p != ']') p++;
- assert(*p == ']');
- p++;
- assert(*p == '-');
- p++;
- assert(*p == '>');
- p++;
- while (*p && *p != ']') p++;
- assert(*p == ']');
- return(p+1);
- }
-
- static Boolean relationshipResults [] = { TRUE, TRUE, FALSE };
-
- static Map conformsMap = NULL;
- static OID cacheKey = NULL;
- static Map cacheMap;
-
- static int guessLevel = 0;
- typedef struct GuessRecord {
- int guessLevel;
- OID oid1, oid2;
- Relationship relationship;
- struct GuessRecord *prev;
- } GuessRecord, *GuessRecordPtr;
- static GuessRecordPtr guessRecords = NULL;
-
- static Relationship getRelationship(oid1, oid2)
- OID oid1, oid2;
- {
- if (conformsMap == NULL) {
- conformsMap = Map_Create();
- }
- if (oid1 != cacheKey) {
- cacheKey = oid1;
- cacheMap = (Map) Map_Lookup(conformsMap, (int)oid1);
- if (cacheMap == (Map)NIL) {
- cacheMap = Map_Create();
- Map_Insert(conformsMap, (int)oid1, (int)cacheMap);
- }
- }
- return((Relationship)Map_Lookup(cacheMap, (int)oid2));
- }
-
- static void setRelationship(oid1, oid2, relationship, guess)
- OID oid1, oid2;
- Relationship relationship;
- Boolean guess;
- {
- register GuessRecordPtr g;
-
- if (conformsMap == NULL) {
- conformsMap = Map_Create();
- }
- if (oid1 != cacheKey) {
- cacheKey = oid1;
- cacheMap = (Map) Map_Lookup(conformsMap, (int)oid1);
- if (cacheMap == (Map)NIL) {
- cacheMap = Map_Create();
- Map_Insert(conformsMap, (int)oid1, (int)cacheMap);
- }
- }
- Map_Insert(cacheMap, (int)oid2, (int)relationship);
- if (guess) {
- g = (GuessRecordPtr) malloc(sizeof(GuessRecord));
- g->guessLevel = guessLevel;
- g->oid1 = oid1;
- g->oid2 = oid2;
- g->relationship = relationship;
- g->prev = guessRecords;
- guessRecords = g;
- }
- }
-
- static void startGuessing(oid1, oid2, relationship)
- OID oid1, oid2;
- Relationship relationship;
- {
- guessLevel++;
- setRelationship(oid1, oid2, relationship, TRUE);
- if (relationship == IDENTICAL) setRelationship(oid2, oid1, IDENTICAL, TRUE);
- }
-
- static void endGuessing(worked, conforms)
- Boolean worked, conforms;
- {
- register GuessRecordPtr g;
- for (g=guessRecords; g != NULL && g->guessLevel==guessLevel; g=g->prev) {
- if (!worked) {
- setRelationship(g->oid1, g->oid2, (Relationship)NIL, FALSE);
- } else if (!conforms) {
- setRelationship(g->oid1, g->oid2, (Relationship)NOTCONFORMS, FALSE);
- }
- guessRecords = g->prev;
- free((char *)g);
- }
- guessLevel--;
- }
-
- static ConformsResult allConform(), hardConforms(), i_conforms();
-
- char *fetchInfo(atOID)
- OID atOID;
- {
- /* otlookup, if not there return NULL */
- /* else return the pointer the chars of the string */
- CodeODP codp;
- CodePtr cp;
- StringPtr stringPtr;
-
- codp = (CodeODP) OTLookup(atOID);
- if (IsNULL(codp) || IsNULL(codp->dataPtr)) return(NULL);
- cp = codp->dataPtr;
- stringPtr = (StringPtr) addOffset(cp, cp->abstractTypeInfoOffset);
- return((char *) &stringPtr->data[0]);
- }
-
- /* Call back for at loaded for conforms */
- HResult ConformsCallBack(fReq, fOID)
- ConformReqPtr fReq;
- OID fOID;
- {
- ConformsResult result;
- KMDTrace("Conform", 1,
- "AT %s loaded, re-starting conforms of %s to %s\n",
- PPCOID(fOID), PPCOID(fReq->oid1), PPCOID(fReq->oid2));
- do {
- result = i_conforms(fReq->oid1, fReq->oid2, 1);
- if (! result.hasValue) {
- if (! LoadRequest(result.missingAT, (GenericReqPtr) fReq)) break;
- }
- } while (! result.hasValue);
- /* result is as good as it gets */
- if (result.hasValue) {
- fReq->waiting->resultBrand = DataBrand;
- fReq->waiting->regs.arg1 = (int)result.value;
- schedule(fReq->waiting);
- FreeRequest((GenericReqPtr) fReq);
- }
- }
-
- /* Kernel call */
- void Conform(at1, at2)
- OID at1, at2;
- {
- ConformsResult result;
- ConformReqPtr req = NULL;
- do {
- result = i_conforms(at1, at2, 1);
- if (! result.hasValue) {
- /* create request */
- if (req == NULL) {
- req = mNewRequest(Conform);
- req->oid1 = at1;
- req->oid2 = at2;
- req->hdr.callBack = (GenericHandlerPtr) ConformsCallBack;
- }
- KMDTrace("Conform", 1, "Waiting for AT %s to be loaded\n",
- PPCOID(result.missingAT));
- if (! LoadRequest(result.missingAT, (GenericReqPtr) req)) break;
- }
- } while (! result.hasValue);
- /* result is as good as it gets */
- if (result.hasValue) {
- currentSSP->resultBrand = DataBrand;
- currentSSP->regs.arg1 = (int)result.value;
- if (req != NULL) FreeRequest((GenericReqPtr) req);
- } else {
- req->waiting = preemptRunning();
- req->waiting->status.rs = SSConformWait;
- KMDTrace("LineNumber", 4, "%s waiting on conformity check in %s\n",
- PPPOID(req->waiting->processOID), PPSSPlace(req->waiting));
- }
- }
-
- /* Call back for at loaded for Views */
- HResult ViewCallBack(fReq, fOID)
- ViewReqPtr fReq;
- OID fOID;
- {
- ConformsResult result;
- CodeODP codp;
- CodePtr cp;
-
- if (IsNIL(fReq->restrictOID)) {
- /* we have just loaded the code so we can get the ATOID */
- codp = (CodeODP) OTLookup(fReq->ctOID);
- assert(NonNULL(codp));
- assert(NonNULL(codp->dataPtr));
- cp = codp->dataPtr;
- fReq->restrictOID = cp->ownAbstractType;
- KMDTrace("Conform", 1, "CT %s is loaded, starting view of %s to %s\n",
- PPCOID(fOID), PPCOID(fReq->restrictOID), PPCOID(fReq->newATOID));
- } else {
- KMDTrace("Conform", 1, "AT %s is loaded, re-starting view of %s to %s\n",
- PPCOID(fOID), PPCOID(fReq->restrictOID), PPCOID(fReq->newATOID));
- }
- do {
- result = i_conforms(fReq->restrictOID, fReq->newATOID, 1);
- if (! result.hasValue) {
- KMDTrace("Conform", 1, "Waiting for AT %s to be loaded\n",
- PPCOID(result.missingAT));
- if (! LoadRequest(result.missingAT, (GenericReqPtr) fReq)) break;
- }
- } while (! result.hasValue);
- /* result is as good as it gets */
- if (result.hasValue) {
- if (result.value) {
- codp = (CodeODP) OTLookup(fReq->ctOID);
- if (
- (NonNULL(codp)) && NonNULL(codp->dataPtr) &&
- (codp->dataPtr->ownAbstractType == fReq->restrictOID)
- ) {
- fReq->restrictOID = (OID) NIL;
- }
-
- fReq->waiting->resultBrand = VariableBrand;
- fReq->waiting->regs.arg1 = (int) fReq->dataPtr;
- fReq->waiting->regs.arg2 = (int) OIDOIDOIDToAbCon(fReq->newATOID,
- fReq->restrictOID, fReq->ctOID);
-
- schedule(fReq->waiting);
- } else {
- fail(fReq->waiting);
- }
- FreeRequest((GenericReqPtr) fReq);
- }
- }
-
- /* Kernel call */
- void ViewPtr(dataPtr, abConPtr, atPtr)
- DataAddr dataPtr;
- struct AbCon *abConPtr;
- CodePtr atPtr;
- /* View the object pointed to by dataPtr and abConPtr as one of atPtr */
- {
- OID ownATOID = 0, ownCTOID = 0, at;
- ConformsResult result;
- register ViewReqPtr req = NULL;
-
- at = atPtr->ownOID;
- KMDTrace("Conform", 3, "ViewPtr (0x%04x) as one of %s\n", dataPtr,
- PPCodePtr(atPtr));
-
- if (abConPtr == (AbConPtr) EMNIL || dataPtr == (DataAddr) EMNIL) {
- currentSSP->resultBrand = VariableBrand;
- currentSSP->regs.arg1 = (int) EMNIL;
- currentSSP->regs.arg2 = (int) EMNIL;
- return;
- }
- ownCTOID = abConPtr->CodeOID;
- if (IsNIL(abConPtr->restrictOID) && IsNULL(abConPtr->cPtr)) {
- req = mNewRequest(View);
- req->restrictOID = (OID) NIL;
- req->newATOID = at;
- req->ctOID = ownCTOID;
- req->dataPtr = dataPtr;
- req->hdr.callBack = (GenericHandlerPtr) ViewCallBack;
- KMDTrace("Conform", 1, "Waiting for CT %s to be loaded\n",
- PPCOID(ownCTOID));
- if (! LoadRequest(ownCTOID, (GenericReqPtr) req)) {
- req->waiting = preemptRunning();
- req->waiting->status.rs = SSConformWait;
- KMDTrace("LineNumber", 4, "%s waiting on conformity check in %s\n",
- PPPOID(req->waiting->processOID), PPSSPlace(req->waiting));
- return;
- } else {
- assert(NonNULL(abConPtr->cPtr));
- }
- }
- ownATOID = abConPtr->restrictOID;
- if (IsNIL(ownATOID)) {
- ownATOID = abConPtr->cPtr->ownAbstractType;
- }
-
- do {
- result = i_conforms(ownATOID, at, 1);
- if (! result.hasValue) {
- /* create request */
- if (req == NULL) {
- req = mNewRequest(View);
- req->restrictOID = ownATOID;
- req->newATOID = at;
- req->ctOID = ownCTOID;
- req->dataPtr = dataPtr;
- req->hdr.callBack = (GenericHandlerPtr) ViewCallBack;
- }
- KMDTrace("Conform", 1, "Waiting for AT %s to be loaded\n",
- PPCOID(result.missingAT));
- if (! LoadRequest(result.missingAT, (GenericReqPtr) req)) break;
- }
- } while (! result.hasValue);
- /* result is as good as it gets */
- if (result.hasValue) {
- if (result.value) {
- CodeODP codp;
-
- codp = (CodeODP) OTLookup(ownCTOID);
- if (
- (NonNULL(codp)) && NonNULL(codp->dataPtr) &&
- (codp->dataPtr->ownAbstractType == ownATOID)
- ) {
- ownATOID = (OID) NIL;
- }
-
- currentSSP->resultBrand = VariableBrand;
- currentSSP->regs.arg1 = (int) dataPtr;
- currentSSP->regs.arg2 = (int) OIDOIDOIDToAbCon(at, ownATOID, ownCTOID);
- } else {
- fail(preemptRunning());
- }
- if (req != NULL) FreeRequest((GenericReqPtr) req);
- } else {
- req->waiting = preemptRunning();
- req->waiting->status.rs = SSConformWait;
- KMDTrace("LineNumber", 4, "%s waiting on conformity check in %s\n",
- PPPOID(req->waiting->processOID), PPSSPlace(req->waiting));
- }
- }
-
- static char *SPACES = " ";
-
- #define ANSWER(b, id) { \
- result.hasValue = (id == 0); \
- result.value = b; \
- result.missingAT = id; \
- return(result); \
- }
-
- static ConformsResult i_conforms(oid1, oid2, level)
- OID oid1, oid2;
- int level;
- {
- Relationship relationship;
- ConformsResult result;
- char *at1, *at2;
- Boolean theResult;
-
- KMDTrace("Conform", level, "%.*sConforming 0x%08x to 0x%08x\n",
- level, SPACES, oid1, oid2);
-
- if ((at1 = fetchInfo(oid1)) == NULL) ANSWER(FALSE, oid1);
- if ((at2 = fetchInfo(oid2)) == NULL) ANSWER(FALSE, oid2);
-
- if (oid1 == oid2) {
- KMDTrace("Conform", level, "%.*sSame oid => true\n", level, SPACES);
- ANSWER(TRUE, 0);
- }
- if (oid1 == OIDOfBuiltin(B_INSTAT, NILINDEX)) {
- KMDTrace("Conform", level, "%.*sNil conforms to anything => true\n",
- level, SPACES);
- ANSWER(TRUE, 0);
- } else if (oid2 == OIDOfBuiltin(B_INSTAT, NILINDEX)) {
- KMDTrace("Conform", level, "%.*sOnly nil conforms to None => false\n",
- level, SPACES);
- ANSWER(FALSE, 0);
- }
- relationship = getRelationship(oid1, oid2);
- if ((int) relationship != NIL) {
- theResult = relationshipResults[(int)relationship];
- KMDTrace("Conform", level, "%.*sAlready know => %s\n", level, SPACES,
- theResult ? "true" : "false");
- ANSWER(theResult, 0);
- }
-
- /* if at2 will not admit conformers, then give up */
- if (*at2 == 'Y') {
- if (*(at2+1) == 'Y' && *(at1+1) == 'Y') {
- KMDTrace("Conform", level,
- "%.*s0x%08x cannotBeConformedTo but 0x%08x is a vector: keep going\n",
- level, SPACES, oid2, oid1);
- } else {
- KMDTrace("Conform", level, "%.*s0x%08x cannotBeConformedTo => false\n",
- level, SPACES, oid2);
- ANSWER(FALSE, 0);
- }
- }
-
- startGuessing(oid1, oid2, CONFORMS);
- result = hardConforms(oid1, oid2, at1, at2, level+1);
- if (result.hasValue && result.value) {
- endGuessing(TRUE, TRUE);
- KMDTrace("Conform", level, "%.*s=> true\n", level, SPACES);
- ANSWER(TRUE, 0);
- } else {
- endGuessing(result.hasValue, result.value);
- if (result.hasValue)
- KMDTrace("Conform", level, "%.*s=> false\n", level, SPACES);
- ANSWER(FALSE, result.missingAT);
- }
- }
-
- static int pLength(s)
- register char *s;
- {
- register int r = 0;
- assert(*s == '[');
- while (*s && *s != ']') {
- if (*s == 'S' || *s == 'O') r++;
- s++;
- }
- return(r);
- }
-
- static ConformsResult hardConforms(oid1, oid2, at1, at2, level)
- OID oid1, oid2;
- char *at1, *at2;
- int level;
- {
- char *ops1, *ops2, *args1, *args2, *res1, *res2;
- ConformsResult result;
-
- /* check immutability */
- if (*(at2+2) == 'Y' && *(at1+2) == 'N') {
- KMDTrace("Conform", level,
- "%.*s0x%08x is immutable, 0x%08x isnt => false\n", level,
- SPACES, oid2, oid1);
- ANSWER(FALSE, 0);
- }
-
- ops1 = opsOf(at1);
- ops2 = opsOf(at2);
- while (*ops2 && *ops2 != '\n') {
- KMDTrace("Conform", level, "%.*sChecking operation %.8s\n", level, SPACES,
- ops2+2);
- while (*ops1 && *ops1 != '\n' && !opnameSame(ops1, ops2)) {
- ops1 = skipOp(ops1);
- }
- if (*ops1 == '\0' || *ops1 == '\n') {
- KMDTrace("Conform", level, "%.*s%s not defined => false\n", level,
- SPACES, ops2 + 2);
- ANSWER(FALSE, 0);
- }
- args1 = paramsOf(ops1);
- res1 = resultsOf(ops1);
- args2 = paramsOf(ops2);
- res2 = resultsOf(ops2);
- if (pLength(args1) != pLength(args2)) {
- KMDTrace("Conform", level,
- "%.*soperation %.8s argument number mismatch %d != %d => false\n",
- level, SPACES, ops1+2, pLength(args1), pLength(args2));
- ANSWER(FALSE, 0);
- }
- if (pLength(res1) != pLength(res2)) {
- KMDTrace("Conform", level,
- "%.*soperation %.8s result number mismatch %d != %d => false\n",
- level, SPACES, ops1+2, pLength(res1), pLength(res2));
- ANSWER(FALSE, 0);
- }
- if (*ops2 == 'F' && *ops1 == 'O') {
- KMDTrace("Conform", level,
- "%.*soperation %.8s function mismatch => false\n", level, SPACES,
- ops1+2);
- ANSWER(FALSE, 0);
- }
- result = allConform(oid2, oid1, args2, args1, level+1);
- if (! result.hasValue) ANSWER(FALSE, result.missingAT);
- if (! result.value) {
- KMDTrace("Conform", level,
- "%.*soperation %.8s arguments mismatch => false\n", level, SPACES,
- ops1+2);
- ANSWER(FALSE, 0);
- }
- result = allConform(oid1, oid2, res1, res2, level+1);
- if (! result.hasValue) ANSWER(FALSE, result.missingAT);
- if (! result.value) {
- KMDTrace("Conform", level,
- "%.*soperation %.8s results mismatch => false\n", level, SPACES,
- ops1+2);
- ANSWER(FALSE, 0);
- }
- KMDTrace("Conform", level, "%.*soperation %.8s matches\n", level, SPACES,
- ops1+2);
- ops1 = skipOp(ops1);
- ops2 = skipOp(ops2);
- }
- ANSWER(TRUE, 0);
- }
-
- char *fetchOID(fOID, fOIDP, p)
- OID fOID, *fOIDP;
- register char *p;
- {
- register OID oid;
- register int c;
- if (*p == 'S') {
- *fOIDP = fOID;
- p++;
- } else {
- assert(*p == 'O');
- p ++;
- oid = 0;
- while (*p != ',' && *p != ']') {
- c = *p++;
- oid <<= 4;
- oid += '0' <= c && c <= '9' ? c - '0' : c - 'a' + 10;
- }
- *fOIDP = oid;
- }
- return(*p == ',' ? p + 1 : p);
- }
-
- static ConformsResult allConform(oid1, oid2, ps1, ps2, level)
- OID oid1, oid2;
- register char *ps1, *ps2;
- int level;
- {
- ConformsResult result;
- OID poid1, poid2;
- assert(*ps1 == '[');
- ps1 ++;
- assert(*ps2 == '[');
- ps2 ++;
- while (*ps1 != ']') {
- ps1 = fetchOID(oid1, &poid1, ps1);
- ps2 = fetchOID(oid2, &poid2, ps2);
- result = i_conforms(poid1, poid2, level+1);
- if (! result.hasValue) ANSWER(FALSE, result.missingAT);
- if (! result.value) ANSWER(FALSE, 0);
- }
- ANSWER(TRUE, 0);
- }
-
- /* kernel call*/
- void RestrictPtr(dataPtr, abConPtr, restrictPtr)
- DataAddr dataPtr;
- struct AbCon *abConPtr;
- CodePtr restrictPtr;
- /* Restrict the object pointed to by dataPtr and abConPtr to restrictPtr */
- {
- AVariable aVar;
- AbConPtr newAbConPtr;
-
- aVar.myAddr = dataPtr;
- aVar.myAbConPtr = abConPtr;
-
- KMDTrace("View", 3, "RestrictPtr (0x%04x) Var: %s to %s\n", dataPtr,
- PPVar(&aVar), PPCodePtr(restrictPtr));
-
- if (IsNIL(abConPtr) || IsNIL(dataPtr)) {
- KMDTrace("View", 3, "variable is NIL\n");
- currentSSP->resultBrand = VariableBrand;
- currentSSP->regs.arg1 =
- currentSSP->regs.arg2 = (int) EMNIL;
- return;
- }
- newAbConPtr = OIDOIDOIDToAbCon(restrictPtr->ownOID, restrictPtr->ownOID,
- abConPtr->CodeOID);
- if (NonNULL(newAbConPtr)) {
- currentSSP->resultBrand = VariableBrand;
- currentSSP->regs.arg1 = (int) dataPtr;
- currentSSP->regs.arg2 = (int) newAbConPtr;
- KMDTrace("View", 3, "Result: AbCon (0x%04x) Var: %s\n",
-
- PPVar((AVariablePtr) ¤tSSP->regs.arg1));
- return;
- }
- assert(FALSE);
- abort();
- }
-
-