Skip to content

Commit b6b78dc

Browse files
committed
fixes
1 parent 6c8dce3 commit b6b78dc

31 files changed

+239
-144
lines changed

spec/truffle/arguments_descriptor_spec.rb

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,11 @@ def struct_new_like(a, *b, c: 101)
160160
info.arguments.should == ['A', :a, :b, {c: 1}] if truffleruby?
161161

162162
info = struct_new_like('A', :a, :b, {c: 1})
163-
info.values.should == ['A', [:a, :b], 1]
163+
if truffleruby? # TO FIX
164+
info.values.should == ['A', [:a, :b], 1]
165+
else
166+
info.values.should == ['A', [:a, :b, {c: 1}], 101]
167+
end
164168
info.descriptor.should == [] if truffleruby?
165169
info.arguments.should == ['A', :a, :b, {c: 1}] if truffleruby?
166170

@@ -273,7 +277,11 @@ def mixture(a, b = nil, c = nil, d, e: nil, **f)
273277
info.arguments.should == [1, 2, {e: 3}] if truffleruby?
274278

275279
info = mixture(1, 2, {foo: :bar})
276-
info.values.should == [1, nil, nil, 2, nil, {:foo=>:bar}]
280+
if truffleruby? # TO FIX
281+
info.values.should == [1, nil, nil, 2, nil, {:foo=>:bar}]
282+
else
283+
info.values.should == [1, 2, nil, {foo: :bar}, nil, {}]
284+
end
277285
info.descriptor.should == [] if truffleruby?
278286
info.arguments.should == [1, 2, {foo: :bar}] if truffleruby?
279287

@@ -375,4 +383,61 @@ def use_yielder(x, y)
375383
info.descriptor.should == [:keywords] if truffleruby?
376384
info.arguments.should == [{a: 1, b: 2}] if truffleruby?
377385
end
386+
387+
it "work through instance_exec" do
388+
info = instance_exec(a: 1) do |*args, **kwargs|
389+
info([args, kwargs], Primitive.arguments_descriptor, Primitive.arguments)
390+
end
391+
info.values.should == [[], {a: 1}]
392+
info.descriptor.should == [:keywords] if truffleruby?
393+
info.arguments.should == [{a: 1}] if truffleruby?
394+
end
395+
396+
it "work through module_exec" do
397+
info = Module.new.module_exec(a: 1) do |*args, **kwargs|
398+
ArgumentsDescriptorSpecs::Info.new([args, kwargs], Primitive.arguments_descriptor, Primitive.arguments)
399+
end
400+
info.values.should == [[], {a: 1}]
401+
info.descriptor.should == [:keywords] if truffleruby?
402+
info.arguments.should == [{a: 1}] if truffleruby?
403+
end
404+
405+
it "work through Proc#call" do
406+
info = -> (*args, **kwargs) do
407+
ArgumentsDescriptorSpecs::Info.new([args, kwargs], Primitive.arguments_descriptor, Primitive.arguments)
408+
end.call(a: 1)
409+
info.values.should == [[], {a: 1}]
410+
info.descriptor.should == [:keywords] if truffleruby?
411+
info.arguments.should == [{a: 1}] if truffleruby?
412+
end
413+
414+
it "work through Thread#new" do
415+
info = Thread.new(a: 1) do |*args, **kwargs|
416+
ArgumentsDescriptorSpecs::Info.new([args, kwargs], Primitive.arguments_descriptor, Primitive.arguments)
417+
end.value
418+
info.values.should == [[], {a: 1}]
419+
# TODO: info.descriptor.should == [:keywords] if truffleruby?
420+
info.arguments.should == [{a: 1}] if truffleruby?
421+
end
422+
423+
it "work through Fiber#resume" do
424+
info = Fiber.new do |*args, **kwargs|
425+
ArgumentsDescriptorSpecs::Info.new([args, kwargs], Primitive.arguments_descriptor, Primitive.arguments)
426+
end.resume(a: 1)
427+
info.values.should == [[], {a: 1}]
428+
info.descriptor.should == [:keywords] if truffleruby?
429+
info.arguments.should == [{a: 1}] if truffleruby?
430+
end
431+
432+
# CRuby behavior, but probably a bug: https://bugs.ruby-lang.org/issues/18621
433+
it "Fiber.yield loses the fact it was kwargs from Fiber#resume" do
434+
f = Fiber.new do
435+
args = Fiber.yield
436+
args
437+
end
438+
f.resume
439+
args = f.resume(a: 1)
440+
Hash.ruby2_keywords_hash?(args).should == false
441+
args.should == {a: 1}
442+
end
378443
end

