Skip to content

Commit b4705ae

Browse files
aardvark179eregon
authored andcommitted
Alter rb_protect and rb_jump_tag to match MRI behaviour.
1 parent 8e5e36a commit b4705ae

File tree

3 files changed

+95
-10
lines changed

3 files changed

+95
-10
lines changed

lib/truffle/truffle/cext.rb

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,8 +1041,8 @@ def rb_protect(function, arg, write_status, status)
10411041
end
10421042

10431043
unless Primitive.object_equal(nil, e)
1044-
store = (Thread.current[:__stored_exceptions__] ||= [])
1045-
pos = store.push(e).size
1044+
store_exception(e)
1045+
pos = extract_tag(e)
10461046
Primitive.thread_set_exception(extract_ruby_exception(e))
10471047
end
10481048

@@ -1052,14 +1052,9 @@ def rb_protect(function, arg, write_status, status)
10521052

10531053
def rb_jump_tag(pos)
10541054
if pos > 0
1055-
store = Thread.current[:__stored_exceptions__]
1056-
if pos == store.size
1057-
e = store.pop
1058-
else
1059-
# Can't disturb other positions or other rb_jump_tag calls might fail.
1060-
e = store[pos - 1]
1061-
store[pos - 1] = nil
1062-
end
1055+
e = retrieve_exception
1056+
tag = extract_tag(e)
1057+
raise RuntimeError, 'mismatch between jump tag and captured exception' unless pos == tag
10631058
raise_exception(e)
10641059
end
10651060
end

