gecko-dev/ef/Compiler/FrontEnd/LocalEnv.h

220 строки
7.4 KiB
C++

/* -*- 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 Binding, class Common, Uint32 nMemoryBindings>
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<class Binding, class Common, Uint32 nMemoryBindings>
inline LocalEnv<Binding, Common, nMemoryBindings>::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<class Binding, class Common, Uint32 nMemoryBindings>
inline void LocalEnv<Binding, Common, nMemoryBindings>::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<class Binding, class Common, Uint32 nMemoryBindings>
inline Binding &LocalEnv<Binding, Common, nMemoryBindings>::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<class Binding, class Common, Uint32 nMemoryBindings>
inline Binding &LocalEnv<Binding, Common, nMemoryBindings>::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<class Binding, class Common, Uint32 nMemoryBindings>
inline Binding &LocalEnv<Binding, Common, nMemoryBindings>::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<class Binding, class Common, Uint32 nMemoryBindings>
inline Binding &LocalEnv<Binding, Common, nMemoryBindings>::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<class Binding, class Common, Uint32 nMemoryBindings>
void LocalEnv<Binding, Common, nMemoryBindings>::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<class Binding, class Common, Uint32 nMemoryBindings>
void LocalEnv<Binding, Common, nMemoryBindings>::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