src/main/java/org/truffleruby/RubyContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import org.truffleruby.language.LexicalScope;
6767
import org.truffleruby.language.RubyBaseNode;
6868
import org.truffleruby.language.SafepointManager;
69+
import org.truffleruby.language.arguments.EmptyArgumentsDescriptor;
6970
import org.truffleruby.language.backtrace.BacktraceFormatter;
7071
import org.truffleruby.language.dispatch.DispatchNode;
7172
import org.truffleruby.language.globals.GlobalVariableStorage;
@@ -322,7 +323,7 @@ protected boolean patch(Env newEnv) {
322323
.getSourceSection()
323324
.getSource();
324325
TranslatorDriver.printParseTranslateExecuteMetric("before-run-delayed-initialization", this, source);
325-
ProcOperations.rootCall((RubyProc) proc);
326+
ProcOperations.rootCall((RubyProc) proc, EmptyArgumentsDescriptor.INSTANCE, RubyBaseNode.EMPTY_ARGUMENTS);
326327
TranslatorDriver.printParseTranslateExecuteMetric("after-run-delayed-initialization", this, source);
327328
}
328329
Metrics.printTime("after-run-delayed-initialization");

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -995,8 +995,9 @@ protected Object callSuper(VirtualFrame frame, Object[] args) {
995995
final MethodLookupResult superMethodLookup = ModuleOperations
996996
.lookupSuperMethod(callingMethod, callingMetaclass);
997997
final InternalMethod superMethod = superMethodLookup.getMethod();
998-
return callSuperMethodNode.execute(frame, callingSelf, superMethod, EmptyArgumentsDescriptor.INSTANCE, args,
999-
nil);
998+
// This C API only passes positional arguments, but maybe it should be influenced by ruby2_keywords hashes?
999+
return callSuperMethodNode.execute(
1000+
frame, callingSelf, superMethod, EmptyArgumentsDescriptor.INSTANCE, args, nil);
10001001
}
10011002