src/main/java/org/truffleruby/cext/CExtNodes.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,13 @@
9292
import org.truffleruby.language.constants.LookupConstantNode;
9393
import org.truffleruby.language.control.BreakException;
9494
import org.truffleruby.language.control.BreakID;
95+
import org.truffleruby.language.control.DynamicReturnException;
96+
import org.truffleruby.language.control.LocalReturnException;
97+
import org.truffleruby.language.control.NextException;
98+
import org.truffleruby.language.control.RedoException;
99+
import org.truffleruby.language.control.RetryException;
95100
import org.truffleruby.language.control.RaiseException;
101+
import org.truffleruby.language.control.ThrowException;
96102
import org.truffleruby.language.dispatch.DispatchNode;
97103
import org.truffleruby.language.dispatch.LiteralCallNode;
98104
import org.truffleruby.language.library.RubyStringLibrary;
@@ -130,6 +136,18 @@
130136
@CoreModule("Truffle::CExt")
131137
public class CExtNodes {
132138

139+
/* These tag values are derived from MRI source and from the Tk gem and are used to represent different control flow
140+
* states under which code may exit an `rb_protect` plock. The fatal tag is defined but I could not find a point
141+
* where it is assigned, and am not sure it maps to anything we would use in TruffleRuby. */
142+
public static int RUBY_TAG_RETURN = 0x1;
143+
public static int RUBY_TAG_BREAK = 0x2;
144+
public static int RUBY_TAG_NEXT = 0x3;
145+
public static int RUBY_TAG_RETRY = 0x4;
146+
public static int RUBY_TAG_REDO = 0x5;
147+
public static int RUBY_TAG_RAISE = 0x6;
148+
public static int RUBY_TAG_THROW = 0x7;
149+
public static int RUBY_TAG_FATAL = 0x8;
150+
133151
public static Pointer newNativeStringPointer(int capacity, RubyLanguage language) {
134152
// We need up to 4 \0 bytes for UTF-32. Always use 4 for speed rather than checking the encoding min length.
135153
Pointer pointer = Pointer.mallocAutoRelease(capacity + 4, language);
@@ -1355,6 +1373,31 @@ protected Object executeWithProtect(RubyProc block,
13551373
}
13561374
}
13571375

1376+
@CoreMethod(names = "store_exception", onSingleton = true, required = 1)
1377+
public abstract static class StoreException extends YieldingCoreMethodNode {
1378+
1379+
@Specialization
1380+
protected Object storeException(CapturedException captured) {
1381+
final ExtensionCallStack extensionStack = getLanguage()
1382+
.getCurrentThread()
1383+
.getCurrentFiber().extensionCallStack;
1384+
extensionStack.setException(captured);
1385+
return nil;
1386+
}
1387+
}
1388+
1389+
@CoreMethod(names = "retrieve_exception", onSingleton = true)
1390+
public abstract static class RetrieveException extends YieldingCoreMethodNode {
1391+
1392+
@Specialization
1393+
protected Object retrieveException() {
1394+
final ExtensionCallStack extensionStack = getLanguage()
1395+
.getCurrentThread()
1396+
.getCurrentFiber().extensionCallStack;
1397+
return extensionStack.getException();
1398+
}
1399+
}
1400+
13581401
@CoreMethod(names = "extract_ruby_exception", onSingleton = true, required = 1)
13591402
public abstract static class ExtractRubyException extends CoreMethodArrayArgumentsNode {
13601403

@@ -1370,6 +1413,41 @@ protected Object executeThrow(CapturedException captured,
13701413
}
13711414
}
13721415

1416+
@CoreMethod(names = "extract_tag", onSingleton = true, required = 1)
1417+
public abstract static class ExtractRubyTag extends CoreMethodArrayArgumentsNode {
1418+
1419+
@Specialization
1420+
protected int executeThrow(CapturedException captured,
1421+
@Cached ConditionProfile localReturnProfile,
1422+
@Cached ConditionProfile dynamicReturnProfile,
1423+
@Cached ConditionProfile breakProfile,
1424+
@Cached ConditionProfile nextProfile,
1425+
@Cached ConditionProfile retryProfile,
1426+
@Cached ConditionProfile redoProfile,
1427+
@Cached ConditionProfile raiseProfile,
1428+
@Cached ConditionProfile throwProfile) {
1429+
final Throwable e = captured.getException();
1430+
if (dynamicReturnProfile.profile(e instanceof DynamicReturnException)) {
1431+
return RUBY_TAG_RETURN;
1432+
} else if (localReturnProfile.profile(e instanceof LocalReturnException)) {
1433+
return RUBY_TAG_RETURN;
1434+
} else if (breakProfile.profile(e instanceof BreakException)) {
1435+
return RUBY_TAG_BREAK;
1436+
} else if (nextProfile.profile(e instanceof NextException)) {
1437+
return RUBY_TAG_NEXT;
1438+
} else if (retryProfile.profile(e instanceof RetryException)) {
1439+
return RUBY_TAG_RETRY;
1440+
} else if (redoProfile.profile(e instanceof RedoException)) {
1441+
return RUBY_TAG_REDO;
1442+
} else if (raiseProfile.profile(e instanceof RaiseException)) {
1443+
return RUBY_TAG_RAISE;
1444+
} else if (throwProfile.profile(e instanceof ThrowException)) {
1445+
return RUBY_TAG_THROW;
1446+
}
1447+
return 0;
1448+
}
1449+
}
1450+
13731451
@CoreMethod(names = "raise_exception", onSingleton = true, required = 1)
13741452
public abstract static class RaiseExceptionNode extends CoreMethodArrayArgumentsNode {
13751453

@@ -1382,6 +1460,7 @@ protected Object executeThrow(CapturedException captured,
13821460
if (runtimeExceptionProfile.profile(e instanceof RuntimeException)) {
13831461
throw (RuntimeException) e;
13841462
} else if (errorProfile.profile(e instanceof Error)) {
1463+
13851464
throw (Error) e;
13861465
} else {
13871466
throw CompilerDirectives.shouldNotReachHere("Checked Java Throwable rethrown", e);

src/main/java/org/truffleruby/core/MarkingService.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import org.truffleruby.RubyContext;
1616
import org.truffleruby.RubyLanguage;
17+
import org.truffleruby.cext.CapturedException;
1718
import org.truffleruby.cext.ValueWrapperManager;
1819
import org.truffleruby.core.array.ArrayUtils;
1920
import org.truffleruby.core.queue.UnsizedQueue;
@@ -118,6 +119,7 @@ protected static class ExtensionCallStackEntry {
118119
protected final boolean keywordsGiven;
119120
protected Object specialVariables;
120121
protected final Object block;
122+
protected CapturedException capturedException;
121123

122124
protected ExtensionCallStackEntry(
123125
ExtensionCallStackEntry previous,
@@ -128,6 +130,7 @@ protected ExtensionCallStackEntry(
128130
this.keywordsGiven = keywordsGiven;
129131
this.specialVariables = specialVariables;
130132
this.block = block;
133+
this.capturedException = null;
131134
}
132135
}
133136

@@ -165,6 +168,14 @@ public void setSpecialVariables(Object specialVariables) {
165168
current.specialVariables = specialVariables;
166169
}
167170

171+
public CapturedException getException() {
172+
return current.capturedException;
173+
}
174+
175+
public void setException(CapturedException capturedException) {
176+
current.capturedException = capturedException;
177+
}
178+
168179
public Object getBlock() {
169180
return current.block;
170181
}

0 commit comments

Comments
 (0)