|
43 | 43 | import java.util.ArrayList;
|
44 | 44 | import java.util.List;
|
45 | 45 | import java.util.concurrent.TimeUnit;
|
| 46 | +import java.util.concurrent.atomic.AtomicInteger; |
46 | 47 |
|
| 48 | +import com.oracle.truffle.api.RootCallTarget; |
| 49 | +import com.oracle.truffle.api.Truffle; |
47 | 50 | import com.oracle.truffle.api.TruffleContext;
|
48 | 51 | import com.oracle.truffle.api.TruffleSafepoint;
|
49 | 52 | import com.oracle.truffle.api.TruffleSafepoint.Interrupter;
|
| 53 | +import com.oracle.truffle.api.TruffleStackTraceElement; |
| 54 | +import com.oracle.truffle.api.frame.FrameInstance; |
50 | 55 | import com.oracle.truffle.api.frame.VirtualFrame;
|
51 | 56 | import com.oracle.truffle.api.profiles.InlinedBranchProfile;
|
52 | 57 | import com.oracle.truffle.api.profiles.InlinedConditionProfile;
|
| 58 | +import com.oracle.truffle.api.nodes.RootNode; |
53 | 59 | import com.oracle.truffle.api.strings.TruffleString;
|
54 | 60 | import org.graalvm.collections.Pair;
|
55 | 61 | import org.truffleruby.RubyContext;
|
|
87 | 93 | import org.truffleruby.interop.TranslateInteropExceptionNode;
|
88 | 94 | import org.truffleruby.language.Nil;
|
89 | 95 | import org.truffleruby.language.NotProvided;
|
| 96 | +import org.truffleruby.language.RubyRootNode; |
90 | 97 | import org.truffleruby.language.SafepointAction;
|
91 | 98 | import org.truffleruby.language.SafepointManager;
|
92 | 99 | import org.truffleruby.annotations.Visibility;
|
93 | 100 | import org.truffleruby.language.arguments.ArgumentsDescriptor;
|
94 | 101 | import org.truffleruby.language.arguments.RubyArguments;
|
95 | 102 | import org.truffleruby.language.backtrace.Backtrace;
|
| 103 | +import org.truffleruby.language.backtrace.BacktraceFormatter; |
96 | 104 | import org.truffleruby.language.control.KillException;
|
97 | 105 | import org.truffleruby.language.control.RaiseException;
|
| 106 | +import org.truffleruby.language.methods.SharedMethodInfo; |
98 | 107 | import org.truffleruby.language.objects.AllocationTracing;
|
99 | 108 | import org.truffleruby.language.objects.shared.SharedObjects;
|
100 | 109 | import org.truffleruby.language.yield.CallBlockNode;
|
@@ -1044,10 +1053,59 @@ public abstract static class EachCallerLocationNode extends PrimitiveArrayArgume
|
1044 | 1053 | @Specialization
|
1045 | 1054 | protected Object eachCallerLocation(VirtualFrame frame) {
|
1046 | 1055 | final RubyProc block = (RubyProc) RubyArguments.getBlock(frame);
|
1047 |
| - final Backtrace backtrace = getContext().getCallStack().getBacktrace(this, 2); |
| 1056 | + // Skip the block of `Thread#each_caller_location` + its internal iteration. |
| 1057 | + final int skip = 2; |
| 1058 | + final List<TruffleStackTraceElement> stackTraceElements = new ArrayList<>(); |
| 1059 | + final AtomicInteger index = new AtomicInteger(0); |
| 1060 | + |
| 1061 | + Truffle.getRuntime().iterateFrames((frameInstance) -> { |
| 1062 | + final RootCallTarget rootCallTarget = (RootCallTarget) frameInstance.getCallTarget(); |
| 1063 | + Node location = frameInstance.getCallNode(); |
| 1064 | + |
| 1065 | + if (location != null) { |
| 1066 | + final RootNode rootNode = location.getRootNode(); |
| 1067 | + |
| 1068 | + if (rootNode.isInternal()) { |
| 1069 | + return frameInstance; |
| 1070 | + } |
| 1071 | + |
| 1072 | + if (rootNode instanceof RubyRootNode) { |
| 1073 | + final SharedMethodInfo sharedMethodInfo = ((RubyRootNode) rootNode).getSharedMethodInfo(); |
| 1074 | + if (getContext().getCoreLibrary().isTruffleBootMainMethod(sharedMethodInfo)) { |
| 1075 | + return frameInstance; |
| 1076 | + } |
| 1077 | + } |
| 1078 | + } |
| 1079 | + |
| 1080 | + if (index.getAndIncrement() >= skip) { |
| 1081 | + final TruffleStackTraceElement stackTraceElement = TruffleStackTraceElement.create( |
| 1082 | + location, |
| 1083 | + rootCallTarget, |
| 1084 | + frameInstance.getFrame(FrameInstance.FrameAccess.READ_ONLY)); |
| 1085 | + stackTraceElements.add(stackTraceElement); |
| 1086 | + |
| 1087 | + final TruffleStackTraceElement[] finalStackTraceElements = stackTraceElements |
| 1088 | + .toArray(TruffleStackTraceElement[]::new); |
| 1089 | + final boolean readyToYield = BacktraceFormatter.nextAvailableSourceSection(finalStackTraceElements, |
| 1090 | + 0) != null; |
| 1091 | + |
| 1092 | + if (readyToYield) { |
| 1093 | + for (int i = 0; i < finalStackTraceElements.length; i++) { |
| 1094 | + Backtrace backtrace = new Backtrace(location, 0, finalStackTraceElements); |
| 1095 | + RubyBacktraceLocation rubyBacktraceLocation = new RubyBacktraceLocation( |
| 1096 | + getContext().getCoreLibrary().threadBacktraceLocationClass, |
| 1097 | + getLanguage().threadBacktraceLocationShape, |
| 1098 | + backtrace, |
| 1099 | + i); |
| 1100 | + |
| 1101 | + yieldNode.yield(block, rubyBacktraceLocation); |
| 1102 | + } |
| 1103 | + stackTraceElements.clear(); |
| 1104 | + } |
| 1105 | + } |
| 1106 | + |
| 1107 | + return null; |
1048 | 1108 |
|
1049 |
| - backtrace.getBacktraceRawLocations(getContext(), getLanguage(), -1, this, (location) -> { |
1050 |
| - yieldNode.yield(block, location); |
1051 | 1109 | });
|
1052 | 1110 |
|
1053 | 1111 | return nil;
|
|
0 commit comments