On 18.08.2024 15:18, Rony G. Flatscher wrote:
On 18.08.2024 14:44, Rick McGuire wrote:
One thing you've missed is that there are situations where there is no spawning activation. For
example, from native code, I can attach a thread, create a message object and send it a START
message. In that situation, there is no activation to create a stack frame from.
Went through the code and it seems that in this case "MessageClass::start()" gets invoked as well?
If so, there will be an oldActivity and a newActivity as well, so I probably misunderstood your remark.
If there is no stack frame available, then in "Activity::setCallerStackFrameAsStringTable(...)" this
will yield an empty StringTtable to be created as a result of invoking
"RexxActivation::getStackFrameAsStringTable(StackFrameClass * stackFrame)". The stringtable gets a
THREAD entry added before returning it (the existence of a THREAD entry in the TraceObject's
callerStackFrame stringtable indicates that the caller with that thread ID spawned the activity;
this is meant to indicate that no stackframe was available at the time of creation).
Also, the stack frame in question might be a native activation, so you need to make sure that
these function as well.
Again not sure what the implications of a native activation are in this context.
"Activity::generateCallerStackFrame(bool skipFirst)" was modeled after
"Activity::generateStackFrames(bool skipFirst)" assuming that it would therefore cover all scenarios
related to dealing with stack frames.
Should the stack frame be NULL then as described above an empty StringTable gets created (meant to
indicate that no stackframe was available at the time of creation) and a THREAD entry will be added
to indicate the thread ID on which the spawn took place.
If this is not sufficient, then please let me know what needs to be done.
---rony
P.S.: The rexxref book needs to be updated to explain the cicrumstance when a THREAD entry gets
added (and why it can be the case that the callerStackFrame StringTable otherwise may not contain
stackframe related entries, e.g. when spawned from native code).
P.P.S.: As there was a left-over statement that serves no purpose anymore I removed it, hence here
the updated diff:
Index:*interpreter/classes/MessageClass.cpp*
===================================================================
--- interpreter/classes/MessageClass.cpp (revision 12859)
+++ interpreter/classes/MessageClass.cpp (working copy)
@@ -537,6 +537,10 @@
// spawn a new activity off of the old activity
Activity *oldActivity = ActivityManager::currentActivity;
Activity *newActivity = oldActivity->spawnReply();
+
+ // save current frame info in a StringTable as it has caused the creation
of a new activity +
Activity::setCallerStackFrameAsStringTable(oldActivity, newActivity, true);
// create stackframe
from parent/caller
+
// mark which activity we're running on, then dispatch the message
// on the new activity (which is sitting waiting for work to perform)
setField(startActivity, newActivity);
Index:*interpreter/concurrency/Activity.cpp*
===================================================================
--- interpreter/concurrency/Activity.cpp (revision 12859)
+++ interpreter/concurrency/Activity.cpp (working copy)
@@ -1159,31 +1159,53 @@
}
+
/**
- * Generates a StackFrame from the parent and returns it.
+ * Generate the caller's stack frame.
*
- * @return parent's StackFrame or NULLOBJECT, if no parent exists
+ * @param skipFirst Determines if we should skip the first frame: + * false
for reply in
RexxActivation::run(...), + * true for Message::start() and in the general
case. + * + * @return
The stackframe of the caller which caused a spawned activity.
*/
-StackFrameClass* Activity::generateParentStackFrame()
+StackFrameClass* Activity::generateCallerStackFrame(bool skipFirst)
{
- // create lists for both the stack frames and the traceback lines
- StackFrameClass *parentStackFrame = NULLOBJECT;
-
ActivationFrame *frame = activationFrames;
+ StackFrameClass *callerStackFrame = NULL;
- if (frame != NULL)
+ if (frame && skipFirst)
{
- frame = frame->next; // get parent
- if (frame != NULL)
- {
- parentStackFrame = frame->createStackFrame();
- }
+ frame = frame->next;
}
- return parentStackFrame;
+ if (frame) + { + callerStackFrame = frame->createStackFrame(); + } +
return callerStackFrame;
}
/**
+ * Generates and saves a StringTable to store stackFrame infos of
oldActivity in newActivity +
* (for TraceObject), used by MessageClass::start(). + * + */ +void
Activity::setCallerStackFrameAsStringTable(Activity *oldActivity, Activity
*newActivity, bool
skipFirst) +{ + // get caller stackframe, if any + StackFrameClass
*oldActivityStackFrame =
oldActivity -> generateCallerStackFrame(skipFirst); + // returns a
StringTable that may be empty
if oldActivityStackFrame==NULLOBJECT + newActivity ->
spawnerStackFrameInfo=RexxActivation::getStackFrameAsStringTable(oldActivityStackFrame);
+ //
save thread ID to indicate from which thread ID the spawnReply() came from
(helpful, e.g., if
StringTable is empty) + // if oldActivity NULL, then THREAD will be 0 to
indicate this +
newActivity -> spawnerStackFrameInfo -> put(new_integer(oldActivity ->
getIdntfr()),
GlobalNames::THREAD ); + return; +}
+
+
+
+/**
* Build a message and perform the indicated substitutions.
*
* @param messageCode
Index:*interpreter/concurrency/Activity.hpp*
===================================================================
--- interpreter/concurrency/Activity.hpp (revision 12859)
+++ interpreter/concurrency/Activity.hpp (working copy)
@@ -159,8 +159,12 @@
void unwindToFrame(RexxActivation *frame);
void cleanupStackFrame(ActivationBase *poppedStackFrame);
ArrayClass *generateStackFrames(bool skipFirst);
- StackFrameClass *generateParentStackFrame();
+ // allow TraceObject's callerStackFrame entry to indicate the caller that caused the spawned
activity + StackFrameClass* Activity::generateCallerStackFrame(bool ); +
static void
Activity::setCallerStackFrameAsStringTable(Activity *oldActivity, Activity
*newActivity, bool);
+ StringTable *spawnerStackFrameInfo;
+
Activity *spawnReply();
void exitKernel();
Index:*interpreter/execution/RexxActivation.cpp*
===================================================================
--- interpreter/execution/RexxActivation.cpp (revision 12859)
+++ interpreter/execution/RexxActivation.cpp (working copy)
@@ -702,6 +702,9 @@
activity = oldActivity->spawnReply();
+ // save current frame info in a StringTable as it has caused the creation of a new activity +
Activity::setCallerStackFrameAsStringTable(oldActivity, activity, false);
+
// save the pointer to the start of our stack frame. We're
// going to need to release this after we migrate
everything
// over.
@@ -5157,8 +5160,23 @@
}
else if (tracePrefix == TRACE_PREFIX_INVOCATION) // tracing an
invocation entry
{
- StackFrameClass *stackFrame = activity ->
generateParentStackFrame();
- traceObject -> put(stackFrame ?
getStackFrameAsStringTable(stackFrame) : TheNilObject,
GlobalNames::CALLERSTACKFRAME);
+ StackFrameClass *stackFrame = activity -> generateCallerStackFrame(true);
+ if (stackFrame) +
{ + traceObject -> put(getStackFrameAsStringTable(stackFrame),
GlobalNames::CALLERSTACKFRAME); +
} + else + { + if (activity -> spawnerStackFrameInfo) // spawner's frame
infos saved as a
StringTable? + { + // allows for analyzing trace logs to identify the caller
of a spawned
activity + traceObject -> put(activity -> spawnerStackFrameInfo,
GlobalNames::CALLERSTACKFRAME);
+ } + else + { + traceObject -> put(TheNilObject,
GlobalNames::CALLERSTACKFRAME); + } + }
}
// METHODCALL, fill in method related information
@@ -5232,26 +5250,28 @@
* the identityHash of the StackFrame entries EXECUTABLE and TARGET if
they are not
* .nil.
*
-* @param stackFrame the StackFrame object to use
-* @return a StringTable with all the entries of stackFrame
+* @param stackFrame the StackFrame object to use, may be NULLOBJECT +*
@return a StringTable
with all the entries of stackFrame, if available
*/
StringTable * RexxActivation::getStackFrameAsStringTable(StackFrameClass *
stackFrame)
{
- ProtectedObject result;
StringTable *tmpStringTable = new_string_table();
- // array
- tmpStringTable -> put(stackFrame->sendMessage(GlobalNames::ARGUMENTS ,
result), GlobalNames::ARGUMENTS );
+ if (stackFrame != NULLOBJECT) + { + ProtectedObject result; + // array +
tmpStringTable ->
put(stackFrame->sendMessage(GlobalNames::ARGUMENTS , result),
GlobalNames::ARGUMENTS );
- // strings
- tmpStringTable -> put(stackFrame->sendMessage(GlobalNames::LINE ,
result), GlobalNames::LINE );
- tmpStringTable -> put(stackFrame->sendMessage(GlobalNames::NAME ,
result), GlobalNames::NAME );
- tmpStringTable -> put(stackFrame->sendMessage(GlobalNames::TRACELINE ,
result), GlobalNames::TRACELINE );
- tmpStringTable -> put(stackFrame->sendMessage(GlobalNames::TYPE ,
result), GlobalNames::TYPE );
+ // strings + tmpStringTable ->
put(stackFrame->sendMessage(GlobalNames::LINE , result),
GlobalNames::LINE ); + tmpStringTable ->
put(stackFrame->sendMessage(GlobalNames::NAME ,
result), GlobalNames::NAME ); + tmpStringTable ->
put(stackFrame->sendMessage(GlobalNames::TRACELINE , result),
GlobalNames::TRACELINE ); +
tmpStringTable -> put(stackFrame->sendMessage(GlobalNames::TYPE , result),
GlobalNames::TYPE );
- // objects
- tmpStringTable -> put(stackFrame->sendMessage(GlobalNames::EXECUTABLE,
result), GlobalNames::EXECUTABLE);
- tmpStringTable -> put(stackFrame->sendMessage(GlobalNames::TARGET ,
result), GlobalNames::TARGET );
-
+ // objects + tmpStringTable ->
put(stackFrame->sendMessage(GlobalNames::EXECUTABLE, result),
GlobalNames::EXECUTABLE); + tmpStringTable ->
put(stackFrame->sendMessage(GlobalNames::TARGET ,
result), GlobalNames::TARGET ); + }
return tmpStringTable;
}
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel