// environment.h - Each environment records the state of computation within a // clause. It enables the computation to continue after the // current subgoal has been solved. // // ##Copyright## // // Copyright 2000-2016 Peter Robinson (pjr@itee.uq.edu.au) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.00 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ##Copyright## // // $Id: environment.h,v 1.6 2006/01/31 23:17:50 qp Exp $ #ifndef ENVIRONMENT_H #define ENVIRONMENT_H #include #include "area_offsets.h" #include "code.h" #include "objects.h" #include "defs.h" #include "magic.h" #include "qem_options.h" #include "record_stack.h" class Thread; class EnvironmentStack : public RecordStack { friend class Trace; private: class Environment { private: static const word32 GC_Mark = 0x80000000ULL; public: EnvLoc previousEnvironment; CodeLoc continuationInstruction; word32 NumYRegs; #ifdef WIN32 Object* y[1]; #else Object* y[1] __attribute__ ((aligned)); #endif Environment(void) : NumYRegs(0) { } // // Set all the Yregs to NULL // inline void zeroYRegs(void) { for (u_int i = 0; i < NumYRegs; i++) { y[i] = NULL; } } // // Compare two environments for ``equality''. This // is rough and ready and quite probably unreliable. // bool operator==(const Environment& e) const { return (previousEnvironment == e.previousEnvironment && continuationInstruction == e.continuationInstruction); } bool operator!=(const Environment& e) const { return ! (*this == e); } // // Work out the size of the environment. // word32 size(void) const { return(sizeof(Environment) + (NumYRegs - 1) * sizeof(Object*)); } // // Set the Mark bit for garbage collection // void gc_markEnv(void) { NumYRegs |= GC_Mark; } // // Unset the Mark bit. // void gc_unmarkEnv(void) { NumYRegs &= ~GC_Mark; } // // Test the mark bit. // bool gc_isMarkedEnv(void) { return ((NumYRegs & GC_Mark) == GC_Mark); } }; // // Fetch the address of an environment. // If EnvLoc or StackLoc changes representation, then a bug may // occur if this is not changed. // Environment *fetchEnv(const EnvLoc env) { assert(fetchAddr(env) != NULL); return((Environment *)(fetchAddr(env))); } // // Return the name of the area. // virtual const char *getAreaName(void) const { return("environment stack"); } public: explicit EnvironmentStack(word32 size) : RecordStack(size, size / 10) { } EnvLoc firstEnv(void) const { return(0); } // // Get the top of the environment. // If EnvLoc or StackLoc changes representation, then a bug may // occur if this is not changed. // EnvLoc getTop(void) const { return(getTopOfStack()); } // // Set the top of the environment. // If EnvLoc or StackLoc changes representation, then a bug may // occur if this is not changed. // void setTop(const EnvLoc top) { setTopOfStack(top); } // // Push a new environment onto the stack. // If EnvLoc or StackLoc changes representation, then a bug may // occur if this is not changed. // EnvLoc push(const EnvLoc PrevEnv, const CodeLoc ContInst, const word32 NumYs) { EnvLoc env; // // Allocate environment. // env = pushRecord(sizeof(Environment) + (NumYs - 1) * sizeof(Object*)); // // Initialise fixed fields. // fetchEnv(env)->previousEnvironment = PrevEnv; fetchEnv(env)->continuationInstruction = ContInst; fetchEnv(env)->NumYRegs = NumYs; fetchEnv(env)->zeroYRegs(); return(env); } // Test if environment is top environment // bool isTopEnv(const EnvLoc env) const { return(previousTop(getTop()) == env); } // // Work out the size of the given environment in StackWords. // word32 envSize(const EnvLoc env) { return(numberOfStackWords(fetchEnv(env)->size())); } // // Work out the size of the environment given the number of Yregs. // word32 size(const word32 NumYs) const { return(sizeof(Environment) + NumYs * sizeof(Object*)); } // Bring the top of stack down. Thus, reclaim all the space between // the current top and the new top. This is used for environment // trimming. // void trim(const EnvLoc env, const word32 NumYs) { assert(previousTop(getTop()) == env); if(fetchEnv(env)->NumYRegs != NumYs) { trimRecord(env, size(NumYs)); fetchEnv(env)->NumYRegs = NumYs; } } // // Fetch the previousEnvironment and continuationInstruction fields // from an environment. // void retrieve(const EnvLoc prev, EnvLoc& env, CodeLoc& code) { code = fetchEnv(prev)->continuationInstruction; env = fetchEnv(prev)->previousEnvironment; } // // Get the previous env // EnvLoc getPreviousEnv(const EnvLoc env) { return(fetchEnv(env)->previousEnvironment); } // // Get a Y register. // Object*& yReg(const EnvLoc env, const word32 RegNum) { return(fetchEnv(env)->y[RegNum]); } // // Get a y reg address // heapobject* yRegAddr(const EnvLoc env, const word32 RegNum) { return (reinterpret_cast(fetchEnv(env)->y + RegNum)); } // // Check if given Env is GC marked // bool gc_isMarkedEnv(const EnvLoc env) { return(fetchEnv(env)->gc_isMarkedEnv()); } // // GC mark given env // void gc_markEnv(const EnvLoc env) { fetchEnv(env)->gc_markEnv(); } // // GC unmark given env // void gc_unmarkEnv(const EnvLoc env) { fetchEnv(env)->gc_unmarkEnv(); } // // Get the number of Y regs for a given env // word32 getNumYRegs(const EnvLoc env) { return(fetchEnv(env)->NumYRegs); } // // Save the area. // void save(ostream& strm) const { saveStack(strm, ENVIRONMENT_MAGIC_NUMBER); } // // Restore the area. // void load(istream& strm) { loadStack(strm); } // // Debugging display // ostream& Display(ostream& strm, EnvLoc index, const size_t = 0); #ifdef QP_DEBUG void printMe(AtomTable&, EnvLoc); #endif //QP_DEBUG }; #endif // ENVIRONMENT_H