/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (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.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #ifndef LOCALENV_H #define LOCALENV_H #include "Fundamentals.h" // Information common to all environments in a graph struct CommonEnv { Pool &envPool; // Memory pool from which to allocate const Uint32 nLocals; // Number of words of local variables const Uint32 stackBase; // Index of first stack temporary const Uint32 stackSize; // Number of words of local stack space const Uint32 nEnvSlots; // nMemoryBindings + nLocals + stackSize CommonEnv(Pool &envPool, Uint32 nMemoryBindings, Uint32 nLocals, Uint32 stackSize): envPool(envPool), nLocals(nLocals), stackBase(nMemoryBindings + nLocals), stackSize(stackSize), nEnvSlots(nMemoryBindings + nLocals + stackSize) {} }; // A single environment containings bindings of class Binding. // Class Common, which should be derived from CommonEnv, contains information // common to all environments in a graph. template class LocalEnv { protected: const Common &commonEnv; // Backpointer to information shared among all LocalEnvs in a graph private: Binding *bindings; // Array of: // nMemoryBindings memory bindings // nLocals local variable bindings // stackSize stack temporaries' bindings // (the bindings may be nil). Uint32 sp; // Stack pointer (index within bindings array of first unused temporary) // Bindings at indices 0..sp-1 are valid; others are ignored public: explicit LocalEnv(const Common &commonEnv); LocalEnv(const LocalEnv &env): commonEnv(env.commonEnv) {copyEnv(env);} void operator=(const LocalEnv &env) {assert(!bindings); copyEnv(env);} void move(LocalEnv &env); void init(); protected: void copyEnv(const LocalEnv &env); Binding *bindingsBegin() const {return bindings;} // Return the first valid binding Binding *bindingsEnd() const {return bindings + sp;} // Return the last valid binding + 1 Binding *bindingsMemoryEnd() const {return bindings + nMemoryBindings;} // Return the last memory binding + 1 public: Pool &envPool() const {return commonEnv.envPool;} Binding &memory() const {return bindings[0];} Binding &local(Uint32 n) const {assert(n < commonEnv.nLocals); return bindings[nMemoryBindings + n];} Binding &stackNth(Uint32 n) const {assert(n > 0 && sp >= commonEnv.stackBase + n); return bindings[sp - n];} Binding *stackTopN(Uint32 DEBUG_ONLY(n)) const {assert(sp >= commonEnv.stackBase + n); return bindings + sp;} // Stack operations Uint32 getSP() const {return sp - commonEnv.stackBase;} void dropAll() {sp = commonEnv.stackBase;} void drop(uint n) {assert(sp >= commonEnv.stackBase + n); sp -= n;} void raise(uint n) {assert(sp + n <= commonEnv.nEnvSlots); sp += n;} Binding &pop() {assert(sp > commonEnv.stackBase); return bindings[--sp];} // Note: Result invalidated by next push! Binding &push() {assert(sp < commonEnv.nEnvSlots); return bindings[sp++];} Binding &pop2(); Binding &push2(); Binding &pop1or2(bool two); Binding &push1or2(bool two); protected: bool compatible(const LocalEnv &env) {return bindings && env.bindings && &commonEnv == &env.commonEnv && sp == env.sp;} }; // --- INLINES ---------------------------------------------------------------- // // Construct a new LocalEnv for the method described by commonEnv. // The LocalEnv cannot be used unless init is called first or another LocalEnv // is copied to this one. // template inline LocalEnv::LocalEnv(const Common &commonEnv): commonEnv(commonEnv), bindings(0) {} // // Destructively move the given LocalEnv (which must have been initialized) // to this LocalEnv, which must be uninitialized. The given LocalEnv is // left uninitialized. // template inline void LocalEnv::move(LocalEnv &env) { assert(!bindings && env.bindings); bindings = env.bindings; sp = env.sp; #ifdef DEBUG env.bindings = 0; #endif } // // Pop and return a long or double binding from the stack. The two words on the top of // the stack must contain a long or double value. // Note that the returned reference will be invalidated by the next push. // template inline Binding &LocalEnv::pop2() { assert(sp > commonEnv.stackBase+1 && bindings[sp-1].isSecondWord()); return bindings[sp -= 2]; } // // Push a long or double binding outo the stack. The return value is a reference to // a new stack slot; the caller must initialize it to refer to the long or double's first word. // template inline Binding &LocalEnv::push2() { assert(sp < commonEnv.nEnvSlots-1); Binding *b = &bindings[sp]; b[1].defineSecondWord(); sp += 2; return *b; } // // Do pop() if two is false or pop2() if two is true. // template inline Binding &LocalEnv::pop1or2(bool two) { assert(sp > commonEnv.stackBase+two && (!two || bindings[sp-1].isSecondWord())); if (two) --sp; return bindings[--sp]; } // // Do push() if two is false or push2() if two is true. // template inline Binding &LocalEnv::push1or2(bool two) { assert(sp < commonEnv.nEnvSlots-two); Binding &b = bindings[sp++]; if (two) bindings[sp++].defineSecondWord(); return b; } // --- TEMPLATES -------------------------------------------------------------- // // Initialize every entry in this LocalEnv to be empty and the stack to have no // temporaries. This LocalEnv must not have been initialized before. // template void LocalEnv::init() { assert(!bindings); Binding *lb = new(commonEnv.envPool) Binding[commonEnv.nEnvSlots]; bindings = lb; Uint32 stackBase = commonEnv.stackBase; sp = stackBase; Binding *lbEnd = lb + stackBase; while (lb != lbEnd) lb++->clear(); } // // Assign a copy of the given LocalEnv (which must have been initialized) // to this LocalEnv, which is known to be uninitialized. // template void LocalEnv::copyEnv(const LocalEnv &env) { assert(env.bindings); Binding *lbDst = new(commonEnv.envPool) Binding[commonEnv.nEnvSlots]; copy(env.bindingsBegin(), env.bindingsEnd(), lbDst); bindings = lbDst; sp = env.sp; } #endif