mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 13:45:27 +00:00
1095 lines
27 KiB
C++
1095 lines
27 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.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
/* file: abenv.cpp
|
|
** Most portions derive from public domain IronDoc code and interfaces.
|
|
**
|
|
** Changes:
|
|
** <1> 05Feb1998 first implementation
|
|
** <0> 23Dec1997 first interface draft
|
|
*/
|
|
|
|
#ifndef _ABTABLE_
|
|
#include "abtable.h"
|
|
#endif
|
|
|
|
#ifndef _ABMODEL_
|
|
#include "abmodel.h"
|
|
#endif
|
|
|
|
#include "xp_mem.h"
|
|
|
|
|
|
/*3456789_123456789_123456789_123456789_123456789_123456789_123456789_12345678*/
|
|
|
|
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
|
|
|
|
|
|
#if AB_CONFIG_TRACE_orDEBUG_orPRINT
|
|
static const char* ab_Env_kClassName /*i*/ = "ab_Env";
|
|
#endif /* end AB_CONFIG_TRACE_orDEBUG_orPRINT*/
|
|
|
|
|
|
#if AB_CONFIG_TRACE_orDEBUG_orPRINT
|
|
static const char* AB_Env_kClassName /*i*/ = "AB_Env";
|
|
#endif /* end AB_CONFIG_TRACE_orDEBUG_orPRINT*/
|
|
|
|
|
|
// ````` ````` ````` ````` ````` ````` ````` `````
|
|
// virtual ab_Object methods
|
|
char* ab_Env::ObjectAsString(ab_Env* ev, char* outXmlBuf) const /*i*/
|
|
{
|
|
AB_USED_PARAMS_1(ev);
|
|
#if AB_CONFIG_TRACE_orDEBUG_orPRINT
|
|
// copied from public domain IronDoc:
|
|
char debugFlags[ 5 ];
|
|
char printFlags[ 5 ];
|
|
|
|
debugFlags[ 0 ] = (mEnv_Self.sEnv_DoTrace)? 'T' : 't';
|
|
debugFlags[ 1 ] = (mEnv_Self.sEnv_DoDebug)? 'D' : 'd';
|
|
debugFlags[ 2 ] = (mEnv_Self.sEnv_DoErrBreak)? 'E' : 'e';
|
|
debugFlags[ 3 ] = (mEnv_Self.sEnv_BeParanoid)? 'P' : 'p';
|
|
debugFlags[ 4 ] = '\0';
|
|
|
|
printFlags[ 0 ] = (mEnv_BeShallow)? 'S' : 's';
|
|
printFlags[ 1 ] = (mEnv_BeComplete)? 'C' : 'c';
|
|
printFlags[ 2 ] = (mEnv_BeConcise)? 'I' : 'i';
|
|
printFlags[ 3 ] = (mEnv_BeVerbose)? 'V' : 'v';
|
|
printFlags[ 4 ] = '\0';
|
|
|
|
XP_SPRINTF(outXmlBuf,
|
|
"<ab_Env:str me=\"^%lX\" d:t=\"^%lX:^%lX\" d:p=\"%.4s:%.4s\" fc=\"%lu\" sr=\"^%lX\" md=\"%lu\" rc=\"%lu\" a=\"%.9s\" u=\"%.9s\"/>",
|
|
(long) this, // me=\"^%lX\"
|
|
(long) mEnv_Debugger, // d:t=\"^%lX:
|
|
(long) mEnv_Tracer, // :^%lX\"
|
|
debugFlags, // d:p=\"%.4s
|
|
printFlags, // :%.4s\"
|
|
(long) mEnv_Self.sEnv_FaultCount, // fc=\"%lu\"
|
|
(long) mEnv_StackRef, // sr=\"^%lX\"
|
|
(long) mEnv_MaxRefDelta, // md=\"%lu\"
|
|
(unsigned long) mObject_RefCount, // rc=\"%lu\"
|
|
this->GetObjectAccessAsString(), // ac=\"%.9s\"
|
|
this->GetObjectUsageAsString() // us=\"%.9s\"
|
|
);
|
|
#else
|
|
*outXmlBuf = 0; /* empty string */
|
|
#endif /*AB_CONFIG_TRACE_orDEBUG_orPRINT*/
|
|
return outXmlBuf;
|
|
}
|
|
|
|
void ab_Env::CloseObject(ab_Env* ev) /*i*/
|
|
{
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
this->MarkClosing();
|
|
this->CloseEnv(ev);
|
|
this->MarkShut();
|
|
}
|
|
}
|
|
|
|
void ab_Env::PrintObject(ab_Env* ev, ab_Printer* ioPrinter) const /*i*/
|
|
{
|
|
#ifdef AB_CONFIG_PRINT
|
|
ioPrinter->PutString(ev, "<ab_Env>");
|
|
char xmlBuf[ ab_Object_kXmlBufSize + 2 ];
|
|
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
ioPrinter->PushDepth(ev); // indent all objects in the list
|
|
|
|
ioPrinter->NewlineIndent(ev, /*count*/ 1);
|
|
ioPrinter->PutString(ev, this->ObjectAsString(ev, xmlBuf));
|
|
|
|
if ( mEnv_Debugger )
|
|
{
|
|
ioPrinter->NewlineIndent(ev, /*count*/ 1);
|
|
mEnv_Debugger->PrintObject(ev, ioPrinter);
|
|
}
|
|
|
|
if ( mEnv_Tracer )
|
|
{
|
|
ioPrinter->NewlineIndent(ev, /*count*/ 1);
|
|
mEnv_Tracer->PrintObject(ev, ioPrinter);
|
|
}
|
|
|
|
ab_num stackTop = mEnv_StackTop;
|
|
if ( stackTop )
|
|
{
|
|
ioPrinter->Print(ev, "<ab_Env:faults top=\"%lu\">",
|
|
(long) stackTop);
|
|
ioPrinter->PushDepth(ev); // indent all objects in the list
|
|
|
|
if ( stackTop > ab_Env_kFaultMaxStackTop )
|
|
{
|
|
#ifdef AB_CONFIG_DEBUG
|
|
this->BreakObject(ev);
|
|
#endif /*AB_CONFIG_DEBUG*/
|
|
stackTop = ab_Env_kFaultMaxStackTop;
|
|
}
|
|
const AB_Fault* bottom = mEnv_FaultStack;
|
|
const AB_Fault* top = mEnv_FaultStack + stackTop;
|
|
|
|
while ( --top >= bottom )
|
|
{
|
|
ioPrinter->NewlineIndent(ev, /*count*/ 1);
|
|
ioPrinter->PutString(ev,
|
|
AB_Fault_AsXmlString(top, ev->AsSelf(), xmlBuf));
|
|
}
|
|
|
|
ioPrinter->PopDepth(ev); // stop indentation
|
|
ioPrinter->NewlineIndent(ev, /*count*/ 1);
|
|
ioPrinter->PutString(ev, "</ab_Env:faults>");
|
|
}
|
|
|
|
ioPrinter->PopDepth(ev); // stop indentation
|
|
}
|
|
else // use ab_Object::ObjectAsString() for non-objects:
|
|
{
|
|
ioPrinter->PutString(ev, this->ab_Object::ObjectAsString(ev, xmlBuf));
|
|
}
|
|
ioPrinter->NewlineIndent(ev, /*count*/ 1);
|
|
ioPrinter->PutString(ev, "</ab_Env>");
|
|
#endif /*AB_CONFIG_PRINT*/
|
|
}
|
|
|
|
ab_Env::~ab_Env()
|
|
{
|
|
AB_ASSERT(mEnv_Debugger==0);
|
|
AB_ASSERT(mEnv_Tracer==0);
|
|
#if AB_CONFIG_TRACE_orDEBUG_orPRINT
|
|
ab_Object* obj = mEnv_Debugger;
|
|
if ( obj )
|
|
obj->ObjectNotReleasedPanic(ab_Env_kClassName);
|
|
obj = mEnv_Tracer;
|
|
if ( obj )
|
|
obj->ObjectNotReleasedPanic(ab_Env_kClassName);
|
|
#endif /*AB_CONFIG_TRACE_orDEBUG_orPRINT*/
|
|
}
|
|
|
|
// ````` ````` ````` ````` ````` ````` ````` `````
|
|
// virtual ab_Env methods
|
|
|
|
ab_error_count ab_Env::CutAllFaults() /*i*/
|
|
{
|
|
ab_error_count outCount = 0;
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "CutAllFaults")
|
|
|
|
mEnv_Self.sEnv_FaultCount = 0;
|
|
mEnv_StackTop = 0;
|
|
ab_num stackSize = ab_Env_kFaultStackSlots * sizeof(AB_Fault);
|
|
AB_MEMSET(mEnv_FaultStack, 0, stackSize);
|
|
|
|
ab_Env_EndMethod(ev)
|
|
return outCount;
|
|
}
|
|
|
|
ab_error_count ab_Env::GetAllFaults(AB_Fault* outVector, /*i*/
|
|
ab_error_count inSize, ab_error_count* outLength) const
|
|
{
|
|
ab_error_count outCount = 0;
|
|
const ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "GetAllFaults")
|
|
|
|
outCount = mEnv_StackTop + 1;
|
|
if ( outCount > ab_Env_kFaultStackSlots )
|
|
outCount = ab_Env_kFaultStackSlots;
|
|
|
|
if ( inSize && outVector ) // any space to receive output?
|
|
{
|
|
if ( inSize > outCount ) // more than enough space?
|
|
inSize = outCount; // copy no more than have on hand
|
|
|
|
ab_num copySize = inSize * sizeof(AB_Fault);
|
|
AB_MEMCPY(outVector, mEnv_FaultStack, copySize);
|
|
if ( outLength ) // caller wants actual number copied?
|
|
*outLength = inSize;
|
|
}
|
|
|
|
ab_Env_EndMethod(ev)
|
|
return outCount;
|
|
}
|
|
|
|
#define abEnv_kStackDepthSlop 1024
|
|
|
|
ab_bool ab_Env::is_stack_depth_okay() const /*i*/
|
|
{
|
|
// copied from public domain IronDoc:
|
|
ab_bool outDepthOkay = AB_kTrue; /* default in case check is disabled */
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
ab_num maxDelta = mEnv_MaxRefDelta;
|
|
if ( maxDelta && mEnv_StackRef ) /* stack checking enabled? */
|
|
{
|
|
long delta = ((ab_u1*) mEnv_StackRef) - ((ab_u1*) &maxDelta);
|
|
if ( delta < 0 ) /* need to convert to absolute value? */
|
|
delta = -delta;
|
|
|
|
// add slop so to be more forgiving than abEnv::DefaultCheckStack(),
|
|
// so it is possible to notify of errors on soft stack overflow.
|
|
outDepthOkay = ( delta <= (maxDelta + abEnv_kStackDepthSlop) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
outDepthOkay = AB_kFalse; /* for a bad env, the stack is too deep */
|
|
this->ObjectPanic("is_stack_depth_okay env not open");
|
|
}
|
|
return outDepthOkay;
|
|
}
|
|
|
|
void ab_Env::error_notify(const AB_Fault* inFault) /*i*/
|
|
{
|
|
ab_Env* ev = this;
|
|
// copied from public domain IronDoc:
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
if ( this->is_stack_depth_okay() )
|
|
{
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "error_notify")
|
|
|
|
char buf[ AB_Fault_kXmlBufSize + 2 ];
|
|
AB_Fault_AsXmlString(inFault, ev->AsSelf(), buf);
|
|
|
|
#ifdef AB_CONFIG_DEBUG
|
|
if ( mEnv_Debugger && ev->DoErrorBreak() )
|
|
mEnv_Debugger->BreakString(ev, buf);
|
|
#endif /*AB_CONFIG_DEBUG*/
|
|
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( mEnv_Tracer && ev->DoTrace() )
|
|
mEnv_Tracer->TraceString(ev, buf);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
|
|
ab_Env_EndMethod(ev)
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if AB_CONFIG_TRACE_orDEBUG_orPRINT
|
|
AB_Env* cev = this->AsSelf();
|
|
char buf[ AB_Fault_kXmlBufSize + 2 ];
|
|
this->ObjectPanic(AB_Fault_AsXmlString(inFault, cev, buf));
|
|
#endif /* end AB_CONFIG_TRACE_orDEBUG_orPRINT*/
|
|
}
|
|
}
|
|
|
|
void ab_Env::push_error(ab_error_uid inCode, ab_u4 inSpace) /*i*/
|
|
{
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
// note: first fault is written on stack top without bumping pointer
|
|
ab_num top = mEnv_StackTop;
|
|
if ( mEnv_Self.sEnv_FaultCount ) // not the first recorded error?
|
|
++top;
|
|
|
|
++mEnv_Self.sEnv_FaultCount; // another error has occurred
|
|
|
|
if ( top < ab_Env_kFaultMaxStackTop ) // room for another error?
|
|
{
|
|
mEnv_StackTop = top;
|
|
AB_Fault* fault = mEnv_FaultStack + top;
|
|
AB_Fault_Init(fault, inCode, inSpace);
|
|
}
|
|
else
|
|
{
|
|
#ifdef AB_CONFIG_DEBUG
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "push_error")
|
|
|
|
ev->BreakString("dropping one error too many");
|
|
|
|
ab_Env_EndMethod(ev)
|
|
#endif /*AB_CONFIG_DEBUG*/
|
|
}
|
|
}
|
|
else this->ObjectPanic("ev not open");
|
|
}
|
|
|
|
ab_error_uid ab_Env::NewFault(ab_error_uid inCode, ab_u4 inSpace) /*i*/
|
|
{
|
|
AB_Fault fault;
|
|
AB_Fault_Init(&fault, inCode, inSpace);
|
|
this->error_notify(&fault);
|
|
this->push_error(inCode, inSpace); // untouched by ErrorNotify()
|
|
|
|
return inCode;
|
|
}
|
|
|
|
void ab_Env::BreakString(const char* inMessage) /*i*/
|
|
{
|
|
#ifdef AB_CONFIG_DEBUG
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
ab_Env* ev = this;
|
|
if ( mEnv_Debugger )
|
|
mEnv_Debugger->BreakString(ev, inMessage);
|
|
}
|
|
#endif /*AB_CONFIG_DEBUG*/
|
|
}
|
|
|
|
void ab_Env::TraceString(const char* inMessage) /*i*/
|
|
{
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
ab_Env* ev = this;
|
|
ab_Tracer* tracer = mEnv_Tracer;
|
|
if ( mEnv_Tracer && ev->DoTrace() )
|
|
mEnv_Tracer->TraceString(ev, inMessage);
|
|
}
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
}
|
|
|
|
// ````` ````` ````` ````` ````` ````` ````` `````
|
|
// public non-poly ab_Env methods
|
|
|
|
// ````` construction `````
|
|
ab_Env::ab_Env(const ab_Usage& inUsage) /*i*/
|
|
: ab_Object(inUsage),
|
|
mEnv_Debugger( 0 ),
|
|
mEnv_Tracer( 0 )
|
|
{
|
|
AB_MEMSET(&mEnv_Self, 0, sizeof(AB_Env));
|
|
}
|
|
|
|
ab_Env::ab_Env(const ab_Usage& inUsage, const ab_Env& other) /*i*/
|
|
: ab_Object(inUsage),
|
|
mEnv_Debugger( 0 ),
|
|
mEnv_Tracer( 0 )
|
|
{
|
|
ab_Env* ev = this;
|
|
|
|
// copy the flags from other's C struct AB_Env...
|
|
AB_MEMCPY(&mEnv_Self, &other.mEnv_Self, sizeof(AB_Env));
|
|
mEnv_Self.sEnv_FaultCount = 0; // ...but keep error count equal to zero
|
|
|
|
ab_Tracer* tracer = other.mEnv_Tracer;
|
|
if ( tracer && tracer->AcquireObject(ev) )
|
|
mEnv_Tracer = tracer;
|
|
|
|
ab_Debugger* debugger = other.mEnv_Debugger;
|
|
if ( ev->Good() && debugger && debugger->AcquireObject(ev) )
|
|
mEnv_Debugger = debugger;
|
|
}
|
|
|
|
ab_Env::ab_Env(const ab_Usage& inUsage, ab_Debugger* ioDebugger, /*i*/
|
|
ab_Tracer* ioTracer)
|
|
: ab_Object(inUsage),
|
|
mEnv_Debugger( 0 ),
|
|
mEnv_Tracer( 0 )
|
|
{
|
|
ab_Env* ev = this;
|
|
|
|
AB_MEMSET(&mEnv_Self, 0, sizeof(AB_Env)); // zero embedded C struct
|
|
|
|
if ( ioTracer && ioTracer->AcquireObject(ev) )
|
|
mEnv_Tracer = ioTracer;
|
|
|
|
if ( ev->Good() && ioDebugger && ioDebugger->AcquireObject(ev) )
|
|
mEnv_Debugger = ioDebugger;
|
|
}
|
|
|
|
// ````` standard logging env `````
|
|
|
|
static ab_Env* ab_Env_g_simple_env = 0; // for ab_Env::GetSimpleEnv() use
|
|
|
|
/*static*/
|
|
ab_Env* ab_Env::GetSimpleEnv() /*i*/
|
|
// This env just has a debugger instance installed. It is used
|
|
// when instantiating the standard session log file objects. This
|
|
// env is installed as the top panic env when first instantiated.
|
|
// (Please, never close this env instance.)
|
|
{
|
|
ab_Env* outEnv = ab_Env_g_simple_env;
|
|
|
|
if ( !outEnv )
|
|
{
|
|
ab_Env* nullEnv = 0; // note operator new() accounts
|
|
outEnv = new(*nullEnv) ab_Env(ab_Usage::GetHeap());
|
|
}
|
|
|
|
if ( outEnv && outEnv->Bad() )
|
|
outEnv->CutAllFaults();
|
|
|
|
if ( outEnv && !outEnv->mEnv_Debugger )
|
|
{
|
|
ab_Debugger* debugger = new(*outEnv) ab_Debugger(ab_Usage::GetHeap());
|
|
if ( debugger )
|
|
{
|
|
if ( outEnv->Good() )
|
|
{
|
|
outEnv->mEnv_Debugger = debugger;
|
|
#ifdef AB_CONFIG_DEBUG
|
|
outEnv->mEnv_Self.sEnv_DoDebug = AB_kTrue;
|
|
outEnv->mEnv_Self.sEnv_DoErrBreak = AB_kTrue;
|
|
outEnv->mEnv_Self.sEnv_BeParanoid = AB_kTrue;
|
|
#endif /*AB_CONFIG_DEBUG*/
|
|
}
|
|
else
|
|
debugger->ReleaseObject(outEnv);
|
|
}
|
|
}
|
|
if ( outEnv && !ab_Env_g_simple_env )
|
|
{
|
|
ab_Env_g_simple_env = outEnv;
|
|
outEnv->AcquireObject(outEnv);
|
|
|
|
ab_Object::PushPanicEnv(outEnv, outEnv);
|
|
}
|
|
return outEnv;
|
|
}
|
|
|
|
static ab_Env* ab_Env_g_log_file_env = 0; // for ab_Env::GetLogFileEnv() use
|
|
|
|
/*static*/
|
|
ab_Env* ab_Env::GetLogFileEnv() /*i*/
|
|
// standard session log env (uses ab_StdioFile::GetLogStdioFile()).
|
|
// This uses standard session debugger, tracer, printer, etc.
|
|
// (Please, never close this env instance.)
|
|
{
|
|
ab_Env* outEnv = ab_Env_g_log_file_env;
|
|
if ( !outEnv )
|
|
{
|
|
ab_Env* simpleEv = ab_Env::GetSimpleEnv();
|
|
if ( simpleEv )
|
|
{
|
|
ab_Debugger* d = ab_Debugger::GetLogFileDebugger(simpleEv);
|
|
if ( d )
|
|
{
|
|
ab_Tracer* t = ab_FileTracer::GetLogFileTracer(simpleEv);
|
|
if ( t )
|
|
{
|
|
outEnv = new(*simpleEv) ab_Env(ab_Usage::GetHeap(), d, t);
|
|
if ( outEnv )
|
|
outEnv->AcquireObject(outEnv);
|
|
}
|
|
}
|
|
}
|
|
if ( outEnv )
|
|
{
|
|
int localVar = 0; // lives somewhere on stack
|
|
outEnv->SetStackControl(&localVar, ab_Env_kDefaultMaxRefDelta);
|
|
|
|
#if AB_CONFIG_TRACE_andLOGGING
|
|
outEnv->mEnv_Self.sEnv_DoTrace = AB_kTrue;
|
|
#endif /*AB_CONFIG_TRACE_andLOGGING*/
|
|
|
|
#ifdef AB_CONFIG_DEBUG
|
|
outEnv->mEnv_Self.sEnv_DoDebug = AB_kTrue;
|
|
outEnv->mEnv_Self.sEnv_DoErrBreak = AB_kTrue;
|
|
outEnv->mEnv_Self.sEnv_BeParanoid = AB_kTrue;
|
|
#endif /*AB_CONFIG_DEBUG*/
|
|
|
|
ab_Env_g_log_file_env = outEnv;
|
|
outEnv->AcquireObject(outEnv);
|
|
|
|
ab_Object::PushPanicEnv(outEnv, outEnv);
|
|
|
|
#if AB_CONFIG_TRACE_andLOGGING
|
|
if ( outEnv->DoTrace() )
|
|
outEnv->TraceObject(outEnv);
|
|
#endif /*AB_CONFIG_TRACE_andLOGGING*/
|
|
|
|
#ifdef AB_CONFIG_PRINT
|
|
ab_Printer* printer = ab_FilePrinter::GetLogFilePrinter(outEnv);
|
|
if ( printer )
|
|
{
|
|
outEnv->PrintObject(outEnv, printer);
|
|
printer->Flush(outEnv);
|
|
}
|
|
#ifdef AB_CONFIG_DEBUG
|
|
else outEnv->Break("no log printer");
|
|
#endif /*AB_CONFIG_DEBUG*/
|
|
|
|
#endif /*AB_CONFIG_PRINT*/
|
|
}
|
|
}
|
|
|
|
return outEnv;
|
|
}
|
|
|
|
// ````` ````` begin class to statically make log class instances ````` `````
|
|
#if AB_CONFIG_TRACE_orDEBUG_orPRINT && defined(USE_STATIC_TWIDDLER)
|
|
class ab_EnvStaticTwiddler {
|
|
public:
|
|
ab_Env* mEnvStaticTwiddler_LogEnv;
|
|
public:
|
|
ab_EnvStaticTwiddler();
|
|
~ab_EnvStaticTwiddler();
|
|
};
|
|
|
|
ab_EnvStaticTwiddler::ab_EnvStaticTwiddler()
|
|
{
|
|
mEnvStaticTwiddler_LogEnv = ab_Env::GetLogFileEnv();
|
|
if ( mEnvStaticTwiddler_LogEnv )
|
|
{
|
|
ab_Env* simple = ab_Env::GetSimpleEnv();
|
|
mEnvStaticTwiddler_LogEnv->AcquireObject(simple);
|
|
}
|
|
}
|
|
|
|
ab_EnvStaticTwiddler::~ab_EnvStaticTwiddler()
|
|
{
|
|
mEnvStaticTwiddler_LogEnv = 0;
|
|
|
|
ab_Env* ev = ab_Object::TopPanicEnv();
|
|
if ( ev && ev->IsOpenObject() )
|
|
{
|
|
ab_Env_BeginMethod(ev, "ab_EnvStaticTwiddler", "~ab_EnvStaticTwiddler")
|
|
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
ev->TraceObject(ev);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
|
|
ab_Env_EndMethod(ev)
|
|
|
|
ab_Printer* printer = ab_FilePrinter::GetLogFilePrinter(ev);
|
|
if ( printer )
|
|
{
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
printer->TraceObject(ev);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
printer->Flush(ev);
|
|
}
|
|
ab_Tracer* tracer = ab_FileTracer::GetLogFileTracer(ev);
|
|
if ( tracer )
|
|
{
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
tracer->TraceObject(ev);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
tracer->Flush(ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
ab_EnvStaticTwiddler ab_EnvStaticTwiddler_gStaticInstance;
|
|
#endif /* end AB_CONFIG_TRACE_orDEBUG_orPRINT && use-static-twiddler */
|
|
// ````` ````` end class to statically make log class instances ````` `````
|
|
|
|
|
|
// ````` destruction `````
|
|
void ab_Env::CloseEnv(ab_Env* ev) /*i*/
|
|
{
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "CloseEnv")
|
|
|
|
ab_Object*obj = mEnv_Debugger;
|
|
if ( obj )
|
|
{
|
|
mEnv_Debugger = 0;
|
|
obj->ReleaseObject(ev);
|
|
}
|
|
|
|
obj = mEnv_Tracer;
|
|
if ( obj )
|
|
{
|
|
mEnv_Tracer = 0;
|
|
obj->ReleaseObject(ev);
|
|
}
|
|
|
|
ab_Env_EndMethod(ev)
|
|
}
|
|
|
|
|
|
// ````` tagged memory management `````
|
|
void* ab_Env::HeapSafeTagAlloc(ab_num inSize) /*i*/
|
|
{
|
|
void* outAddress = 0;
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "HeapSafeTagAlloc")
|
|
|
|
if ( !inSize )
|
|
inSize = 1;
|
|
|
|
ab_u4* tag = (ab_u4*) XP_ALLOC(inSize + sizeof(ab_u4));
|
|
if ( tag )
|
|
{
|
|
*tag = ab_Env_kHeapSafeTag; // install magic tag for later use
|
|
outAddress = tag + 1; // slot after tag slot
|
|
}
|
|
else
|
|
ev->NewAbookFault(AB_Table_kFaultOutOfMemory);
|
|
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
ev->Trace("<ab_Env::HeapSafeTagAlloc at=\"^%lX\" sz=\"%lu\"/>",
|
|
(long) outAddress, (long) inSize);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
|
|
ab_Env_EndMethod(ev)
|
|
return outAddress;
|
|
}
|
|
|
|
void ab_Env::HeapSafeTagFree(void* ioAddress) /*i*/
|
|
{
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "HeapSafeTagFree")
|
|
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
ev->Trace("<ab_Env::HeapSafeTagFree at=\"^%lX\" />",
|
|
(long) ioAddress);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
|
|
if ( ioAddress )
|
|
{
|
|
ab_u4* tag = ((ab_u4*) ioAddress) - 1; // u4 slot before address
|
|
if ( *tag == ab_Env_kHeapSafeTag ) // has expected leading tag?
|
|
{
|
|
XP_FREE(tag); // only free when the tag is correct
|
|
}
|
|
else
|
|
ev->Break("<ab_Env::HeapSafeTagFree tag=\"%.4s\"/>", (char*) tag);
|
|
}
|
|
|
|
ab_Env_EndMethod(ev)
|
|
}
|
|
|
|
/*static*/
|
|
ab_bool ab_Env::GoodHeapSafeTag(void* ioAddress)
|
|
{
|
|
if ( ioAddress )
|
|
{
|
|
// take care not to act upon an illegally aligned address for a u4:
|
|
ab_u4 expected = ab_Env_kHeapSafeTag;
|
|
ab_u1* want = (ab_u1*) &expected;
|
|
ab_u1* actual = (ab_u1*) (((ab_u4*) ioAddress) - 1);
|
|
return ( want[ 0 ] == actual[ 0 ] &&
|
|
want[ 1 ] == actual[ 1 ] &&
|
|
want[ 2 ] == actual[ 2 ] &&
|
|
want[ 3 ] == actual[ 3 ] );
|
|
}
|
|
return AB_kFalse;
|
|
}
|
|
|
|
// ````` memory management `````
|
|
void* ab_Env::HeapAlloc(ab_num inSize) /*i*/
|
|
{
|
|
void* outAddress = 0;
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "HeapAlloc")
|
|
|
|
if ( !inSize )
|
|
inSize = 1;
|
|
|
|
outAddress = XP_ALLOC(inSize);
|
|
if ( !outAddress )
|
|
ev->NewAbookFault(AB_Table_kFaultOutOfMemory);
|
|
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
ev->Trace("<ab_Env::HeapAlloc at=\"^%lX\" sz=\"%lu\"/>",
|
|
(long) outAddress, (long) inSize);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
|
|
ab_Env_EndMethod(ev)
|
|
return outAddress;
|
|
}
|
|
|
|
void ab_Env::HeapFree(void* ioAddress) /*i*/
|
|
{
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "HeapFree")
|
|
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
ev->Trace("<ab_Env::HeapFree at=\"^%lX\" />",
|
|
(long) ioAddress);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
|
|
if ( ioAddress )
|
|
XP_FREE(ioAddress);
|
|
|
|
ab_Env_EndMethod(ev)
|
|
}
|
|
|
|
char* ab_Env::CopyString(const char* inStringToCopy) /*i*/
|
|
{
|
|
char* outString = 0;
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "CopyString")
|
|
|
|
if ( !inStringToCopy )
|
|
inStringToCopy = "";
|
|
|
|
ab_num length = XP_STRLEN(inStringToCopy);
|
|
|
|
outString = (char*) XP_ALLOC(length + 1);
|
|
if ( outString )
|
|
{
|
|
XP_STRCPY(outString, inStringToCopy);
|
|
}
|
|
else ev->NewAbookFault(AB_Table_kFaultOutOfMemory);
|
|
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
ev->Trace(
|
|
"<ab_Env::CopyString at=\"^%lX\" in=\"%.128s\" len=\"%lu\"/>",
|
|
(long) outString, inStringToCopy, (long) length);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
|
|
ab_Env_EndMethod(ev)
|
|
return outString;
|
|
}
|
|
|
|
void ab_Env::FreeString(char* ioStringToFree) /*i*/
|
|
{
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "FreeString")
|
|
|
|
if ( ioStringToFree )
|
|
{
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
ev->Trace("<ab_Env::FreeString at=\"^%lX\" io=\"%.128s\"/>",
|
|
(long) ioStringToFree, ioStringToFree);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
|
|
XP_FREE(ioStringToFree);
|
|
}
|
|
|
|
ab_Env_EndMethod(ev)
|
|
}
|
|
|
|
// ````` fault creation covers `````
|
|
|
|
void ab_Env::NewAbookFault(ab_error_uid faultCode) /*i*/
|
|
{
|
|
this->NewFault(faultCode, /*space*/ AB_Fault_kAbookSpace);
|
|
}
|
|
// ````` fault access `````
|
|
|
|
ab_error_count ab_Env::GetAllErrors(ab_error_uid* outVector, /*i*/
|
|
ab_error_count inSize, ab_error_count* outLength)
|
|
{
|
|
ab_num outCount = mEnv_Self.sEnv_FaultCount;
|
|
if ( outCount > ab_Env_kFaultStackSlots )
|
|
outCount = ab_Env_kFaultStackSlots;
|
|
|
|
ab_num copyCount = outCount;
|
|
if ( copyCount > inSize )
|
|
copyCount = inSize;
|
|
|
|
if ( copyCount && outVector )
|
|
{
|
|
AB_MEMCPY(outVector, mEnv_FaultStack, copyCount * sizeof(AB_Fault));
|
|
}
|
|
if ( outLength )
|
|
*outLength = copyCount;
|
|
return outCount;
|
|
}
|
|
|
|
// ````` debugging covers `````
|
|
void ab_Env::Break(const char* inFormat, ...) /*i*/
|
|
{
|
|
#ifdef AB_CONFIG_DEBUG
|
|
// copied from public domain IronDoc
|
|
ab_Env* ev = this;
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
ab_Debugger* debugger = mEnv_Debugger;
|
|
if ( debugger )
|
|
{
|
|
char buf[ AB_Env_kFormatBufferSize ];
|
|
va_list args;
|
|
va_start(args,inFormat);
|
|
PR_vsnprintf(buf, AB_Env_kFormatBufferSize, inFormat, args);
|
|
va_end(args);
|
|
|
|
debugger->BreakString(ev, buf);
|
|
}
|
|
}
|
|
|
|
#endif /*AB_CONFIG_DEBUG*/
|
|
}
|
|
|
|
// ````` tracing covers `````
|
|
|
|
#ifdef AB_CONFIG_TRACE
|
|
void ab_Env::Trace(const char* inFormat, ...) /*i*/
|
|
{
|
|
// copied from public domain IronDoc
|
|
ab_Env* ev = this;
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
ab_Tracer* tracer = mEnv_Tracer;
|
|
if ( tracer && ev->DoTrace() )
|
|
{
|
|
char buf[ AB_Env_kFormatBufferSize ];
|
|
va_list args;
|
|
va_start(args,inFormat);
|
|
PR_vsnprintf(buf, AB_Env_kFormatBufferSize, inFormat, args);
|
|
va_end(args);
|
|
|
|
tracer->TraceString(ev, buf);
|
|
}
|
|
}
|
|
}
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
|
|
void ab_Env::TraceBeginMethod(const char* inClass,
|
|
const char* inMethod) const /*i*/
|
|
{
|
|
ab_Env* ev = (ab_Env*) this; // cast away const
|
|
|
|
// copied from public domain IronDoc
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
ab_Tracer* tracer = mEnv_Tracer;
|
|
if ( tracer && ev->DoTrace() )
|
|
{
|
|
tracer->BeginMethod(ev, inClass, inMethod);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ab_Env::TraceEndMethod() const /*i*/
|
|
{
|
|
ab_Env* ev = (ab_Env*) this; // cast away const
|
|
|
|
// copied from public domain IronDoc
|
|
if ( this->IsOpenObject() )
|
|
{
|
|
ab_Tracer* tracer = mEnv_Tracer;
|
|
if ( tracer && ev->DoTrace() )
|
|
{
|
|
tracer->EndMethod(ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ````` member access `````
|
|
void ab_Env::ChangeDebugger(ab_Debugger* ioDebugger) /*i*/
|
|
{
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "ChangeDebugger")
|
|
|
|
if ( ev->Good() && ev->IsOpenObject() )
|
|
{
|
|
if ( ioDebugger )
|
|
ioDebugger->AcquireObject(ev);
|
|
if ( ev->Good() )
|
|
{
|
|
if ( mEnv_Debugger )
|
|
mEnv_Debugger->ReleaseObject(ev);
|
|
mEnv_Debugger = ioDebugger;
|
|
}
|
|
}
|
|
|
|
ab_Env_EndMethod(ev)
|
|
}
|
|
|
|
void ab_Env::ChangeTracer(ab_Tracer* ioTracer) /*i*/
|
|
{
|
|
ab_Env* ev = this;
|
|
ab_Env_BeginMethod(ev, ab_Env_kClassName, "ChangeTracer")
|
|
|
|
if ( ev->Good() && this->IsOpenObject() )
|
|
{
|
|
if ( ioTracer )
|
|
ioTracer->AcquireObject(ev);
|
|
if ( ev->Good() )
|
|
{
|
|
if ( mEnv_Tracer )
|
|
mEnv_Tracer->ReleaseObject(ev);
|
|
mEnv_Tracer = ioTracer;
|
|
}
|
|
}
|
|
|
|
ab_Env_EndMethod(ev)
|
|
}
|
|
|
|
/* ----- ----- ----- ----- C Env ----- ----- ----- ----- */
|
|
|
|
/* ----- ----- creation / ref counting ----- ----- */
|
|
|
|
AB_API_IMPL(AB_Env*) /* abenv.cpp */
|
|
AB_Env_New() /*i*/
|
|
{
|
|
AB_Env* outEnv = 0;
|
|
#ifdef AB_CONFIG_LOGGING
|
|
ab_Env* ev = ab_Env::GetLogFileEnv();
|
|
#else /*AB_CONFIG_LOGGING*/
|
|
ab_Env* ev = ab_Env::GetSimpleEnv();
|
|
#endif /*AB_CONFIG_LOGGING*/
|
|
if ( ev )
|
|
{
|
|
ab_Env_BeginMethod(ev, AB_Env_kClassName, "New")
|
|
|
|
ab_Env* copyEnv = new(*ev) ab_Env(ab_Usage::GetHeap(), *ev);
|
|
if ( copyEnv )
|
|
{
|
|
outEnv = copyEnv->AsSelf();
|
|
|
|
#ifdef AB_CONFIG_TRACE
|
|
if ( ev->DoTrace() )
|
|
copyEnv->TraceObject(ev);
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
}
|
|
ab_Env_EndMethod(ev)
|
|
}
|
|
return outEnv;
|
|
}
|
|
|
|
AB_API_IMPL(AB_Env*) /* abenv.cpp */
|
|
AB_Env_GetLogFileEnv() /*i*/
|
|
{
|
|
AB_Env* outEnv = 0;
|
|
ab_Env* ev = ab_Env::GetLogFileEnv();
|
|
if ( ev )
|
|
{
|
|
outEnv = ev->AsSelf();
|
|
}
|
|
return outEnv;
|
|
}
|
|
|
|
AB_API_IMPL(ab_ref_count) /* abenv.cpp */
|
|
AB_Env_Acquire(AB_Env* self) /*i*/
|
|
{
|
|
ab_Env* ev = ab_Env::AsThis(self);
|
|
return ev->AcquireObject(ev);
|
|
}
|
|
|
|
AB_API_IMPL(ab_ref_count) /* abenv.cpp */
|
|
AB_Env_Release(AB_Env* self) /*i*/
|
|
{
|
|
ab_Env* ev = ab_Env::AsThis(self);
|
|
return ev->ReleaseObject(ev);
|
|
}
|
|
|
|
/* ----- ----- error access ----- ----- */
|
|
|
|
AB_API_IMPL(ab_error_count) /* abenv.cpp */
|
|
AB_Env_ForgetErrors(AB_Env* self) /*i*/
|
|
/*- Discard all error information. -*/
|
|
{
|
|
ab_Env* ev = ab_Env::AsThis(self);
|
|
return ev->CutAllFaults();
|
|
}
|
|
|
|
AB_API_IMPL(ab_error_count) /* abenv.cpp */
|
|
AB_Env_ErrorCount(const AB_Env* self) /*i*/
|
|
/*- Number of errors since last forget/reset. -*/
|
|
{
|
|
AB_Env* mutableSelf = (AB_Env*) self; // cast away const
|
|
ab_Env* ev = ab_Env::AsThis(mutableSelf);
|
|
return ev->ErrorCount();
|
|
}
|
|
|
|
AB_API_IMPL(ab_error_uid) /* abenv.cpp */
|
|
AB_Env_GetError(const AB_Env* self) /*i*/
|
|
/*- Last error since forget/reset, otherwise zero. -*/
|
|
{
|
|
AB_Env* mutableSelf = (AB_Env*) self; // cast away const
|
|
ab_Env* ev = ab_Env::AsThis(mutableSelf);
|
|
return ev->GetError();
|
|
}
|
|
|
|
AB_API_IMPL(ab_error_count) /* abenv.cpp */
|
|
AB_Env_GetAllErrors(const AB_Env* self, ab_error_uid* outVector, /*i*/
|
|
ab_error_count inSize, ab_error_count* outLength)
|
|
/*- All errors (up to inSize) since forget/reset. -*/
|
|
{
|
|
AB_Env* mutableSelf = (AB_Env*) self; // cast away const
|
|
ab_Env* ev = ab_Env::AsThis(mutableSelf);
|
|
return ev->GetAllErrors(outVector, inSize, outLength);
|
|
}
|
|
|
|
|
|
AB_API_IMPL(ab_error_uid) /* abenv.cpp */
|
|
AB_Env_NewFault(AB_Env* self, ab_error_uid inFaultCode, /*i*/
|
|
ab_u4 inFaultSpace)
|
|
{
|
|
ab_Env* ev = ab_Env::AsThis(self);
|
|
return ev->NewFault(inFaultCode, inFaultSpace);
|
|
}
|
|
|
|
/* ----- ----- static dispatching methods ----- ----- */
|
|
|
|
AB_API_IMPL(ab_error_uid) /* abenv.cpp */
|
|
AB_Env_NewAbookFault(AB_Env* self, ab_error_uid inFaultCode) /*i*/
|
|
{
|
|
ab_Env* ev = ab_Env::AsThis(self);
|
|
ev->NewAbookFault(inFaultCode);
|
|
return inFaultCode;
|
|
}
|
|
|
|
AB_API_IMPL(void) /* abenv.cpp */
|
|
AB_Env_Break(AB_Env* self, const char* inFormat, ...) /*i*/
|
|
{
|
|
#ifdef AB_CONFIG_DEBUG
|
|
ab_Env* ev = ab_Env::AsThis(self);
|
|
ab_Env_BeginMethod(ev, AB_Env_kClassName, "Break")
|
|
|
|
if ( ev->IsOpenObject() )
|
|
{
|
|
char buf[ AB_Env_kFormatBufferSize ];
|
|
va_list args;
|
|
va_start(args,inFormat);
|
|
PR_vsnprintf(buf, AB_Env_kFormatBufferSize, inFormat, args);
|
|
va_end(args);
|
|
|
|
ev->BreakString(buf);
|
|
}
|
|
ab_Env_EndMethod(ev)
|
|
#endif /*AB_CONFIG_DEBUG*/
|
|
}
|
|
|
|
AB_API_IMPL(void) /* abenv.cpp */
|
|
AB_Env_Trace(AB_Env* self, const char* inFormat, ...) /*i*/
|
|
{
|
|
#ifdef AB_CONFIG_TRACE
|
|
ab_Env* ev = ab_Env::AsThis(self);
|
|
ab_Env_BeginMethod(ev, AB_Env_kClassName, "Trace")
|
|
|
|
if ( ev->IsOpenObject() )
|
|
{
|
|
char buf[ AB_Env_kFormatBufferSize ];
|
|
va_list args;
|
|
va_start(args,inFormat);
|
|
PR_vsnprintf(buf, AB_Env_kFormatBufferSize, inFormat, args);
|
|
va_end(args);
|
|
|
|
ev->TraceString(buf);
|
|
}
|
|
ab_Env_EndMethod(ev)
|
|
#endif /*AB_CONFIG_TRACE*/
|
|
}
|
|
|
|
AB_API_IMPL(void) /* abenv.cpp */
|
|
AB_Env_TraceBeginMethod(const AB_Env* self, const char* inClass, /*i*/
|
|
const char* inMethod)
|
|
{
|
|
AB_Env* mutableSelf = (AB_Env*) self; // cast away const
|
|
ab_Env* ev = ab_Env::AsThis(mutableSelf);
|
|
ev->TraceBeginMethod(inClass, inMethod);
|
|
}
|
|
|
|
AB_API_IMPL(void) /* abenv.cpp */
|
|
AB_Env_TraceEndMethod(const AB_Env* self) /*i*/
|
|
{
|
|
AB_Env* mutableSelf = (AB_Env*) self; // cast away const
|
|
ab_Env* ev = ab_Env::AsThis(mutableSelf);
|
|
ev->TraceEndMethod();
|
|
}
|
|
|
|
|