10021003
@TruffleBoundary

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ protected boolean watchSignalProc(Object signalString, boolean isRubyDefaultHand
305305
new SafepointAction("Handling of signal " + signal, rootThread, true, false) {
306306
@Override
307307
public void run(RubyThread rubyThread, Node currentNode) {
308-
ProcOperations.rootCall(action, signal.getNumber());
308+
ProcOperations.rootCall(action, EmptyArgumentsDescriptor.INSTANCE, signal.getNumber());
309309
}
310310
});
311311
}, isRubyDefaultHandler);
@@ -593,17 +593,14 @@ protected int javaVersion() {
593593

594594
@Primitive(name = "arguments")
595595
public abstract static class ArgumentsNode extends PrimitiveArrayArgumentsNode {
596-
597596
@Specialization
598597
protected RubyArray arguments(VirtualFrame frame) {
599598
return createArray(RubyArguments.getArguments(frame));
600599
}
601-
602600
}
603601

604602
@Primitive(name = "arguments_descriptor")
605603
public abstract static class ArgumentsDescriptorNode extends PrimitiveArrayArgumentsNode {
606-
607604
@Specialization
608605
protected RubyArray argumentsDescriptor(VirtualFrame frame) {
609606
return descriptorToArray(RubyArguments.getDescriptor(frame));
@@ -619,7 +616,6 @@ private RubyArray descriptorToArray(ArgumentsDescriptor descriptor) {
619616
throw CompilerDirectives.shouldNotReachHere();
620617
}
621618
}
622-
623619
}
624620

625621
@Primitive(name = "vm_native_argv")

src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import org.truffleruby.language.RubyNode;
4444
import org.truffleruby.language.RubySourceNode;
4545
import org.truffleruby.language.Visibility;
46-
import org.truffleruby.language.arguments.EmptyArgumentsDescriptor;
4746
import org.truffleruby.language.arguments.ReadCallerFrameNode;
4847
import org.truffleruby.language.arguments.RubyArguments;
4948
import org.truffleruby.language.control.RaiseException;
@@ -373,9 +372,14 @@ protected Object instanceEval(
373372

374373
@Specialization
375374
protected Object instanceEval(
376-
Object receiver, NotProvided string, NotProvided fileName, NotProvided line, RubyProc block,
375+
VirtualFrame frame,
376+
Object receiver,
377+
NotProvided string,
378+
NotProvided fileName,
379+
NotProvided line,
380+
RubyProc block,
377381
@Cached InstanceExecNode instanceExecNode) {
378-
return instanceExecNode.executeInstanceExec(receiver, new Object[]{ receiver }, block);
382+
return instanceExecNode.executeInstanceExec(frame, receiver, new Object[]{ receiver }, block);
379383
}
380384

381385
@Specialization
@@ -434,17 +438,17 @@ public static InstanceExecNode create() {
434438

435439
@Child private CallBlockNode callBlockNode = CallBlockNode.create();
436440

437-
abstract Object executeInstanceExec(Object self, Object[] args, RubyProc block);
441+
abstract Object executeInstanceExec(VirtualFrame frame, Object self, Object[] args, RubyProc block);
438442

439443
@Specialization
440-
protected Object instanceExec(Object receiver, Object[] arguments, RubyProc block) {
444+
protected Object instanceExec(VirtualFrame frame, Object receiver, Object[] arguments, RubyProc block) {
441445
final DeclarationContext declarationContext = new DeclarationContext(
442446
Visibility.PUBLIC,
443447
new SingletonClassOfSelfDefaultDefinee(receiver),
444448
block.declarationContext.getRefinements());
445-
return callBlockNode
446-
.executeCallBlock(declarationContext, block, receiver, block.block,
447-
EmptyArgumentsDescriptor.INSTANCE, arguments);
449+
var descriptor = RubyArguments.getDescriptor(frame);
450+
return callBlockNode.executeCallBlock(
451+
declarationContext, block, receiver, block.block, descriptor, arguments);
448452
}
449453

450454
@Specialization

src/main/java/org/truffleruby/core/binding/BindingNodes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ public static MaterializedFrame newFrame(MaterializedFrame parent, FrameDescript
128128
null,
129129
RubyArguments.getSelf(parent),
130130
RubyArguments.getBlock(parent),
131+
RubyArguments.getDescriptor(parent),
131132
RubyArguments.getArguments(parent)),
132133
descriptor).materialize();
133134
}

src/main/java/org/truffleruby/core/fiber/FiberManager.java

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import org.truffleruby.core.thread.ThreadManager;
2828
import org.truffleruby.core.thread.ThreadManager.BlockingAction;
2929
import org.truffleruby.language.SafepointAction;
30+
import org.truffleruby.language.arguments.ArgumentsDescriptor;
31+
import org.truffleruby.language.arguments.EmptyArgumentsDescriptor;
3032
import org.truffleruby.language.control.BreakException;
3133
import org.truffleruby.language.control.DynamicReturnException;
3234
import org.truffleruby.language.control.ExitException;
@@ -120,11 +122,12 @@ private void fiberMain(RubyContext context, RubyFiber fiber, RubyProc block, Nod
120122

121123
FiberMessage lastMessage = null;
122124
try {
123-
final Object[] args = handleMessage(fiber, message, currentNode);
125+
var descriptorAndArgs = handleMessage(fiber, message, currentNode);
124126
fiber.status = FiberStatus.RESUMED;
125-
final Object result = ProcOperations.rootCall(block, args);
127+
final Object result = ProcOperations.rootCall(block, descriptorAndArgs.descriptor, descriptorAndArgs.args);
126128

127-
lastMessage = new FiberResumeMessage(FiberOperation.YIELD, fiber, new Object[]{ result });
129+
lastMessage = new FiberResumeMessage(FiberOperation.YIELD, fiber,
130+
EmptyArgumentsDescriptor.INSTANCE, new Object[]{ result });
128131

129132
// Handlers in the same order as in ThreadManager
130133
} catch (KillException | ExitException | RaiseException e) {
@@ -220,13 +223,14 @@ private void assertNotEntered(String reason) {
220223
}
221224

222225
@TruffleBoundary
223-
private Object[] handleMessage(RubyFiber fiber, FiberMessage message, Node currentNode) {
226+
private DescriptorAndArgs handleMessage(RubyFiber fiber, FiberMessage message, Node currentNode) {
224227
// Written as a loop to not grow the stack when processing guest safepoints
225228
while (message instanceof FiberSafepointMessage) {
226229
final FiberSafepointMessage safepointMessage = (FiberSafepointMessage) message;
227230
safepointMessage.action.run(fiber.rubyThread, currentNode);
228231
final RubyFiber sendingFiber = safepointMessage.sendingFiber;
229-
message = resumeAndWait(fiber, sendingFiber, FiberOperation.TRANSFER, SAFEPOINT_ARGS, currentNode);
232+
message = resumeAndWait(fiber, sendingFiber, FiberOperation.TRANSFER,
233+
EmptyArgumentsDescriptor.INSTANCE, SAFEPOINT_ARGS, currentNode);
230234
}
231235

232236
if (message instanceof FiberShutdownMessage) {
@@ -252,21 +256,22 @@ private Object[] handleMessage(RubyFiber fiber, FiberMessage message, Node curre
252256
throw new RaiseException(context, (RubyException) resumeMessage.getArgs()[0]);
253257
}
254258

255-
return resumeMessage.getArgs();
259+
return resumeMessage.getDescriptorAndArgs();
256260
} else {
257261
throw CompilerDirectives.shouldNotReachHere();
258262
}
259263
}
260264

261265
/** Send a resume message to a fiber by posting into its message queue. Doesn't explicitly notify the Java thread
262266
* (although the queue implementation may) and doesn't wait for the message to be received. */
263-
private void resume(RubyFiber fromFiber, RubyFiber fiber, FiberOperation operation, Object... args) {
264-
addToMessageQueue(fiber, new FiberResumeMessage(operation, fromFiber, args));
267+
private void resume(RubyFiber fromFiber, RubyFiber fiber, FiberOperation operation,
268+
ArgumentsDescriptor descriptor, Object... args) {
269+
addToMessageQueue(fiber, new FiberResumeMessage(operation, fromFiber, descriptor, args));
265270
}
266271

267272
@TruffleBoundary
268-
public Object[] transferControlTo(RubyFiber fromFiber, RubyFiber toFiber, FiberOperation operation, Object[] args,
269-
Node currentNode) {
273+
public DescriptorAndArgs transferControlTo(RubyFiber fromFiber, RubyFiber toFiber, FiberOperation operation,
274+
ArgumentsDescriptor descriptor, Object[] args, Node currentNode) {
270275
assert fromFiber.resumingFiber == null;
271276
if (operation == FiberOperation.RESUME) {
272277
fromFiber.resumingFiber = toFiber;
@@ -280,7 +285,7 @@ public Object[] transferControlTo(RubyFiber fromFiber, RubyFiber toFiber, FiberO
280285
if (fromFiber.status == FiberStatus.RESUMED) {
281286
fromFiber.status = FiberStatus.SUSPENDED;
282287
}
283-
final FiberMessage message = resumeAndWait(fromFiber, toFiber, operation, args, currentNode);
288+
final FiberMessage message = resumeAndWait(fromFiber, toFiber, operation, descriptor, args, currentNode);
284289
return handleMessage(fromFiber, message, currentNode);
285290
}
286291

@@ -294,13 +299,13 @@ public Object[] transferControlTo(RubyFiber fromFiber, RubyFiber toFiber, FiberO
294299
* @param fromFiber the current fiber which will soon be suspended
295300
* @param toFiber the fiber we resume or transfer to */
296301
@TruffleBoundary
297-
private FiberMessage resumeAndWait(RubyFiber fromFiber, RubyFiber toFiber, FiberOperation operation, Object[] args,
298-
Node currentNode) {
302+
private FiberMessage resumeAndWait(RubyFiber fromFiber, RubyFiber toFiber, FiberOperation operation,
303+
ArgumentsDescriptor descriptor, Object[] args, Node currentNode) {
299304
final TruffleContext truffleContext = context.getEnv().getContext();
300305
final FiberMessage message = context
301306
.getThreadManager()
302307
.leaveAndEnter(truffleContext, currentNode, () -> {
303-
resume(fromFiber, toFiber, operation, args);
308+
resume(fromFiber, toFiber, operation, descriptor, args);
304309
return waitMessage(fromFiber, currentNode);
305310
});
306311
fromFiber.rubyThread.setCurrentFiber(fromFiber);
@@ -441,18 +446,34 @@ public String getFiberDebugInfo(RubyThread rubyThread) {
441446
}
442447
}
443448

449+
public static final class DescriptorAndArgs {
450+
public final ArgumentsDescriptor descriptor;
451+
public final Object[] args;
452+
453+
public DescriptorAndArgs(ArgumentsDescriptor descriptor, Object[] args) {
454+
this.descriptor = descriptor;
455+
this.args = args;
456+
}
457+
}
458+
444459
public interface FiberMessage {
445460
}
446461

447462
private static class FiberResumeMessage implements FiberMessage {
448463

449464
private final FiberOperation operation;
450465
private final RubyFiber sendingFiber;
466+
private final ArgumentsDescriptor descriptor;
451467
private final Object[] args;
452468

453-
public FiberResumeMessage(FiberOperation operation, RubyFiber sendingFiber, Object[] args) {
469+
public FiberResumeMessage(
470+
FiberOperation operation,
471+
RubyFiber sendingFiber,
472+
ArgumentsDescriptor descriptor,
473+
Object[] args) {
454474
this.operation = operation;
455475
this.sendingFiber = sendingFiber;
476+
this.descriptor = descriptor;
456477
this.args = args;
457478
}
458479

@@ -464,10 +485,17 @@ public RubyFiber getSendingFiber() {
464485
return sendingFiber;
465486
}
466487

488+
public ArgumentsDescriptor getDescriptor() {
489+
return descriptor;
490+
}
491+
467492
public Object[] getArgs() {
468493
return args;
469494
}
470495

496+
public DescriptorAndArgs getDescriptorAndArgs() {
497+
return new DescriptorAndArgs(descriptor, args);
498+
}
471499
}
472500

473501
private static class FiberSafepointMessage implements FiberMessage {

0 commit comments

Comments
 (0)