diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2024-05-17 11:11:31 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2024-05-17 11:11:31 (GMT) |
commit | aa585c0ac925c9ca50a5a98d65e576eb93e5afcc (patch) | |
tree | c1a422bae6bd399596beffb276fb59729a091e63 /generic | |
parent | 71e8e7a16883b76aaf0d406d59c8799f5c50b157 (diff) | |
download | tcl-aa585c0ac925c9ca50a5a98d65e576eb93e5afcc.zip tcl-aa585c0ac925c9ca50a5a98d65e576eb93e5afcc.tar.gz tcl-aa585c0ac925c9ca50a5a98d65e576eb93e5afcc.tar.bz2 |
Starting to clean up the mess. The extra frame info can have the same lifespan as the method itself.
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclOOInt.h | 9 | ||||
-rw-r--r-- | generic/tclOOMethod.c | 136 |
2 files changed, 91 insertions, 54 deletions
diff --git a/generic/tclOOInt.h b/generic/tclOOInt.h index 2931044..e7d727a 100644 --- a/generic/tclOOInt.h +++ b/generic/tclOOInt.h @@ -97,6 +97,15 @@ typedef struct ProcedureMethod { GetFrameInfoValueProc *gfivProc; /* Callback to allow for fine tuning of how * the method reports itself. */ + ExtraFrameInfo efi; /* Space used to store data for [info frame] */ + Tcl_Interp *interp; /* Interpreter in which to compute the name of + * the method. */ + Tcl_Method method; /* Method to compute the name of. */ + int callSiteFlags; /* Flags from the call chain. Only interested + * in whether this is a constructor or + * destructor, which we can't know until then + * for messy reasons. Other flags are variable + * but not used. */ } ProcedureMethod; #define TCLOO_PROCEDURE_METHOD_VERSION 0 diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c index edaa593..1347aa5 100644 --- a/generic/tclOOMethod.c +++ b/generic/tclOOMethod.c @@ -17,17 +17,6 @@ #include "tclCompile.h" /* - * Structure used to help delay computing names of objects or classes for - * [info frame] until needed, making invocation faster in the normal case. - */ - -struct PNI { - Tcl_Interp *interp; /* Interpreter in which to compute the name of - * a method. */ - Tcl_Method method; /* Method to compute the name of. */ -}; - -/* * Structure used to contain all the information needed about a call frame * used in a procedure-like method. */ @@ -38,11 +27,8 @@ typedef struct { ProcErrorProc *errProc; /* The error handler for the body. */ Tcl_Obj *nameObj; /* The "name" of the command. */ Command cmd; /* The command structure. Mostly bogus. */ - ExtraFrameInfo efi; /* Extra information used for [info frame]. */ Command *oldCmdPtr; /* Saved cmdPtr so that we can be safe after a * recursive call returns. */ - struct PNI pni; /* Specialist information used in the efi - * field for this type of call. */ } PMFrameData; /* @@ -86,6 +72,9 @@ static void ConstructorErrorHandler(Tcl_Interp *interp, Tcl_Obj *procNameObj); static void DestructorErrorHandler(Tcl_Interp *interp, Tcl_Obj *procNameObj); +static inline void InitFrameInfo(Tcl_Interp *interp, + ProcedureMethod *pmPtr, Tcl_ObjectContext context); +static Tcl_Obj * RenderMethodName(void *clientData); static Tcl_Obj * RenderDeclarerName(void *clientData); static int InvokeForwardMethod(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, @@ -658,7 +647,7 @@ TclOOMakeProcMethod( static int InvokeProcedureMethod( - void *clientData, /* Pointer to some per-method context. */ + void *clientData, /* Pointer to some per-method context. */ Tcl_Interp *interp, Tcl_ObjectContext context, /* The method calling context. */ int objc, /* Number of arguments. */ @@ -682,6 +671,8 @@ InvokeProcedureMethod( Tcl_ObjectContextSkippedArgs(context)); } + InitFrameInfo(interp, pmPtr, context); + /* * Allocate the special frame data. */ @@ -737,6 +728,48 @@ InvokeProcedureMethod( Tcl_ObjectContextSkippedArgs(context), fdPtr->errProc); } +/* + * Finishes filling out the extra frame info so that [info frame] works. + */ +static inline void +InitFrameInfo( + Tcl_Interp *interp, /* For object name resolution later. */ + ProcedureMethod *pmPtr, /* What we're writing to. */ + Tcl_ObjectContext context) /* The calling context, used to figure out how + * we're using the method. */ +{ + Tcl_Method method = Tcl_ObjectContextMethod(context); + + if (pmPtr->efi.length) { + /* + * Do nothing if already set up. + */ + return; + } + + pmPtr->efi.length = 2; + pmPtr->efi.fields[0].name = "method"; + pmPtr->efi.fields[0].proc = RenderMethodName; + pmPtr->efi.fields[0].clientData = pmPtr; + pmPtr->callSiteFlags = ((CallContext *) + context)->callPtr->flags & (CONSTRUCTOR | DESTRUCTOR); + pmPtr->interp = interp; + pmPtr->method = method; + if (pmPtr->gfivProc != NULL) { + pmPtr->efi.fields[1].name = ""; + pmPtr->efi.fields[1].proc = pmPtr->gfivProc; + pmPtr->efi.fields[1].clientData = pmPtr; + } else { + if (Tcl_MethodDeclarerObject(method) != NULL) { + pmPtr->efi.fields[1].name = "object"; + } else { + pmPtr->efi.fields[1].name = "class"; + } + pmPtr->efi.fields[1].proc = RenderDeclarerName; + pmPtr->efi.fields[1].clientData = pmPtr; + } +} + static int FinalizePMCall( void *data[], @@ -791,7 +824,6 @@ PushMethodCallFrame( { Namespace *nsPtr = (Namespace *) contextPtr->oPtr->namespacePtr; int result; - const char *namePtr; CallFrame **framePtrPtr = &fdPtr->framePtr; /* @@ -799,17 +831,14 @@ PushMethodCallFrame( */ if (contextPtr->callPtr->flags & CONSTRUCTOR) { - namePtr = "<constructor>"; fdPtr->nameObj = contextPtr->oPtr->fPtr->constructorName; fdPtr->errProc = ConstructorErrorHandler; } else if (contextPtr->callPtr->flags & DESTRUCTOR) { - namePtr = "<destructor>"; fdPtr->nameObj = contextPtr->oPtr->fPtr->destructorName; fdPtr->errProc = DestructorErrorHandler; } else { fdPtr->nameObj = Tcl_MethodName( Tcl_ObjectContextMethod((Tcl_ObjectContext) contextPtr)); - namePtr = TclGetString(fdPtr->nameObj); fdPtr->errProc = MethodErrorHandler; } if (pmPtr->errProc != NULL) { @@ -822,8 +851,7 @@ PushMethodCallFrame( */ if (pmPtr->flags & USE_DECLARER_NS) { - Method *mPtr = - contextPtr->callPtr->chain[contextPtr->index].mPtr; + Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr; if (mPtr->declaringClassPtr != NULL) { nsPtr = (Namespace *) @@ -845,10 +873,9 @@ PushMethodCallFrame( * Compile the body. This operation may fail. */ - fdPtr->efi.length = 2; memset(&fdPtr->cmd, 0, sizeof(Command)); fdPtr->cmd.nsPtr = nsPtr; - fdPtr->cmd.clientData = &fdPtr->efi; + fdPtr->cmd.clientData = &pmPtr->efi; pmPtr->procPtr->cmdPtr = &fdPtr->cmd; /* @@ -865,7 +892,8 @@ PushMethodCallFrame( codePtr->nsPtr = nsPtr; } result = TclProcCompileProc(interp, pmPtr->procPtr, - pmPtr->procPtr->bodyPtr, nsPtr, "body of method", namePtr); + pmPtr->procPtr->bodyPtr, nsPtr, "body of method", + TclGetString(fdPtr->nameObj)); if (result != TCL_OK) { goto failureReturn; } @@ -883,32 +911,6 @@ PushMethodCallFrame( fdPtr->framePtr->objv = objv; fdPtr->framePtr->procPtr = pmPtr->procPtr; - /* - * Finish filling out the extra frame info so that [info frame] works. - */ - - fdPtr->efi.fields[0].name = "method"; - fdPtr->efi.fields[0].proc = NULL; - fdPtr->efi.fields[0].clientData = fdPtr->nameObj; - if (pmPtr->gfivProc != NULL) { - fdPtr->efi.fields[1].name = ""; - fdPtr->efi.fields[1].proc = pmPtr->gfivProc; - fdPtr->efi.fields[1].clientData = pmPtr; - } else { - Tcl_Method method = - Tcl_ObjectContextMethod((Tcl_ObjectContext) contextPtr); - - if (Tcl_MethodDeclarerObject(method) != NULL) { - fdPtr->efi.fields[1].name = "object"; - } else { - fdPtr->efi.fields[1].name = "class"; - } - fdPtr->efi.fields[1].proc = RenderDeclarerName; - fdPtr->efi.fields[1].clientData = &fdPtr->pni; - fdPtr->pni.interp = interp; - fdPtr->pni.method = method; - } - return TCL_OK; /* @@ -1115,6 +1117,32 @@ ProcedureMethodCompiledVarResolver( /* * ---------------------------------------------------------------------- * + * RenderMethodName -- + * + * Returns the name of the declared method. Used for producing information + * for [info frame]. + * + * ---------------------------------------------------------------------- + */ + +static Tcl_Obj * +RenderMethodName( + void *clientData) +{ + ProcedureMethod *pmPtr = (ProcedureMethod *) clientData; + + if (pmPtr->callSiteFlags & CONSTRUCTOR) { + return TclOOGetFoundation(pmPtr->interp)->constructorName; + } else if (pmPtr->callSiteFlags & DESTRUCTOR) { + return TclOOGetFoundation(pmPtr->interp)->destructorName; + } else { + return Tcl_MethodName(pmPtr->method); + } +} + +/* + * ---------------------------------------------------------------------- + * * RenderDeclarerName -- * * Returns the name of the entity (object or class) which declared a @@ -1129,13 +1157,13 @@ static Tcl_Obj * RenderDeclarerName( void *clientData) { - struct PNI *pni = (struct PNI *)clientData; - Tcl_Object object = Tcl_MethodDeclarerObject(pni->method); + ProcedureMethod *pmPtr = (ProcedureMethod *) clientData; + Tcl_Object object = Tcl_MethodDeclarerObject(pmPtr->method); if (object == NULL) { - object = Tcl_GetClassAsObject(Tcl_MethodDeclarerClass(pni->method)); + object = Tcl_GetClassAsObject(Tcl_MethodDeclarerClass(pmPtr->method)); } - return TclOOObjectName(pni->interp, (Object *) object); + return TclOOObjectName(pmPtr->interp, (Object *) object); } /* |