/* Sun-$Revision: 23.10 $ */
/* Copyright 1992-9 Sun Microsystems, Inc. and Stanford University.
See the LICENSE file for license information. */
# pragma interface
// A Process is the VM-level process descriptor of a Self process;
// Self-level process objects (see processOop/Map) contain a pointer
// to their respective Process object and vice versa.
extern Process* prevProcess;
extern Process* currentProcess;
extern Process* twainsProcess;
extern Process* vmProcess;
extern bool8 processSemaphore; // "semaphore" to protect some critical sections
extern bool ConversionInProgress; // true during programming conversions
extern bool traceP;
extern bool traceV;
class CSect {
bool b;
bool* sem;
public:
CSect(bool& sema) { b = sema; sem = &sema; sema = true; }
~CSect() { *sem = b; }
};
struct PreservedList {
preservedVmObjBList list;
PreservedList() : list(32, true) { }
void clear() { list.clear(); }
void oops_do(oopsDoFn f, Process* p);
};
enum ProcessState {
initialized, // ready, but has no stack yet and hasn't run Self code
ready, // could continue at any time, or is currently running
stopped, // stopped because of error; cannot continue but
// still has a stack which can be inspected
aborting, // currently unwinding its stack, or already dead
// but not yet destroyed; has no stack
defunct // not a real process
};
typedef void (*process_p)();
class Process: public CHeapObj {
char* suspendedSP; // process state - saved in runtime_(sparc_mac_ppc).s
char* suspendedPC;
Process* next;
Stack stk;
oop method; // top-level doIt method
PreservedList preservedList;
processOop procObj;
frame* check_vfo_locals; // for checking vframeOop liveness
frame* check_vfo_locals_sender; // check_vfo_locals->sender()
// for debugging only
bool check_vfo_locals_is_uncommon; // is check_vfo_locals's nmethod an uncommon branch?
bool stepping; // are we in single-step mode?
bool stopping; // just returned from "finish" operation; stop ASAP
char* _uncommonPC; // PC of uncommon trap (if currently handling unc.trap)
vframeOop _killUpToVF;// first survivor when cutting back the stack
bool deoptimizing; // currently deoptimizing the last stack frame
public:
bool zombie; // true if it was unreachable at the last GC
bool restartAfterConversion; // for controlling restarting after conversion
protected:
Process* aborter; // process aborting us
public:
ResourceArea resource_area;
int32 nesting; // e.g. 2 means Self called VM called Self
int32 current_hash; // Counter used when assigning hash-values to objects.
ProcessState state;
vframeOop stopActivation; // activation of "finish" operation
Profiler* profiler; // profiler for this process.
friend void startCurrentProcess();
friend void interruptCheck();
friend class Processes;
friend class processOopClass;
friend class vframeMirror;
Process(processOop p, int32 sSize, oop rcvr = NULL,
stringOop sel = NULL, objVectorOop args = NULL);
~Process();
void init(char* pcVal);
void print();
void print_short();
// execution
bool hasStack() { return stk.base != NULL; }
bool allocate();
void start();
void terminate();
void abort();
void transfer(); // coroutine transfer to this process
// termination functions
static void volatile abort_process();
static void volatile terminate_process();
void setupPreemption() { setSPLimit(stackEnd()); } // set up for preemption
void clearPreemption() { setSPLimit(spLimit()); } // reset
bool preemptionPending();
void nonLifoError();
void setSingleStepping(); // set up single step mode
void patchForSingleStepping(frame* f = NULL);
// sets SPLimit & frame patch if necessary
bool isSingleStepping() { return stepping; }
void resetSingleStepping();
void setUncommon(char* pc) { _uncommonPC = pc; }
char* uncommonPC() { return _uncommonPC; }
bool isUncommon() { return _uncommonPC != NULL; }
void resetUncommon() { _uncommonPC = NULL; }
void setStopPoint(vframeOop stop);
bool isStopping() { return stopping; }
frame* stopFrame();
void resetStopping() { stopping = false; }
void killFrames(abstract_vframe* vf);
bool isKilling() { return _killUpToVF != NULL; }
void resetKilling() { _killUpToVF = NULL; }
vframeOop killVF() { return _killUpToVF; }
void setDeoptimizing() { deoptimizing = true; }
bool isDeoptimizing() { return deoptimizing; }
void resetDeoptimizing() { deoptimizing = false; }
void deoptimize(frame* last); // deoptimize last stack frame
bool isKillingOrDeoptimizing() { return isKilling() || isDeoptimizing(); }
bool verifyFramePatches();
void gotoByteCode(abstract_vframe* last, smi bci, objVectorOop exprStack, void* FH);
bool isClean() {
return !stopping
&& !stepping
&& !isUncommon()
&& !check_vfo_locals
&& !isKilling()
&& !isDeoptimizing(); }
// methods for top-level running of self code
oop runDoItMethod( oop rcv,
oop meth,
oop* args = NULL,
fint arg_count = 0);
oop prepare_to_call_self();
void cleanup_after_calling_self();
void cleanup_after_eval_prim(oop res);
private:
void initialize(oop rcvr, stringOop sel, objVectorOop args);
void kill();
public:
// stack operations
int32 selfNesting() { return nesting; }
bool inSelf(bool including_prologue = false); // "in Self" = has visible Self activations
// (false if !including_prologue && topmost activation is in prologue)
char* stackEnd() { return stk.end(); }
bool contains(void* sp) { return stk.contains(sp); }
char* spLimit() { return stk.spLimit(); }
char* lastSP() { return suspendedSP; }
bool isStackOverflow(char* sp) { return stk.isStackOverflow(sp); }
bool hadStackOverflow() { return stk.markDestroyed(); }
bool hasEmptyStack();
void resetStackOverflow() { stk.mark(); }
frame* last_self_frame(bool includePrologue, RegisterLocator** rl = NULL) {
return stk.last_self_frame(includePrologue, rl); }
void setPC(process_p newPC) { suspendedPC= first_inst_addr(newPC); }
bool isRunnable() { return state <= ready; }
processOop processObj() { return procObj; }
Stack* stack() { return &stk; }
// memory operations
void preserve(preservedVmObj* p);
void un_preserve(preservedVmObj* p);
void scavenge_contents();
void gc_mark_contents();
void gc_unmark_contents();
void verify();
void switch_pointers();
void read_snapshot(FILE* f);
void write_snapshot(FILE* f);
void chainFrames() { if (nesting > 0) stack()->chainFrames(); }
void unchainFrames() { if (nesting > 0) stack()->unchainFrames(); }
// programming operations
void convert();
// vframe mirror operations
vframeOop insertVFrameOop(vframeOop vfm);
vframeOop findVFrameOop(abstract_vframe* vfs);
vframeOop findInsertionPoint(abstract_vframe* vf);
protected:
void killVFrameOops(abstract_vframe* currentVF);
void killVFrameOopsInCurrentFrame(abstract_vframe* currentVF);
frame* frame_for_check_vfo_locals(abstract_vframe* currentVF);
void trace_killVFrameOopsInCurrentFrame(vframeOop, abstract_vframe*);
void set_check_vfo_locals( abstract_vframe* currentVF);
void clear_check_vfo_locals();
public:
void convertVFrameOops(frame* fr, frame* vfoLocals,
nmethod* invalidNM,
int32 vdepth, abstract_vframe** old_vf, abstract_vframe** new_vf);
void killVFrameOopsAndSetWatermark(frame* currentFrame);
void printVFrameList(fint howMany);
bool verifyVFrameList();
protected:
void clearWatermark();
void setWatermark(abstract_vframe*);
void traceAndLog_killVFrameOopsAndSetWatermark(frame*, abstract_vframe*);
void traceEpilog_killVFrameOopsAndSetWatermark();
// queuing
public:
void addAfter(Process* p) { next = p->next; p->next = this; }
void remove(Process* p) { p->next = next; next = NULL; }
};
bool isStackOverflow(char* sp);
bool isOnVMStack(void* sp);
extern frame* frameSwitchingToVMStack;
enum PreemptCause {
cNoCause = -1,
cTerminated, cAborted, cStackOverflowed, cNonLIFOBlock,
cLastFatalCause = cNonLIFOBlock,
cYielded,
cSingleStepped, cFinishedActivation,
cSignal,
cLowOnSpace,
cCouldntAllocateStack, // this isn't really a source of preemption; the
// process never got started
cLast // insert new causes before this line
};
inline bool isFatalCause(PreemptCause c) {
return c <= cLastFatalCause && c != cNoCause; }
extern PreemptCause preemptCause;
extern int32 causeString[cLast]; // translates PreemptCause --> VMString index
extern oop yieldArg; // argument passed with _Yield
extern oop yieldRcvr; // receiver of _Yield
class Processes: public CHeapObj {
public:
bool idle;
bool needsInvalidate; // needs to mark invalid stack frames
Processes();
void startVMProcess(); // init and start; won't return!
void discardAll();
void processesDo(processesDoFn f, bool doItForAll = false);
bool isIdle() { return idle; }
void print();
// memory operations
void scavenge_contents();
void gc_mark_contents();
void gc_unmark_contents();
void gc_mark_remaining_processes();
void enumerate_references(enumeration *e);
void enumerate_families(enumeration *e);
void verify();
void switch_pointers(oop from, oop to);
void read_snapshot(FILE* f);
void write_snapshot(FILE* f);
void chainFrames();
void unchainFrames();
objVectorOop zombies();
// programming
void convert(); // convert all stacks after programming change
void convert_cont();
// son-of operation
Stack* stackFor(void* f) {
// try it the fast way (covers almost all calls)
return currentProcess->contains(f) || isOnVMStack(f)
? currentProcess->stack()
: slowStackFor(f); // have to do it the slow way
}
private:
void init();
Stack* slowStackFor(void* f);
public:
friend void doTerminateAll_VM();
friend void doAbortAll_VM();
friend void doDiscardAll_VM();
};
extern Processes* processes;
oop zombie_prim();
void preemptor(); // set up things to preempt Self process
void interruptCheck();
inline char* allocateResource(size_t size) {
return currentProcess->resource_area.allocate_bytes(size);
}
// stack-switching functions; execute the continuation function on the VM stack
void switchToVMStack(doFn continuation);
oop switchToVMStack(fntype continuation, void* arg1);
nmethod* switchToVMStack(nmethod *cont(compilingLookup *),
compilingLookup *L);
typedef nmethod* (*constructDoItMethodContinuation)(oop receiver, oop method);
nmethod* switchToVMStack(oop receiver,
oop method,
constructDoItMethodContinuation continuation);
typedef void (*intLookupContinuation)( simpleLookup* L, int32 arg_count );
void switchToVMStack_intSend( simpleLookup* L,
int32 arg_count,
intLookupContinuation continuation);