/* Sun-$Revision: 23.8 $ */
/* Copyright 1992-9 Sun Microsystems, Inc. and Stanford University.
See the LICENSE file for license information. */
# pragma interface
# if defined(FAST_COMPILER) || defined(SIC_COMPILER)
// nmethods (native methods) are the compiled code versions of Self
// methods.
struct nmFlags {
// metrowerks requires int types for bitfields to pack!
/* bool */ int isZombie: 1; // can be discarded if not on stack
/* bool */ int isDI: 1; // affected by DI
/* bool */ int isInvalid: 1; // nmethod is invalid (needs programming conv.)
/* bool */ int isDebug: 1; // version compiled for debugging
/* nm_compiler */ int compiler: 2; // compiler which generated this nmethod
/* bool */ int flushed: 1; // to catch flushing errors
/* bool */ int isUncommonRecompiled: 1; // recompiled because of uncommon trap? (SIC)
/* bool */ int isYoung: 1; // "young"? (recently recompiled)
/* bool */ int isToBeRecompiled: 1; // to be recompiled as soon as it matures
/* bool */ int isImpureNIC: 1; // if NIC method, something is inlined
/* fint */ int filler: 1;
/* uint16 */ unsigned int level: 4; // optimization level
/* uint16 */ unsigned int version: 8; // version number (0 = first version)
/* uint16 */ unsigned int trapCount: 8; // number of map-load traps encountered
void clear() { assert(sizeof(nmFlags) == 4, "oops"); *(int32*)this = 0; }
};
nmethod* constructDoItMethod(oop receiver, oop method);
# define NMETHOD_FROM(fieldName, p) \
((nmethod*)((char*)p - (char*)&((nmethod*)NULL)->fieldName))
class nmethod : public OopNCode {
public:
int32 depsLen;
nmethodScopes* scopes;
protected:
nmln* depsAddr;
VTBL_AND_SETTER(nmethod,);
public:
NMethodLookupKey key; // key for code table searching
codeTableEntry *codeTableLink; // links codeTableEntries for this nmethod
nmln linkedSends; // links all nmethods that are i-c to me
nmln diLink; // links the nmethod that DI forwards to me
nmln zoneLink; // used by the zone to link replacement candidates
int32 id; // for LRU and recompiles; every nmethod has unique ID
int32 oldCount; // previous value of usage counter
nmFlags flags; // various flags
uint16 verifiedOffset;// offset of entry point for known map
uint16 diCheckOffset; // offset of entry point for DI checks
uint16 frameCreationOffset; // offset of entry point where activation frame
// has been established.
protected:
uint16 frame_size; // size of stack frame (in words)
public:
frame* frame_chain; // beginning link of frames that are running me
protected:
nmethod(AbstractCompiler* c, bool generateDebugCode = false);
void get_platform_specific_data(AbstractCompiler* c);
void* operator new(size_t size);
void deallocate() { flush(); }
public:
friend nmethod* new_nmethod(AbstractCompiler* c,
bool generateDebugCode = false);
char* insts() { return (char*)(this + 1); }
char* verifiedEntryPoint() { return insts() + verifiedOffset; }
char* diCheckEntryPoint() { return insts() + diCheckOffset; }
char* entryPointFor(sendDesc *sd);
PcDesc* pcs() { return (PcDesc*) scopes->pcs();}
PcDesc* pcsEnd() { return (PcDesc*) scopes->pcsEnd();}
nmln* deps() { return depsAddr;}
nmln* depsEnd() { return (nmln*) ((char*) deps() + depsLen);}
fint size() { return (char*)locsEnd() - (char*)this; }
void removeFromCodeTable();
nmethod** dBackLinkAddr() { return (nmethod**)deps() - 1; }
bool isNMethod() { return vtbl_value() == static_vtbl_value(); }
bool isUncommon() { return false; }
bool isZombie() { return flags.isZombie; }
void makeZombie(bool unlink = true);
bool isDI() { return flags.isDI; }
bool isInvalid() { return flags.isInvalid; }
bool isValid() { return !isInvalid(); }
fint compiler() {
switch (flags.compiler) {
case nm_nic: return NIC;
case nm_sic: return SIC;
default: fatal("invalid compiler"); return 0;
}
}
bool isDebug() { return flags.isDebug; }
bool isUncommonRecompiled() { return flags.isUncommonRecompiled; }
bool isYoung() { return flags.isYoung; }
bool isImpureNIC() { return flags.isImpureNIC; }
bool reusable() { return compiler()==NIC && !isImpureNIC(); }
void makeYoung();
void makeVeryYoung();
void makeOld();
fint agingLimit(); // # invocations before isYoung is cleared
bool isToBeRecompiled() { return flags.isToBeRecompiled; }
void makeToBeRecompiled() { flags.isToBeRecompiled = 1; }
void makeImpureNIC() { flags.isImpureNIC= 1; }
bool needToRecompileFor(sendDesc *s) {
return compiler() == NIC && s->isOptimized(); }
void setCompiler(fint c) {
switch (c) {
case NIC: flags.compiler = nm_nic; break;
case SIC: flags.compiler = nm_sic; break;
default: fatal("invalid compiler"); break;
}
}
bool shouldRecompile(); // these names are crummy (one is not the inverse
bool shouldNotRecompile(); // of the other)
bool mustNotRecompile();
fint level();
# ifdef UNUSED
void setLevel(fint newLevel) { flags.level = newLevel; }
# endif
fint version() { return flags.version; }
void setVersion(fint v);
fint invocationCount(); // approximation (not all calls have counters)
fint ncallers(); // # of callers (*not* # of inline caches)
fint nsends(bool includeAll = false); // # of inlinable sends; if includeAll,
// also count non-inlinable sends
bool isTiny();
bool is_frame_chain_saved() { return frame_chain == SavedFrameChain; }
void save_frame_chain() { frame_chain= SavedFrameChain; }
void clear_frame_chain() { frame_chain= NULL; }
void unlink_saved_frame_chain() {
if (frame_chain == SavedFrameChain) frame_chain= NoFrameChain; }
void save_unlinked_frame_chain() {
if (frame_chain == NoFrameChain) frame_chain= SavedFrameChain; }
bool encompasses(void* p);
int32 frameSize() { return frame_size; }
// for zone LRU management
int32 lastUsed() { return LRUtable[id].lastUsed; }
bool isUsed() {
return frame_chain != NoFrameChain
|| !LRUflag[id]
|| useCount[id] != oldCount; }
virtual void moveTo_inner(NCodeBase* to, int32 delta, int32 size);
void shift_target(nmln* l, int32 delta);
NCodeBase* unlink_me(nmln* l);
void forwardLinkedSend(nmln* l, nmethod* to) {
l->asSendDesc()->rebind(to); }
void addDeps(dependencyList *deps); // changes deps
void moveDeps(nmln* newDeps, int32 delta);
void moveScopes(nmethodScopes* scopes);
void remove_me_from_inline_cache();
void forwardLinkedSends(nmethod* to);
void unlink(); // unlink from codeTable, deps etc.
void flush();
void flushPartially(); // used during recompilation
void invalidate();
#ifdef UNUSED
int32 flushPICs();
int32 unlinkDI(nmln*& savedDIChildren);
#endif
void relinkDI(int32 n, nmln*& savedDIChildren);
protected:
void check_store();
public:
bool code_oops_do(oopsDoFn f);
bool scavenge_contents();
void gc_mark_contents();
bool gc_unmark_contents();
bool switch_pointers(oop from, oop to,
nmethodBList* nmethods_to_invalidate);
void relocate();
void verify();
// programming and debugging
PcDesc* containingPcDesc(char* pc);
PcDesc* containingPcDescOrNULL(char* pc);
public:
ScopeDesc* containingScopeDesc(char* pc);
ScopeDesc* correspondingScopeDesc(ScopeDesc* s);
#ifdef DEBUG
PcDesc* correspondingPC(ScopeDesc* sd, int32 bci);
#endif
sendDesc* sendDescFor(compiled_vframe* vf, bool wantIntrCheck);
Map* blockMapFor(blockOop bl);
addrDesc* addrDesc_at(char* p); // slow - for debugging
// Returns true if activation frame has been established.
bool has_frame_at(char* pc);
// Returns true if pc is not in prologue or epilogue code.
bool in_self_code_at(char* pc);
oop method() { return scopes->root()->method(); }
# ifdef UNUSED
bool isMethod() { return scopes->root()->isMethodScope(); }
# endif
bool isAccess() { return scopes->root()->isAccessScope(); }
void print();
void printCode();
# ifdef DEBUG
void printLocs();
void printDeps();
void printPcs();
# endif
friend bool isNMethod(void* p);
friend nmethod* nmethodContaining(char* pc, char* likelyEntryPoint);
friend nmethod* findNMethod(void* start);
friend nmethod* findNMethod_maybe(void* start);
friend nmethod* nmethod_from_insts(char* insts) { // for efficiency
nmethod* nm = (nmethod*) insts - 1;
if (::isNMethod(nm)) return nm; else return findNMethod(nm);
}
# include "_nmethod_pd.h.incl"
};
# else // defined(FAST_COMPILER) || defined(SIC_COMPILER)
struct nmethod {
void invalidate() {}
};
# endif