| ︙ | | | ︙ | |
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tclInt.h"
#include "tclOOInt.h"
#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.
*/
typedef struct {
CallFrame *framePtr; /* Reference to the call frame itself (it's
* actually allocated on the Tcl stack). */
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;
/*
* Structure used to pass information about variable resolution to the
* on-the-ground resolvers used when working with resolved compiled variables.
*/
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tclInt.h"
#include "tclOOInt.h"
#include "tclCompile.h"
/*
* Structure used to contain all the information needed about a call frame
* used in a procedure-like method.
*/
typedef struct {
CallFrame *framePtr; /* Reference to the call frame itself (it's
* actually allocated on the Tcl stack). */
ProcErrorProc *errProc; /* The error handler for the body. */
Tcl_Obj *nameObj; /* The "name" of the command. */
Command cmd; /* The command structure. Mostly bogus. */
Command *oldCmdPtr; /* Saved cmdPtr so that we can be safe after a
* recursive call returns. */
} PMFrameData;
/*
* Structure used to pass information about variable resolution to the
* on-the-ground resolvers used when working with resolved compiled variables.
*/
|
| ︙ | | | ︙ | |
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
void *clientData, void **newClientData);
static void MethodErrorHandler(Tcl_Interp *interp,
Tcl_Obj *procNameObj);
static void ConstructorErrorHandler(Tcl_Interp *interp,
Tcl_Obj *procNameObj);
static void DestructorErrorHandler(Tcl_Interp *interp,
Tcl_Obj *procNameObj);
static Tcl_Obj * RenderDeclarerName(void *clientData);
static int InvokeForwardMethod(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static void DeleteForwardMethod(void *clientData);
static int CloneForwardMethod(Tcl_Interp *interp,
void *clientData, void **newClientData);
|
>
>
>
|
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
void *clientData, void **newClientData);
static void MethodErrorHandler(Tcl_Interp *interp,
Tcl_Obj *procNameObj);
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,
int objc, Tcl_Obj *const *objv);
static void DeleteForwardMethod(void *clientData);
static int CloneForwardMethod(Tcl_Interp *interp,
void *clientData, void **newClientData);
|
| ︙ | | | ︙ | |
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
|
* How to invoke a procedure-like method.
*
* ----------------------------------------------------------------------
*/
static int
InvokeProcedureMethod(
void *clientData, /* Pointer to some per-method context. */
Tcl_Interp *interp,
Tcl_ObjectContext context, /* The method calling context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments as actually seen. */
{
ProcedureMethod *pmPtr = (ProcedureMethod *)clientData;
int result;
|
|
|
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
|
* How to invoke a procedure-like method.
*
* ----------------------------------------------------------------------
*/
static int
InvokeProcedureMethod(
void *clientData, /* Pointer to some per-method context. */
Tcl_Interp *interp,
Tcl_ObjectContext context, /* The method calling context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments as actually seen. */
{
ProcedureMethod *pmPtr = (ProcedureMethod *)clientData;
int result;
|
| ︙ | | | ︙ | |
677
678
679
680
681
682
683
684
685
686
687
688
689
690
|
if (TclOOObjectDestroyed(((CallContext *)context)->oPtr) ||
Tcl_InterpDeleted(interp)
) {
return TclNRObjectContextInvokeNext(interp, context, objc, objv,
Tcl_ObjectContextSkippedArgs(context));
}
/*
* Allocate the special frame data.
*/
fdPtr = (PMFrameData *)TclStackAlloc(interp, sizeof(PMFrameData));
|
>
>
|
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
|
if (TclOOObjectDestroyed(((CallContext *)context)->oPtr) ||
Tcl_InterpDeleted(interp)
) {
return TclNRObjectContextInvokeNext(interp, context, objc, objv,
Tcl_ObjectContextSkippedArgs(context));
}
InitFrameInfo(interp, pmPtr, context);
/*
* Allocate the special frame data.
*/
fdPtr = (PMFrameData *)TclStackAlloc(interp, sizeof(PMFrameData));
|
| ︙ | | | ︙ | |
732
733
734
735
736
737
738
739
740
741
742
743
744
745
|
* Now invoke the body of the method.
*/
TclNRAddCallback(interp, FinalizePMCall, pmPtr, context, fdPtr, NULL);
return TclNRInterpProcCore(interp, fdPtr->nameObj,
Tcl_ObjectContextSkippedArgs(context), fdPtr->errProc);
}
static int
FinalizePMCall(
void *data[],
Tcl_Interp *interp,
int result)
{
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
|
* Now invoke the body of the method.
*/
TclNRAddCallback(interp, FinalizePMCall, pmPtr, context, fdPtr, NULL);
return TclNRInterpProcCore(interp, fdPtr->nameObj,
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[],
Tcl_Interp *interp,
int result)
{
|
| ︙ | | | ︙ | |
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
|
int objc, /* Number of arguments. */
Tcl_Obj *const *objv, /* Array of arguments. */
PMFrameData *fdPtr) /* Place to store information about the call
* frame. */
{
Namespace *nsPtr = (Namespace *) contextPtr->oPtr->namespacePtr;
int result;
const char *namePtr;
CallFrame **framePtrPtr = &fdPtr->framePtr;
/*
* Compute basic information on the basis of the type of method it is.
*/
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) {
fdPtr->errProc = pmPtr->errProc;
}
/*
* Magic to enable things like [incr Tcl], which wants methods to run in
* their class's namespace.
*/
if (pmPtr->flags & USE_DECLARER_NS) {
Method *mPtr =
contextPtr->callPtr->chain[contextPtr->index].mPtr;
if (mPtr->declaringClassPtr != NULL) {
nsPtr = (Namespace *)
mPtr->declaringClassPtr->thisPtr->namespacePtr;
} else {
nsPtr = (Namespace *) mPtr->declaringObjectPtr->namespacePtr;
}
|
<
<
<
<
<
|
|
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
|
int objc, /* Number of arguments. */
Tcl_Obj *const *objv, /* Array of arguments. */
PMFrameData *fdPtr) /* Place to store information about the call
* frame. */
{
Namespace *nsPtr = (Namespace *) contextPtr->oPtr->namespacePtr;
int result;
CallFrame **framePtrPtr = &fdPtr->framePtr;
/*
* Compute basic information on the basis of the type of method it is.
*/
if (contextPtr->callPtr->flags & CONSTRUCTOR) {
fdPtr->nameObj = contextPtr->oPtr->fPtr->constructorName;
fdPtr->errProc = ConstructorErrorHandler;
} else if (contextPtr->callPtr->flags & DESTRUCTOR) {
fdPtr->nameObj = contextPtr->oPtr->fPtr->destructorName;
fdPtr->errProc = DestructorErrorHandler;
} else {
fdPtr->nameObj = Tcl_MethodName(
Tcl_ObjectContextMethod((Tcl_ObjectContext) contextPtr));
fdPtr->errProc = MethodErrorHandler;
}
if (pmPtr->errProc != NULL) {
fdPtr->errProc = pmPtr->errProc;
}
/*
* Magic to enable things like [incr Tcl], which wants methods to run in
* their class's namespace.
*/
if (pmPtr->flags & USE_DECLARER_NS) {
Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr;
if (mPtr->declaringClassPtr != NULL) {
nsPtr = (Namespace *)
mPtr->declaringClassPtr->thisPtr->namespacePtr;
} else {
nsPtr = (Namespace *) mPtr->declaringObjectPtr->namespacePtr;
}
|
| ︙ | | | ︙ | |
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
|
fdPtr->oldCmdPtr = pmPtr->procPtr->cmdPtr;
/*
* 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;
pmPtr->procPtr->cmdPtr = &fdPtr->cmd;
/*
* [Bug 2037727] Always call TclProcCompileProc so that we check not only
* that we have bytecode, but also that it remains valid. Note that we set
* the namespace of the code here directly; this is a hack, but the
* alternative is *so* slow...
*/
if (pmPtr->procPtr->bodyPtr->typePtr == &tclByteCodeType) {
ByteCode *codePtr =
pmPtr->procPtr->bodyPtr->internalRep.twoPtrValue.ptr1;
codePtr->nsPtr = nsPtr;
}
result = TclProcCompileProc(interp, pmPtr->procPtr,
pmPtr->procPtr->bodyPtr, nsPtr, "body of method", namePtr);
if (result != TCL_OK) {
goto failureReturn;
}
/*
* Make the stack frame and fill it out with information about this call.
* This operation may fail.
*/
(void) TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
(Tcl_Namespace *) nsPtr, FRAME_IS_PROC|FRAME_IS_METHOD);
fdPtr->framePtr->clientData = contextPtr;
fdPtr->framePtr->objc = objc;
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;
/*
* Restore the old cmdPtr so that a subsequent use of [info frame] won't
* crash on us. [Bug 3001438]
*/
|
<
|
|
>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
|
fdPtr->oldCmdPtr = pmPtr->procPtr->cmdPtr;
/*
* Compile the body. This operation may fail.
*/
memset(&fdPtr->cmd, 0, sizeof(Command));
fdPtr->cmd.nsPtr = nsPtr;
fdPtr->cmd.clientData = &pmPtr->efi;
pmPtr->procPtr->cmdPtr = &fdPtr->cmd;
/*
* [Bug 2037727] Always call TclProcCompileProc so that we check not only
* that we have bytecode, but also that it remains valid. Note that we set
* the namespace of the code here directly; this is a hack, but the
* alternative is *so* slow...
*/
if (pmPtr->procPtr->bodyPtr->typePtr == &tclByteCodeType) {
ByteCode *codePtr =
pmPtr->procPtr->bodyPtr->internalRep.twoPtrValue.ptr1;
codePtr->nsPtr = nsPtr;
}
result = TclProcCompileProc(interp, pmPtr->procPtr,
pmPtr->procPtr->bodyPtr, nsPtr, "body of method",
TclGetString(fdPtr->nameObj));
if (result != TCL_OK) {
goto failureReturn;
}
/*
* Make the stack frame and fill it out with information about this call.
* This operation may fail.
*/
(void) TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
(Tcl_Namespace *) nsPtr, FRAME_IS_PROC|FRAME_IS_METHOD);
fdPtr->framePtr->clientData = contextPtr;
fdPtr->framePtr->objc = objc;
fdPtr->framePtr->objv = objv;
fdPtr->framePtr->procPtr = pmPtr->procPtr;
return TCL_OK;
/*
* Restore the old cmdPtr so that a subsequent use of [info frame] won't
* crash on us. [Bug 3001438]
*/
|
| ︙ | | | ︙ | |
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
|
*rPtrPtr = &infoPtr->info;
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* RenderDeclarerName --
*
* Returns the name of the entity (object or class) which declared a
* method. Used for producing information for [info frame] in such a way
* that the expensive part of this (generating the object or class name
* itself) isn't done until it is needed.
*
* ----------------------------------------------------------------------
*/
static Tcl_Obj *
RenderDeclarerName(
void *clientData)
{
struct PNI *pni = (struct PNI *)clientData;
Tcl_Object object = Tcl_MethodDeclarerObject(pni->method);
if (object == NULL) {
object = Tcl_GetClassAsObject(Tcl_MethodDeclarerClass(pni->method));
}
return TclOOObjectName(pni->interp, (Object *) object);
}
/*
* ----------------------------------------------------------------------
*
* MethodErrorHandler, ConstructorErrorHandler, DestructorErrorHandler --
*
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
|
*rPtrPtr = &infoPtr->info;
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* 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
* method. Used for producing information for [info frame] in such a way
* that the expensive part of this (generating the object or class name
* itself) isn't done until it is needed.
*
* ----------------------------------------------------------------------
*/
static Tcl_Obj *
RenderDeclarerName(
void *clientData)
{
ProcedureMethod *pmPtr = (ProcedureMethod *) clientData;
Tcl_Object object = Tcl_MethodDeclarerObject(pmPtr->method);
if (object == NULL) {
object = Tcl_GetClassAsObject(Tcl_MethodDeclarerClass(pmPtr->method));
}
return TclOOObjectName(pmPtr->interp, (Object *) object);
}
/*
* ----------------------------------------------------------------------
*
* MethodErrorHandler, ConstructorErrorHandler, DestructorErrorHandler --
*
|
| ︙ | | | ︙ | |