diff --git a/.gitignore b/.gitignore index e6db8b164850..8c162e4600eb 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,7 @@ test/mri/tests/cext-c/**/depend # Diagnostic output directory dumps/ graal_dumps/ +/native-image-build-rubyvm.json # Profiling profiles/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 90a312ea5007..198c1be45ebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Compatibility: Performance: +* Optimize calls with `ruby2_keywords` forwarding by deciding it per call site instead of per callee thanks to [my fix in CRuby 3.2](https://bugs.ruby-lang.org/issues/18625) (@eregon). Changes: diff --git a/mx.truffleruby/env_files.md b/mx.truffleruby/env_files.md index 0767af3819b7..6820576e45f5 100644 --- a/mx.truffleruby/env_files.md +++ b/mx.truffleruby/env_files.md @@ -9,7 +9,7 @@ Here is how the various env files relate to each other: * `jvm-ee-ntl`: + native toolchain launchers * `jvm-ee-libgraal`: + libgraal * `native-ee`: + librubyvm + `Truffle Macro Enterprise` + Native Image G1 + * `native-ee-host-inlining`: + `TruffleHostInliningPrintExplored`, - native toolchain launchers * `native-ee-aux`: + `AuxiliaryEngineCache`, - Native Image G1 (currently incompatible) - * `jvm-gu`: + Graal Updater * `jvm-js`: + Graal.js * `jvm-py`: + GraalPython diff --git a/mx.truffleruby/jvm-gu b/mx.truffleruby/jvm-gu deleted file mode 100644 index f94d2e4fb563..000000000000 --- a/mx.truffleruby/jvm-gu +++ /dev/null @@ -1,3 +0,0 @@ -GRAALVM_SKIP_ARCHIVE=true -DYNAMIC_IMPORTS=/tools,/vm -COMPONENTS=TruffleRuby,suite:tools,gu diff --git a/mx.truffleruby/native-ee-host-inlining b/mx.truffleruby/native-ee-host-inlining new file mode 100644 index 000000000000..518a1bcc34c4 --- /dev/null +++ b/mx.truffleruby/native-ee-host-inlining @@ -0,0 +1,9 @@ +GRAALVM_SKIP_ARCHIVE=true +DYNAMIC_IMPORTS=/tools,/truffleruby-enterprise,/graal-enterprise,/substratevm-enterprise,substratevm-enterprise-gcs +COMPONENTS=TruffleRuby,suite:tools,GraalVM enterprise compiler,Truffle enterprise,SubstrateVM Enterprise,Truffle Macro Enterprise,suite:substratevm-enterprise-gcs +NATIVE_IMAGES=lib:rubyvm +EXTRA_IMAGE_BUILDER_ARGUMENTS=rubyvm:-H:+UnlockExperimentalVMOptions rubyvm:-H:BuildOutputJSONFile=native-image-build-rubyvm.json rubyvm:-H:Log=HostInliningPhase,~CanonicalizerPhase,~GraphBuilderPhase rubyvm:-H:+TruffleHostInliningPrintExplored rubyvm:-H:-UnlockExperimentalVMOptions rubyvm:-Dgraal.LogFile=host-inlining.txt +GENERATE_DEBUGINFO=false +# To also create the standalone +INSTALLABLES=TruffleRuby +BUILD_TARGETS=GRAALVM,GRAALVM_STANDALONES diff --git a/spec/tags/core/module/ruby2_keywords_tags.txt b/spec/tags/core/module/ruby2_keywords_tags.txt deleted file mode 100644 index c03a4924e2bd..000000000000 --- a/spec/tags/core/module/ruby2_keywords_tags.txt +++ /dev/null @@ -1 +0,0 @@ -fails:Module#ruby2_keywords makes a copy and unmark the Hash when calling a method taking (*args) diff --git a/spec/tags/language/keyword_arguments_tags.txt b/spec/tags/language/keyword_arguments_tags.txt index e8404bc16350..c665387fcf83 100644 --- a/spec/tags/language/keyword_arguments_tags.txt +++ b/spec/tags/language/keyword_arguments_tags.txt @@ -1,2 +1 @@ fails:Keyword arguments raises ArgumentError for missing keyword arguments even if there are extra ones -fails:Keyword arguments delegation does not work with call(*ruby2_keyword_args) with missing ruby2_keywords in between diff --git a/spec/truffle/parsing/fixtures/complex_numbers/with_float_imaginary_part.yaml b/spec/truffle/parsing/fixtures/complex_numbers/with_float_imaginary_part.yaml index ef37eb382b8b..6b8c8adc4482 100644 --- a/spec/truffle/parsing/fixtures/complex_numbers/with_float_imaginary_part.yaml +++ b/spec/truffle/parsing/fixtures/complex_numbers/with_float_imaginary_part.yaml @@ -20,7 +20,6 @@ ast: | methodName = "convert" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ IntegerFixnumLiteralNode diff --git a/spec/truffle/parsing/fixtures/complex_numbers/with_integer_imaginary_part.yaml b/spec/truffle/parsing/fixtures/complex_numbers/with_integer_imaginary_part.yaml index 5f39c097645f..4d6bd8c26192 100644 --- a/spec/truffle/parsing/fixtures/complex_numbers/with_integer_imaginary_part.yaml +++ b/spec/truffle/parsing/fixtures/complex_numbers/with_integer_imaginary_part.yaml @@ -20,7 +20,6 @@ ast: | methodName = "convert" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ IntegerFixnumLiteralNode diff --git a/spec/truffle/parsing/fixtures/ensure/in_begin_end_block.yaml b/spec/truffle/parsing/fixtures/ensure/in_begin_end_block.yaml index 4b6d9ac3e22e..09e0aceb3794 100644 --- a/spec/truffle/parsing/fixtures/ensure/in_begin_end_block.yaml +++ b/spec/truffle/parsing/fixtures/ensure/in_begin_end_block.yaml @@ -50,7 +50,6 @@ ast: | methodName = "bar" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/ensure/in_module.yaml b/spec/truffle/parsing/fixtures/ensure/in_module.yaml index b64140c3f5a7..09e4aff2dc67 100644 --- a/spec/truffle/parsing/fixtures/ensure/in_module.yaml +++ b/spec/truffle/parsing/fixtures/ensure/in_module.yaml @@ -87,7 +87,6 @@ ast: | methodName = "bar" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_double_splat.yaml b/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_double_splat.yaml index 5bd048e8ed05..ce002657c605 100644 --- a/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_double_splat.yaml +++ b/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_double_splat.yaml @@ -25,7 +25,6 @@ ast: | methodName = "foo" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_double_splat_and_key_value_pairs.yaml b/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_double_splat_and_key_value_pairs.yaml index 4070c176f11d..ead532af4c59 100644 --- a/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_double_splat_and_key_value_pairs.yaml +++ b/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_double_splat_and_key_value_pairs.yaml @@ -32,7 +32,6 @@ ast: | methodName = "foo" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_key_value_pairs_and_double_splat_operator.yaml b/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_key_value_pairs_and_double_splat_operator.yaml index c630d424be18..613c9e2c89b5 100644 --- a/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_key_value_pairs_and_double_splat_operator.yaml +++ b/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_key_value_pairs_and_double_splat_operator.yaml @@ -46,7 +46,6 @@ ast: | methodName = "bar" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_key_value_pairs_double_splat_operator_and_key_value_pairs.yaml b/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_key_value_pairs_double_splat_operator_and_key_value_pairs.yaml index 43837f39eeb8..5039d3b2c424 100644 --- a/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_key_value_pairs_double_splat_operator_and_key_value_pairs.yaml +++ b/spec/truffle/parsing/fixtures/hashes/with_double_splat_operator/with_key_value_pairs_double_splat_operator_and_key_value_pairs.yaml @@ -47,7 +47,6 @@ ast: | methodName = "bar" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/disabled/when_method_call.yaml b/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/disabled/when_method_call.yaml index 9bf20847be9d..0502d6f5a1b4 100644 --- a/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/disabled/when_method_call.yaml +++ b/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/disabled/when_method_call.yaml @@ -38,7 +38,6 @@ ast: | methodName = "bar" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_complex_literal.yaml b/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_complex_literal.yaml index 0d1b0fb43078..e5f02f7c4fc0 100644 --- a/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_complex_literal.yaml +++ b/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_complex_literal.yaml @@ -38,7 +38,6 @@ ast: | methodName = "convert" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ IntegerFixnumLiteralNode diff --git a/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_rational_literal.yaml b/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_rational_literal.yaml index e359da2f586b..45f2940631bf 100644 --- a/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_rational_literal.yaml +++ b/spec/truffle/parsing/fixtures/rescue/backtrace_optimization/enabled/when_rational_literal.yaml @@ -38,7 +38,6 @@ ast: | methodName = "convert" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ IntegerFixnumLiteralNode diff --git a/spec/truffle/parsing/fixtures/rescue/capturing/with_attribute.yaml b/spec/truffle/parsing/fixtures/rescue/capturing/with_attribute.yaml index 505fa511daf3..b94ca4e13161 100644 --- a/spec/truffle/parsing/fixtures/rescue/capturing/with_attribute.yaml +++ b/spec/truffle/parsing/fixtures/rescue/capturing/with_attribute.yaml @@ -74,7 +74,6 @@ ast: | methodName = "foo=" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ DeadNode @@ -97,7 +96,6 @@ ast: | methodName = "a" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/rescue/capturing/with_element_reference.yaml b/spec/truffle/parsing/fixtures/rescue/capturing/with_element_reference.yaml index 66900b48bc0b..48ec8203eff0 100644 --- a/spec/truffle/parsing/fixtures/rescue/capturing/with_element_reference.yaml +++ b/spec/truffle/parsing/fixtures/rescue/capturing/with_element_reference.yaml @@ -92,7 +92,6 @@ ast: | methodName = "a" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/disabled/when_method_call.yaml b/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/disabled/when_method_call.yaml index 51f10c24c0cc..3b864a7b912e 100644 --- a/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/disabled/when_method_call.yaml +++ b/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/disabled/when_method_call.yaml @@ -34,7 +34,6 @@ ast: | methodName = "bar" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: receiver = SelfNode diff --git a/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_complex_literal.yaml b/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_complex_literal.yaml index a2c4dc56c914..3f73cd77e038 100644 --- a/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_complex_literal.yaml +++ b/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_complex_literal.yaml @@ -34,7 +34,6 @@ ast: | methodName = "convert" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ IntegerFixnumLiteralNode diff --git a/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_rational_literal.yaml b/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_rational_literal.yaml index 650eefe776fc..8750b16601c4 100644 --- a/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_rational_literal.yaml +++ b/spec/truffle/parsing/fixtures/rescue/modifier/backtrace_optimization/enabled/when_rational_literal.yaml @@ -34,7 +34,6 @@ ast: | methodName = "convert" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ IntegerFixnumLiteralNode diff --git a/spec/truffle/parsing/fixtures/strings/backtick_literal.yaml b/spec/truffle/parsing/fixtures/strings/backtick_literal.yaml index 6d8cb9aea64c..48b1ee5e985d 100644 --- a/spec/truffle/parsing/fixtures/strings/backtick_literal.yaml +++ b/spec/truffle/parsing/fixtures/strings/backtick_literal.yaml @@ -21,7 +21,6 @@ ast: | methodName = "`" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ StringLiteralNode diff --git a/spec/truffle/parsing/fixtures/strings/backtick_literal_with_interpolation.yaml b/spec/truffle/parsing/fixtures/strings/backtick_literal_with_interpolation.yaml index 54fd97024858..3023f8c19505 100644 --- a/spec/truffle/parsing/fixtures/strings/backtick_literal_with_interpolation.yaml +++ b/spec/truffle/parsing/fixtures/strings/backtick_literal_with_interpolation.yaml @@ -21,7 +21,6 @@ ast: | methodName = "`" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ InterpolatedStringNode diff --git a/spec/truffle/parsing/fixtures/strings/backtick_literal_with_interpolation_without_expression.yaml b/spec/truffle/parsing/fixtures/strings/backtick_literal_with_interpolation_without_expression.yaml index 64d51ab4a5e3..73e510f5f172 100644 --- a/spec/truffle/parsing/fixtures/strings/backtick_literal_with_interpolation_without_expression.yaml +++ b/spec/truffle/parsing/fixtures/strings/backtick_literal_with_interpolation_without_expression.yaml @@ -24,7 +24,6 @@ ast: | methodName = "`" notEmptyKeywordsProfile = false notRuby2KeywordsHashProfile = false - ruby2KeywordsHashProfile = false children: arguments = [ InterpolatedStringNode diff --git a/src/main/java/org/truffleruby/builtins/ReturnEnumeratorIfNoBlockNode.java b/src/main/java/org/truffleruby/builtins/ReturnEnumeratorIfNoBlockNode.java index 7ec85eb0fa7f..aaf9b13b620a 100644 --- a/src/main/java/org/truffleruby/builtins/ReturnEnumeratorIfNoBlockNode.java +++ b/src/main/java/org/truffleruby/builtins/ReturnEnumeratorIfNoBlockNode.java @@ -53,7 +53,7 @@ public Object execute(VirtualFrame frame) { final Object[] rubyArgs = RubyArguments.repack(frame.getArguments(), receiver, 0, 1); RubyArguments.setArgument(rubyArgs, 0, methodSymbol); - return toEnumNode.execute(null, receiver, "to_enum", rubyArgs, PRIVATE, null); + return toEnumNode.execute(null, receiver, "to_enum", rubyArgs, PRIVATE); } else { return method.execute(frame); } diff --git a/src/main/java/org/truffleruby/cext/CExtNodes.java b/src/main/java/org/truffleruby/cext/CExtNodes.java index e1f289fb286b..9d448c6211e4 100644 --- a/src/main/java/org/truffleruby/cext/CExtNodes.java +++ b/src/main/java/org/truffleruby/cext/CExtNodes.java @@ -1244,7 +1244,7 @@ Object callSuper(VirtualFrame frame, Object[] args, final InternalMethod superMethod = superMethodLookup.getMethod(); // This C API only passes positional arguments, but maybe it should be influenced by ruby2_keywords hashes? return callSuperMethodNode.execute( - frame, callingSelf, superMethod, EmptyArgumentsDescriptor.INSTANCE, args, nil, null); + frame, callingSelf, superMethod, EmptyArgumentsDescriptor.INSTANCE, args, nil); } @TruffleBoundary diff --git a/src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java b/src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java index 958bb2108238..3a24751e6418 100644 --- a/src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java +++ b/src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java @@ -398,8 +398,7 @@ Object instanceExec(VirtualFrame frame, Object receiver, Object[] arguments, Rub new SingletonClassOfSelfDefaultDefinee(receiver), block.declarationContext.getRefinements()); var descriptor = RubyArguments.getDescriptor(frame); - return callBlockNode.executeCallBlock( - declarationContext, block, receiver, nil, descriptor, arguments, null); + return callBlockNode.executeCallBlock(declarationContext, block, receiver, nil, descriptor, arguments); } @Specialization @@ -422,8 +421,7 @@ Object instanceExec(ArgumentsDescriptor descriptor, Object self, Object[] argume new SingletonClassOfSelfDefaultDefinee(self), block.declarationContext.getRefinements()); - return callBlockNode.executeCallBlock( - declarationContext, block, self, nil, descriptor, arguments, null); + return callBlockNode.executeCallBlock(declarationContext, block, self, nil, descriptor, arguments); } } @@ -561,7 +559,7 @@ Object send(Frame callerFrame, Object self, Object[] rubyArgs, RootCallTarget ta @Cached NameToJavaStringNode nameToJavaString) { Object name = RubyArguments.getArgument(rubyArgs, 0); return dispatchNode.execute(callerFrame, self, nameToJavaString.execute(this, name), - RubyArguments.repack(rubyArgs, self, 1), PRIVATE, null); + RubyArguments.repack(rubyArgs, self, 1), PRIVATE); } } diff --git a/src/main/java/org/truffleruby/core/kernel/KernelNodes.java b/src/main/java/org/truffleruby/core/kernel/KernelNodes.java index b34544e8295d..72dd1bccfbca 100644 --- a/src/main/java/org/truffleruby/core/kernel/KernelNodes.java +++ b/src/main/java/org/truffleruby/core/kernel/KernelNodes.java @@ -1396,8 +1396,7 @@ Object send(Frame callerFrame, Object self, Object[] rubyArgs, RootCallTarget ta @Cached NameToJavaStringNode nameToJavaString) { Object name = RubyArguments.getArgument(rubyArgs, 0); Object[] newArgs = RubyArguments.repack(rubyArgs, self, 1); - return dispatchNode.execute(callerFrame, self, nameToJavaString.execute(this, name), newArgs, PUBLIC, - null); + return dispatchNode.execute(callerFrame, self, nameToJavaString.execute(this, name), newArgs, PUBLIC); } } diff --git a/src/main/java/org/truffleruby/core/klass/ClassNodes.java b/src/main/java/org/truffleruby/core/klass/ClassNodes.java index 323f5c340597..10f52820dedb 100644 --- a/src/main/java/org/truffleruby/core/klass/ClassNodes.java +++ b/src/main/java/org/truffleruby/core/klass/ClassNodes.java @@ -288,8 +288,7 @@ Object newInstance(Frame callerFrame, RubyClass rubyClass, Object[] rubyArgs, Ro @Cached DispatchNode allocateNode, @Cached DispatchNode initializeNode) { final Object instance = allocateNode.call(rubyClass, "__allocate__"); - initializeNode.execute(null, instance, "initialize", RubyArguments.repack(rubyArgs, instance), PRIVATE, - null); + initializeNode.execute(null, instance, "initialize", RubyArguments.repack(rubyArgs, instance), PRIVATE); return instance; } diff --git a/src/main/java/org/truffleruby/core/method/MethodNodes.java b/src/main/java/org/truffleruby/core/method/MethodNodes.java index def9676663f0..bf84aa79c209 100644 --- a/src/main/java/org/truffleruby/core/method/MethodNodes.java +++ b/src/main/java/org/truffleruby/core/method/MethodNodes.java @@ -141,7 +141,7 @@ static Object callBoundMethod(Frame frame, InternalMethod internalMethod, Object final Object[] newArgs = RubyArguments.repack(callerRubyArgs, receiver); RubyArguments.setMethod(newArgs, internalMethod); assert RubyArguments.assertFrameArguments(newArgs); - return callInternalMethodNode.execute(frame, internalMethod, receiver, newArgs, null); + return callInternalMethodNode.execute(frame, internalMethod, receiver, newArgs); } } diff --git a/src/main/java/org/truffleruby/core/method/RubyMethod.java b/src/main/java/org/truffleruby/core/method/RubyMethod.java index 1e9dab180685..22b8c4bb6286 100644 --- a/src/main/java/org/truffleruby/core/method/RubyMethod.java +++ b/src/main/java/org/truffleruby/core/method/RubyMethod.java @@ -73,7 +73,7 @@ public Object execute(Object[] arguments, final Object[] convertedArguments = foreignToRubyArgumentsNode.executeConvert(arguments); final Object[] frameArgs = RubyArguments.pack(null, null, method, null, receiver, nil, EmptyArgumentsDescriptor.INSTANCE, convertedArguments); - return callInternalMethodNode.execute(null, method, receiver, frameArgs, null); + return callInternalMethodNode.execute(null, method, receiver, frameArgs); } // endregion diff --git a/src/main/java/org/truffleruby/core/module/ModuleNodes.java b/src/main/java/org/truffleruby/core/module/ModuleNodes.java index bba9e47d4dc3..c3a3b221f434 100644 --- a/src/main/java/org/truffleruby/core/module/ModuleNodes.java +++ b/src/main/java/org/truffleruby/core/module/ModuleNodes.java @@ -808,7 +808,7 @@ Object classExec(ArgumentsDescriptor descriptor, RubyModule self, Object[] args, new FixedDefaultDefinee(self), block.declarationContext.getRefinements()); - return callBlockNode.executeCallBlock(declarationContext, block, self, nil, descriptor, args, null); + return callBlockNode.executeCallBlock(declarationContext, block, self, nil, descriptor, args); } } @@ -2268,8 +2268,7 @@ RubyModule refine(RubyModule namespace, RubyModule moduleToRefine, RubyProc bloc refinement, nil, EmptyArgumentsDescriptor.INSTANCE, - EMPTY_ARGUMENTS, - null); + EMPTY_ARGUMENTS); return refinement; } diff --git a/src/main/java/org/truffleruby/core/proc/ProcNodes.java b/src/main/java/org/truffleruby/core/proc/ProcNodes.java index d11e3db81b28..1c54eca54aae 100644 --- a/src/main/java/org/truffleruby/core/proc/ProcNodes.java +++ b/src/main/java/org/truffleruby/core/proc/ProcNodes.java @@ -166,8 +166,7 @@ Object call(Frame callerFrame, RubyProc proc, Object[] rubyArgs, RootCallTarget ProcOperations.getSelf(proc), RubyArguments.getBlock(rubyArgs), RubyArguments.getDescriptor(rubyArgs), - RubyArguments.getRawArguments(rubyArgs), - null); + RubyArguments.getRawArguments(rubyArgs)); } } diff --git a/src/main/java/org/truffleruby/language/dispatch/DispatchMethodMissingNode.java b/src/main/java/org/truffleruby/language/dispatch/DispatchMethodMissingNode.java index b7c92a69e87a..b7c268fe5d18 100644 --- a/src/main/java/org/truffleruby/language/dispatch/DispatchMethodMissingNode.java +++ b/src/main/java/org/truffleruby/language/dispatch/DispatchMethodMissingNode.java @@ -35,28 +35,18 @@ public abstract class DispatchMethodMissingNode extends RubyBaseNode { public abstract Object execute(Frame frame, Object receiver, String methodName, Object[] rubyArgs, - DispatchConfiguration config, LiteralCallNode literalCallNode); + DispatchConfiguration config); @Specialization(guards = "config.missingBehavior == RETURN_MISSING") static Object dispatchReturnMissing( - Frame frame, - Object receiver, - String methodName, - Object[] rubyArgs, - DispatchConfiguration config, - LiteralCallNode literalCallNode) { + Frame frame, Object receiver, String methodName, Object[] rubyArgs, DispatchConfiguration config) { return MISSING; } @InliningCutoff @Specialization(guards = { "config.missingBehavior == CALL_METHOD_MISSING", "isForeignObject(receiver)" }) static Object dispatchForeign( - Frame frame, - Object receiver, - String methodName, - Object[] rubyArgs, - DispatchConfiguration config, - LiteralCallNode literalCallNode, + Frame frame, Object receiver, String methodName, Object[] rubyArgs, DispatchConfiguration config, @Cached CallForeignMethodNode callForeign) { final Object block = RubyArguments.getBlock(rubyArgs); final Object[] arguments = RubyArguments.getPositionalArguments(rubyArgs); @@ -66,12 +56,7 @@ static Object dispatchForeign( @InliningCutoff @Specialization(guards = { "config.missingBehavior == CALL_METHOD_MISSING", "!isForeignObject(receiver)" }) static Object dispatchMissingMethod( - Frame frame, - Object receiver, - String methodName, - Object[] rubyArgs, - DispatchConfiguration config, - LiteralCallNode literalCallNode, + Frame frame, Object receiver, String methodName, Object[] rubyArgs, DispatchConfiguration config, @Cached ToSymbolNode toSymbol, @Cached DispatchNode callMethodMissing, @Cached InlinedBranchProfile methodMissingMissingProfile, @@ -82,7 +67,7 @@ static Object dispatchMissingMethod( RubyArguments.setArgument(newArgs, 0, symbolName); final Object result = callMethodMissing.execute(frame, receiver, "method_missing", newArgs, - DispatchConfiguration.PRIVATE_RETURN_MISSING_IGNORE_REFINEMENTS, literalCallNode); + DispatchConfiguration.PRIVATE_RETURN_MISSING_IGNORE_REFINEMENTS); if (result == MISSING) { methodMissingMissingProfile.enter(node); diff --git a/src/main/java/org/truffleruby/language/dispatch/DispatchNode.java b/src/main/java/org/truffleruby/language/dispatch/DispatchNode.java index eb9a74043c1e..da0ee9e08bd0 100644 --- a/src/main/java/org/truffleruby/language/dispatch/DispatchNode.java +++ b/src/main/java/org/truffleruby/language/dispatch/DispatchNode.java @@ -59,15 +59,14 @@ public static DispatchNode getUncached() { public abstract Object execute(Frame frame, Object receiver, String methodName, Object[] rubyArgs, - DispatchConfiguration config, - LiteralCallNode literalCallNode); + DispatchConfiguration config); public Object call(DispatchConfiguration config, Object receiver, String method) { final Object[] rubyArgs = RubyArguments.allocate(0); RubyArguments.setSelf(rubyArgs, receiver); RubyArguments.setBlock(rubyArgs, nil); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); - return execute(null, receiver, method, rubyArgs, config, null); + return execute(null, receiver, method, rubyArgs, config); } public Object call(Object receiver, String method) { @@ -75,7 +74,7 @@ public Object call(Object receiver, String method) { RubyArguments.setSelf(rubyArgs, receiver); RubyArguments.setBlock(rubyArgs, nil); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); - return execute(null, receiver, method, rubyArgs, PRIVATE, null); + return execute(null, receiver, method, rubyArgs, PRIVATE); } public Object call(DispatchConfiguration config, Object receiver, String method, Object arg1) { @@ -84,7 +83,7 @@ public Object call(DispatchConfiguration config, Object receiver, String method, RubyArguments.setBlock(rubyArgs, nil); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArgument(rubyArgs, 0, arg1); - return execute(null, receiver, method, rubyArgs, config, null); + return execute(null, receiver, method, rubyArgs, config); } public Object call(Object receiver, String method, Object arg1) { @@ -93,7 +92,7 @@ public Object call(Object receiver, String method, Object arg1) { RubyArguments.setBlock(rubyArgs, nil); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArgument(rubyArgs, 0, arg1); - return execute(null, receiver, method, rubyArgs, PRIVATE, null); + return execute(null, receiver, method, rubyArgs, PRIVATE); } public Object call(DispatchConfiguration config, Object receiver, String method, Object arg1, Object arg2) { @@ -103,7 +102,7 @@ public Object call(DispatchConfiguration config, Object receiver, String method, RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArgument(rubyArgs, 0, arg1); RubyArguments.setArgument(rubyArgs, 1, arg2); - return execute(null, receiver, method, rubyArgs, config, null); + return execute(null, receiver, method, rubyArgs, config); } public Object call(Object receiver, String method, Object arg1, Object arg2) { @@ -113,7 +112,7 @@ public Object call(Object receiver, String method, Object arg1, Object arg2) { RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArgument(rubyArgs, 0, arg1); RubyArguments.setArgument(rubyArgs, 1, arg2); - return execute(null, receiver, method, rubyArgs, PRIVATE, null); + return execute(null, receiver, method, rubyArgs, PRIVATE); } public Object call(Object receiver, String method, Object arg1, Object arg2, Object arg3) { @@ -124,7 +123,7 @@ public Object call(Object receiver, String method, Object arg1, Object arg2, Obj RubyArguments.setArgument(rubyArgs, 0, arg1); RubyArguments.setArgument(rubyArgs, 1, arg2); RubyArguments.setArgument(rubyArgs, 2, arg3); - return execute(null, receiver, method, rubyArgs, PRIVATE, null); + return execute(null, receiver, method, rubyArgs, PRIVATE); } public Object call(DispatchConfiguration config, Object receiver, String method, Object[] arguments) { @@ -133,7 +132,7 @@ public Object call(DispatchConfiguration config, Object receiver, String method, RubyArguments.setBlock(rubyArgs, nil); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArguments(rubyArgs, arguments); - return execute(null, receiver, method, rubyArgs, config, null); + return execute(null, receiver, method, rubyArgs, config); } public Object call(Object receiver, String method, Object[] arguments) { @@ -142,7 +141,7 @@ public Object call(Object receiver, String method, Object[] arguments) { RubyArguments.setBlock(rubyArgs, nil); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArguments(rubyArgs, arguments); - return execute(null, receiver, method, rubyArgs, PRIVATE, null); + return execute(null, receiver, method, rubyArgs, PRIVATE); } public Object callWithKeywords(Object receiver, String method, Object arg1, @@ -153,7 +152,7 @@ public Object callWithKeywords(Object receiver, String method, Object arg1, RubyArguments.setDescriptor(rubyArgs, KeywordArgumentsDescriptorManager.EMPTY); RubyArguments.setArgument(rubyArgs, 0, arg1); RubyArguments.setArgument(rubyArgs, 1, keywords); - return execute(null, receiver, method, rubyArgs, PRIVATE, null); + return execute(null, receiver, method, rubyArgs, PRIVATE); } public Object callWithBlock(Object receiver, String method, Object block) { @@ -161,7 +160,7 @@ public Object callWithBlock(Object receiver, String method, Object block) { RubyArguments.setSelf(rubyArgs, receiver); RubyArguments.setBlock(rubyArgs, block); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); - return execute(null, receiver, method, rubyArgs, PRIVATE, null); + return execute(null, receiver, method, rubyArgs, PRIVATE); } public Object callWithBlock(Object receiver, String method, Object block, Object arg1) { @@ -170,7 +169,7 @@ public Object callWithBlock(Object receiver, String method, Object block, Object RubyArguments.setBlock(rubyArgs, block); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArgument(rubyArgs, 0, arg1); - return execute(null, receiver, method, rubyArgs, PRIVATE, null); + return execute(null, receiver, method, rubyArgs, PRIVATE); } public Object callWithBlock(DispatchConfiguration config, Object receiver, String method, Object block, Object arg1, @@ -181,7 +180,7 @@ public Object callWithBlock(DispatchConfiguration config, Object receiver, Strin RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArgument(rubyArgs, 0, arg1); RubyArguments.setArgument(rubyArgs, 1, arg2); - return execute(null, receiver, method, rubyArgs, config, null); + return execute(null, receiver, method, rubyArgs, config); } public Object callWithBlock(DispatchConfiguration config, Object receiver, String method, Object block, Object arg1, @@ -193,23 +192,17 @@ public Object callWithBlock(DispatchConfiguration config, Object receiver, Strin RubyArguments.setArgument(rubyArgs, 0, arg1); RubyArguments.setArgument(rubyArgs, 1, arg2); RubyArguments.setArgument(rubyArgs, 2, arg3); - return execute(null, receiver, method, rubyArgs, config, null); + return execute(null, receiver, method, rubyArgs, config); } public Object callWithDescriptor(Object receiver, String method, Object block, ArgumentsDescriptor descriptor, Object[] arguments) { - return callWithDescriptor(receiver, method, block, descriptor, arguments, null); - } - - public Object callWithDescriptor(Object receiver, String method, Object block, - ArgumentsDescriptor descriptor, - Object[] arguments, LiteralCallNode literalCallNode) { final Object[] rubyArgs = RubyArguments.allocate(arguments.length); RubyArguments.setSelf(rubyArgs, receiver); RubyArguments.setBlock(rubyArgs, block); RubyArguments.setDescriptor(rubyArgs, descriptor); RubyArguments.setArguments(rubyArgs, arguments); - return execute(null, receiver, method, rubyArgs, PRIVATE, literalCallNode); + return execute(null, receiver, method, rubyArgs, PRIVATE); } public Object callWithFrame(Frame frame, Object receiver, String method) { @@ -217,7 +210,7 @@ public Object callWithFrame(Frame frame, Object receiver, String method) { RubyArguments.setSelf(rubyArgs, receiver); RubyArguments.setBlock(rubyArgs, nil); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); - return execute(frame, receiver, method, rubyArgs, PRIVATE, null); + return execute(frame, receiver, method, rubyArgs, PRIVATE); } public Object callWithFrame(DispatchConfiguration config, Frame frame, Object receiver, String method, @@ -227,7 +220,7 @@ public Object callWithFrame(DispatchConfiguration config, Frame frame, Object re RubyArguments.setBlock(rubyArgs, nil); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArgument(rubyArgs, 0, arg1); - return execute(frame, receiver, method, rubyArgs, config, null); + return execute(frame, receiver, method, rubyArgs, config); } public Object callWithFrame(DispatchConfiguration config, Frame frame, Object receiver, String method, Object arg1, @@ -238,7 +231,7 @@ public Object callWithFrame(DispatchConfiguration config, Frame frame, Object re RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArgument(rubyArgs, 0, arg1); RubyArguments.setArgument(rubyArgs, 1, arg2); - return execute(frame, receiver, method, rubyArgs, config, null); + return execute(frame, receiver, method, rubyArgs, config); } public Object callWithFrame(DispatchConfiguration config, Frame frame, Object receiver, String method, Object arg1, @@ -250,7 +243,7 @@ public Object callWithFrame(DispatchConfiguration config, Frame frame, Object re RubyArguments.setArgument(rubyArgs, 0, arg1); RubyArguments.setArgument(rubyArgs, 1, arg2); RubyArguments.setArgument(rubyArgs, 2, arg3); - return execute(frame, receiver, method, rubyArgs, config, null); + return execute(frame, receiver, method, rubyArgs, config); } public Object callWithFrame(DispatchConfiguration config, Frame frame, Object receiver, String method, @@ -260,7 +253,7 @@ public Object callWithFrame(DispatchConfiguration config, Frame frame, Object re RubyArguments.setBlock(rubyArgs, nil); RubyArguments.setDescriptor(rubyArgs, EmptyArgumentsDescriptor.INSTANCE); RubyArguments.setArguments(rubyArgs, arguments); - return execute(frame, receiver, method, rubyArgs, config, null); + return execute(frame, receiver, method, rubyArgs, config); } public final Object callWithFrameAndBlock(DispatchConfiguration config, Frame frame, Object receiver, @@ -270,17 +263,11 @@ public final Object callWithFrameAndBlock(DispatchConfiguration config, Frame fr RubyArguments.setBlock(rubyArgs, block); RubyArguments.setDescriptor(rubyArgs, descriptor); RubyArguments.setArguments(rubyArgs, arguments); - return execute(frame, receiver, methodName, rubyArgs, config, null); + return execute(frame, receiver, methodName, rubyArgs, config); } @Specialization - Object dispatch( - Frame frame, - Object receiver, - String methodName, - Object[] rubyArgs, - DispatchConfiguration config, - LiteralCallNode literalCallNode, + Object dispatch(Frame frame, Object receiver, String methodName, Object[] rubyArgs, DispatchConfiguration config, @Cached(value = "getSpecialVariableAssumption(frame)", uncached = "ALWAYS_VALID") Assumption specialVariableAssumption, @Cached MetaClassNode metaClassNode, @@ -296,8 +283,7 @@ Object dispatch( final InternalMethod method = lookupMethodNode.execute(frame, metaclass, methodName, config); if (methodMissing.profile(this, method == null || method.isUndefined())) { - return lazyDispatchMethodMissingNode.get(this).execute(frame, receiver, methodName, rubyArgs, config, - literalCallNode); + return lazyDispatchMethodMissingNode.get(this).execute(frame, receiver, methodName, rubyArgs, config); } RubyArguments.setMethod(rubyArgs, method); @@ -307,7 +293,7 @@ Object dispatch( } assert RubyArguments.assertFrameArguments(rubyArgs); - return callNode.execute(frame, method, receiver, rubyArgs, literalCallNode); + return callNode.execute(frame, method, receiver, rubyArgs); } diff --git a/src/main/java/org/truffleruby/language/dispatch/LiteralCallNode.java b/src/main/java/org/truffleruby/language/dispatch/LiteralCallNode.java index f9a76a6c43c7..55f1b6ff9661 100644 --- a/src/main/java/org/truffleruby/language/dispatch/LiteralCallNode.java +++ b/src/main/java/org/truffleruby/language/dispatch/LiteralCallNode.java @@ -20,7 +20,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import org.truffleruby.language.arguments.EmptyArgumentsDescriptor; import org.truffleruby.language.arguments.KeywordArgumentsDescriptor; -import org.truffleruby.language.methods.SharedMethodInfo; +import org.truffleruby.language.arguments.KeywordArgumentsDescriptorManager; /** A literal call site in Ruby code: one of foo(), super or yield. */ public abstract class LiteralCallNode extends RubyContextSourceNode { @@ -29,8 +29,8 @@ public abstract class LiteralCallNode extends RubyContextSourceNode { @Child private CopyHashAndSetRuby2KeywordsNode copyHashAndSetRuby2KeywordsNode; protected final boolean isSplatted; - @CompilationFinal private boolean lastArgIsNotHashProfile, ruby2KeywordsHashProfile, notRuby2KeywordsHashProfile, - emptyKeywordsProfile, notEmptyKeywordsProfile; + @CompilationFinal private boolean lastArgIsNotHashProfile, notRuby2KeywordsHashProfile, emptyKeywordsProfile, + notEmptyKeywordsProfile; protected LiteralCallNode(boolean isSplatted, ArgumentsDescriptor descriptor) { this.isSplatted = isSplatted; @@ -38,7 +38,7 @@ protected LiteralCallNode(boolean isSplatted, ArgumentsDescriptor descriptor) { } // NOTE: args is either frame args or user args - protected boolean isRuby2KeywordsHash(Object[] args, int userArgsCount) { + protected ArgumentsDescriptor getArgumentsDescriptorAndCheckRuby2KeywordsHash(Object[] args, int userArgsCount) { assert isSplatted : "this is only needed if isSplatted"; if (descriptor == EmptyArgumentsDescriptor.INSTANCE) { // *rest and no kwargs passed explicitly (k: v/k => v/**kw) @@ -52,16 +52,13 @@ protected boolean isRuby2KeywordsHash(Object[] args, int userArgsCount) { lastArgIsNotHashProfile = true; } - return false; + return descriptor; } - if (((RubyHash) lastArgument).ruby2_keywords) { // both branches profiled - if (!ruby2KeywordsHashProfile) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - ruby2KeywordsHashProfile = true; - } - - return true; + RubyHash hash = (RubyHash) lastArgument; + if (hash.ruby2_keywords) { // both branches profiled + copyRuby2KeywordsHashBoundary(args, hash); + return KeywordArgumentsDescriptorManager.EMPTY; } else { if (!notRuby2KeywordsHashProfile) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -71,7 +68,7 @@ protected boolean isRuby2KeywordsHash(Object[] args, int userArgsCount) { } } - return false; + return descriptor; } // NOTE: args is either frame args or user args @@ -98,22 +95,16 @@ public static Object[] removeEmptyKeywordArguments(Object[] args) { return ArrayUtils.extractRange(args, 0, args.length - 1); } - // NOTE: args is either frame args or user args - public void copyRuby2KeywordsHash(Object[] args, SharedMethodInfo info) { - if (!info.getArity().hasRest()) { // https://bugs.ruby-lang.org/issues/18625 - copyRuby2KeywordsHashBoundary(args); - } - } - @InliningCutoff - private void copyRuby2KeywordsHashBoundary(Object[] args) { + private void copyRuby2KeywordsHashBoundary(Object[] args, RubyHash hash) { + assert ArrayUtils.getLast(args) == hash && hash.ruby2_keywords; + if (copyHashAndSetRuby2KeywordsNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); copyHashAndSetRuby2KeywordsNode = insert(CopyHashAndSetRuby2KeywordsNode.create()); } - final RubyHash lastArgument = (RubyHash) ArrayUtils.getLast(args); - ArrayUtils.setLast(args, copyHashAndSetRuby2KeywordsNode.execute(lastArgument, false)); + ArrayUtils.setLast(args, copyHashAndSetRuby2KeywordsNode.execute(hash, false)); } } diff --git a/src/main/java/org/truffleruby/language/dispatch/RubyCallNode.java b/src/main/java/org/truffleruby/language/dispatch/RubyCallNode.java index 386192d02908..420a2a4d1728 100644 --- a/src/main/java/org/truffleruby/language/dispatch/RubyCallNode.java +++ b/src/main/java/org/truffleruby/language/dispatch/RubyCallNode.java @@ -29,7 +29,6 @@ import org.truffleruby.language.arguments.ArgumentsDescriptor; import org.truffleruby.language.arguments.EmptyArgumentsDescriptor; import org.truffleruby.language.arguments.KeywordArgumentsDescriptor; -import org.truffleruby.language.arguments.KeywordArgumentsDescriptorManager; import org.truffleruby.language.arguments.RubyArguments; import org.truffleruby.language.arguments.SplatToArgsNode; import org.truffleruby.language.control.RaiseException; @@ -121,20 +120,19 @@ public Object execute(VirtualFrame frame) { Object[] rubyArgs = RubyArguments.allocate(arguments.length); RubyArguments.setSelf(rubyArgs, receiverObject); - ArgumentsDescriptor descriptor = this.descriptor; - boolean ruby2KeywordsHash = false; + final ArgumentsDescriptor descriptor; executeArguments(frame, rubyArgs); if (isSplatted) { rubyArgs = splatArgs(receiverObject, rubyArgs); - ruby2KeywordsHash = isRuby2KeywordsHash(rubyArgs, RubyArguments.getRawArgumentsCount(rubyArgs)); - if (ruby2KeywordsHash) { - descriptor = KeywordArgumentsDescriptorManager.EMPTY; - } + descriptor = getArgumentsDescriptorAndCheckRuby2KeywordsHash(rubyArgs, + RubyArguments.getRawArgumentsCount(rubyArgs)); + } else { + descriptor = this.descriptor; } RubyArguments.setBlock(rubyArgs, executeBlock(frame)); - return doCall(frame, receiverObject, descriptor, rubyArgs, ruby2KeywordsHash); + return doCall(frame, receiverObject, descriptor, rubyArgs); } // Assignment in context of method call means implicit assignment: @@ -166,16 +164,14 @@ public void assign(VirtualFrame frame, Object value) { RubyArguments.setBlock(rubyArgs, executeBlock(frame)); // no ruby2_keywords behavior for assign - doCall(frame, receiverObject, descriptor, rubyArgs, false); + doCall(frame, receiverObject, descriptor, rubyArgs); } - public Object doCall(VirtualFrame frame, Object receiverObject, ArgumentsDescriptor descriptor, Object[] rubyArgs, - boolean ruby2KeywordsHash) { + public Object doCall(VirtualFrame frame, Object receiverObject, ArgumentsDescriptor descriptor, Object[] rubyArgs) { // Remove empty kwargs in the caller, so the callee does not need to care about this special case if (descriptor instanceof KeywordArgumentsDescriptor && emptyKeywordArguments(rubyArgs)) { rubyArgs = removeEmptyKeywordArguments(rubyArgs); descriptor = EmptyArgumentsDescriptor.INSTANCE; - ruby2KeywordsHash = false; } RubyArguments.setDescriptor(rubyArgs, descriptor); @@ -184,8 +180,7 @@ public Object doCall(VirtualFrame frame, Object receiverObject, ArgumentsDescrip dispatch = insert(DispatchNode.create()); } - final Object returnValue = dispatch.execute(frame, receiverObject, methodName, rubyArgs, dispatchConfig, - ruby2KeywordsHash ? this : null); + final Object returnValue = dispatch.execute(frame, receiverObject, methodName, rubyArgs, dispatchConfig); if (isAttrAssign) { final Object value = rubyArgs[rubyArgs.length - 1]; assert RubyGuards.assertIsValidRubyValue(value); @@ -203,7 +198,7 @@ public Object executeWithArgumentsEvaluated(VirtualFrame frame, Object receiverO RubyArguments.setSelf(rubyArgs, receiverObject); RubyArguments.setBlock(rubyArgs, blockObject); RubyArguments.setArguments(rubyArgs, argumentsObjects); - return doCall(frame, receiverObject, descriptor, rubyArgs, false); + return doCall(frame, receiverObject, descriptor, rubyArgs); } private Object executeBlock(VirtualFrame frame) { diff --git a/src/main/java/org/truffleruby/language/methods/CallInternalMethodNode.java b/src/main/java/org/truffleruby/language/methods/CallInternalMethodNode.java index 3e361736ce29..3ef56d5d80cd 100644 --- a/src/main/java/org/truffleruby/language/methods/CallInternalMethodNode.java +++ b/src/main/java/org/truffleruby/language/methods/CallInternalMethodNode.java @@ -38,7 +38,6 @@ import org.truffleruby.language.arguments.RubyArguments; import org.truffleruby.language.control.RaiseException; import org.truffleruby.language.dispatch.DispatchNode; -import org.truffleruby.language.dispatch.LiteralCallNode; @ReportPolymorphism @GenerateUncached @@ -50,10 +49,8 @@ public static CallInternalMethodNode create() { return CallInternalMethodNodeGen.create(); } - /** Callers should use {@link RubyArguments#assertFrameArguments} unless they use {@code RubyArguments#pack}. - * {@code literalCallNode} is only non-null if this was called splatted with a ruby2_keyword Hash. */ - public abstract Object execute(Frame frame, InternalMethod method, Object receiver, Object[] rubyArgs, - LiteralCallNode literalCallNode); + /** Callers should use {@link RubyArguments#assertFrameArguments} unless they use {@code RubyArguments#pack} */ + public abstract Object execute(Frame frame, InternalMethod method, Object receiver, Object[] rubyArgs); @Specialization( guards = { @@ -62,25 +59,17 @@ public abstract Object execute(Frame frame, InternalMethod method, Object receiv "!cachedMethod.alwaysInlined()" }, assumptions = "getMethodAssumption(cachedMethod)", // to remove the inline cache entry when the method is redefined or removed limit = "getCacheLimit()") - Object callCached(InternalMethod method, Object receiver, Object[] rubyArgs, LiteralCallNode literalCallNode, + Object callCached(InternalMethod method, Object receiver, Object[] rubyArgs, @Cached("method.getCallTarget()") RootCallTarget cachedCallTarget, @Cached("method") InternalMethod cachedMethod, @Cached("createCall(cachedMethod.getName(), cachedCallTarget)") DirectCallNode callNode) { - if (literalCallNode != null) { - literalCallNode.copyRuby2KeywordsHash(rubyArgs, cachedMethod.getSharedMethodInfo()); - } - return callNode.call(RubyArguments.repackForCall(rubyArgs)); } @InliningCutoff @Specialization(guards = "!method.alwaysInlined()", replaces = "callCached") - Object callUncached(InternalMethod method, Object receiver, Object[] rubyArgs, LiteralCallNode literalCallNode, + Object callUncached(InternalMethod method, Object receiver, Object[] rubyArgs, @Cached IndirectCallNode indirectCallNode) { - if (literalCallNode != null) { - literalCallNode.copyRuby2KeywordsHash(rubyArgs, method.getSharedMethodInfo()); - } - return indirectCallNode.call(method.getCallTarget(), RubyArguments.repackForCall(rubyArgs)); } @@ -91,8 +80,7 @@ Object callUncached(InternalMethod method, Object receiver, Object[] rubyArgs, L "cachedMethod.alwaysInlined()" }, assumptions = "getMethodAssumption(cachedMethod)", // to remove the inline cache entry when the method is redefined or removed limit = "getCacheLimit()") - static Object alwaysInlined( - Frame frame, InternalMethod method, Object receiver, Object[] rubyArgs, LiteralCallNode literalCallNode, + static Object alwaysInlined(Frame frame, InternalMethod method, Object receiver, Object[] rubyArgs, @Cached("method.getCallTarget()") RootCallTarget cachedCallTarget, @Cached("method") InternalMethod cachedMethod, @Cached("createAlwaysInlinedMethodNode(cachedMethod)") AlwaysInlinedMethodNode alwaysInlinedNode, @@ -104,10 +92,6 @@ static Object alwaysInlined( .acceptsKeywords() : "AlwaysInlinedMethodNodes are currently assumed to not use keyword arguments, the arity check depends on this"; assert RubyArguments.getSelf(rubyArgs) == receiver; - if (literalCallNode != null) { - literalCallNode.copyRuby2KeywordsHash(rubyArgs, cachedMethod.getSharedMethodInfo()); - } - try { int given = RubyArguments.getPositionalArgumentsCount(rubyArgs); if (!cachedArity.checkPositionalArguments(given)) { @@ -141,21 +125,19 @@ private static Object alwaysInlinedException(Node node, RaiseException e, Always } @Specialization(guards = "method.alwaysInlined()", replaces = "alwaysInlined") - Object alwaysInlinedUncached( - Frame frame, InternalMethod method, Object receiver, Object[] rubyArgs, LiteralCallNode literalCallNode) { + Object alwaysInlinedUncached(Frame frame, InternalMethod method, Object receiver, Object[] rubyArgs) { return alwaysInlinedBoundary( frame == null ? null : frame.materialize(), method, receiver, rubyArgs, - literalCallNode, isAdoptable()); } @TruffleBoundary // getUncachedAlwaysInlinedMethodNode(method) and arity are not PE constants private Object alwaysInlinedBoundary( MaterializedFrame frame, InternalMethod method, Object receiver, Object[] rubyArgs, - LiteralCallNode literalCallNode, boolean cachedToUncached) { + boolean cachedToUncached) { EncapsulatingNodeReference encapsulating = null; Node prev = null; if (cachedToUncached) { @@ -168,7 +150,6 @@ private Object alwaysInlinedBoundary( method, receiver, rubyArgs, - literalCallNode, method.getCallTarget(), method, getUncachedAlwaysInlinedMethodNode(method), diff --git a/src/main/java/org/truffleruby/language/methods/SymbolProcNode.java b/src/main/java/org/truffleruby/language/methods/SymbolProcNode.java index ba35b97afa75..285e7cd014e1 100644 --- a/src/main/java/org/truffleruby/language/methods/SymbolProcNode.java +++ b/src/main/java/org/truffleruby/language/methods/SymbolProcNode.java @@ -36,7 +36,7 @@ public Object execute(VirtualFrame frame) { final Object receiver = RubyArguments.getArgument(frame, 0); return getCallNode().execute(frame, receiver, symbol, - RubyArguments.repack(frame.getArguments(), receiver, 1), PUBLIC, null); + RubyArguments.repack(frame.getArguments(), receiver, 1), PUBLIC); } private DispatchNode getCallNode() { diff --git a/src/main/java/org/truffleruby/language/supercall/CallSuperMethodNode.java b/src/main/java/org/truffleruby/language/supercall/CallSuperMethodNode.java index 488dad1deb45..06fa559e5234 100644 --- a/src/main/java/org/truffleruby/language/supercall/CallSuperMethodNode.java +++ b/src/main/java/org/truffleruby/language/supercall/CallSuperMethodNode.java @@ -17,7 +17,6 @@ import org.truffleruby.language.arguments.ArgumentsDescriptor; import org.truffleruby.language.arguments.RubyArguments; import org.truffleruby.language.dispatch.DispatchNode; -import org.truffleruby.language.dispatch.LiteralCallNode; import org.truffleruby.language.methods.CallInternalMethodNode; import org.truffleruby.language.methods.InternalMethod; @@ -50,13 +49,12 @@ public Object execute( InternalMethod superMethod, ArgumentsDescriptor descriptor, Object[] arguments, - Object block, - LiteralCallNode literalCallNode) { + Object block) { if (missingProfile.profile(superMethod == null)) { final String name = RubyArguments.getMethod(frame).getSharedMethodInfo().getMethodNameForNotBlock(); // use the original name final Object[] methodMissingArguments = ArrayUtils.unshift(arguments, getSymbol(name)); - return callMethodMissing(self, block, descriptor, methodMissingArguments, literalCallNode); + return callMethodMissing(self, block, descriptor, methodMissingArguments); } SpecialVariableStorage callerSpecialVariables = null; @@ -67,7 +65,7 @@ public Object execute( final Object[] rubyArgs = RubyArguments.pack( null, callerSpecialVariables, superMethod, null, self, block, descriptor, arguments); - return getCallMethodNode().execute(frame, superMethod, self, rubyArgs, literalCallNode); + return getCallMethodNode().execute(frame, superMethod, self, rubyArgs); } private CallInternalMethodNode getCallMethodNode() { @@ -95,13 +93,12 @@ private Assumption getSpecialVariableStorageAssumption(Frame frame) { } - private Object callMethodMissing(Object receiver, Object block, ArgumentsDescriptor descriptor, Object[] arguments, - LiteralCallNode literalCallNode) { + private Object callMethodMissing(Object receiver, Object block, ArgumentsDescriptor descriptor, + Object[] arguments) { if (callMethodMissingNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); callMethodMissingNode = insert(DispatchNode.create()); } - return callMethodMissingNode.callWithDescriptor(receiver, "method_missing", block, descriptor, arguments, - literalCallNode); + return callMethodMissingNode.callWithDescriptor(receiver, "method_missing", block, descriptor, arguments); } } diff --git a/src/main/java/org/truffleruby/language/supercall/SuperCallNode.java b/src/main/java/org/truffleruby/language/supercall/SuperCallNode.java index e7a9f1e0b0f6..b61c8a25255e 100644 --- a/src/main/java/org/truffleruby/language/supercall/SuperCallNode.java +++ b/src/main/java/org/truffleruby/language/supercall/SuperCallNode.java @@ -16,7 +16,6 @@ import org.truffleruby.language.arguments.ArgumentsDescriptor; import org.truffleruby.language.arguments.EmptyArgumentsDescriptor; import org.truffleruby.language.arguments.KeywordArgumentsDescriptor; -import org.truffleruby.language.arguments.KeywordArgumentsDescriptorManager; import org.truffleruby.language.arguments.RubyArguments; import org.truffleruby.language.dispatch.LiteralCallNode; import org.truffleruby.language.methods.InternalMethod; @@ -45,13 +44,9 @@ public final Object execute(VirtualFrame frame) { Object[] superArguments = (Object[]) arguments.execute(frame); ArgumentsDescriptor descriptor = this.descriptor; - boolean ruby2KeywordsHash = false; if (isSplatted) { // superArguments already splatted - ruby2KeywordsHash = isRuby2KeywordsHash(superArguments, superArguments.length); - if (ruby2KeywordsHash) { - descriptor = KeywordArgumentsDescriptorManager.EMPTY; - } + descriptor = getArgumentsDescriptorAndCheckRuby2KeywordsHash(superArguments, superArguments.length); } // Remove empty kwargs in the caller, so the callee does not need to care about this special case @@ -70,8 +65,7 @@ public final Object execute(VirtualFrame frame) { callSuperMethodNode = insert(CallSuperMethodNode.create()); } - return callSuperMethodNode.execute(frame, self, superMethod, descriptor, superArguments, blockObject, - ruby2KeywordsHash ? this : null); + return callSuperMethodNode.execute(frame, self, superMethod, descriptor, superArguments, blockObject); } @Override diff --git a/src/main/java/org/truffleruby/language/yield/CallBlockNode.java b/src/main/java/org/truffleruby/language/yield/CallBlockNode.java index 274b34be6368..15280305d073 100644 --- a/src/main/java/org/truffleruby/language/yield/CallBlockNode.java +++ b/src/main/java/org/truffleruby/language/yield/CallBlockNode.java @@ -17,7 +17,6 @@ import org.truffleruby.language.arguments.ArgumentsDescriptor; import org.truffleruby.language.arguments.EmptyArgumentsDescriptor; import org.truffleruby.language.arguments.RubyArguments; -import org.truffleruby.language.dispatch.LiteralCallNode; import org.truffleruby.language.methods.DeclarationContext; import com.oracle.truffle.api.RootCallTarget; @@ -42,20 +41,17 @@ public static CallBlockNode getUncached() { return CallBlockNodeGen.getUncached(); } - public final Object yield(RubyProc block, ArgumentsDescriptor descriptor, Object[] args, - LiteralCallNode literalCallNode) { - return executeCallBlock(block.declarationContext, block, ProcOperations.getSelf(block), nil, descriptor, args, - literalCallNode); + public final Object yield(RubyProc block, ArgumentsDescriptor descriptor, Object... args) { + return executeCallBlock(block.declarationContext, block, ProcOperations.getSelf(block), nil, descriptor, args); } public final Object yield(RubyProc block, Object... args) { return executeCallBlock(block.declarationContext, block, ProcOperations.getSelf(block), nil, - EmptyArgumentsDescriptor.INSTANCE, args, null); + EmptyArgumentsDescriptor.INSTANCE, args); } - /** {@code literalCallNode} is only non-null if this was called splatted with a ruby2_keyword Hash. */ public abstract Object executeCallBlock(DeclarationContext declarationContext, RubyProc block, Object self, - Object blockArgument, ArgumentsDescriptor descriptor, Object[] arguments, LiteralCallNode literalCallNode); + Object blockArgument, ArgumentsDescriptor descriptor, Object[] arguments); @Specialization(guards = "block.callTarget == cachedCallTarget", limit = "getCacheLimit()") Object callBlockCached( @@ -65,13 +61,8 @@ Object callBlockCached( Object blockArgument, ArgumentsDescriptor descriptor, Object[] arguments, - LiteralCallNode literalCallNode, @Cached("block.callTarget") RootCallTarget cachedCallTarget, @Cached("createBlockCallNode(cachedCallTarget)") DirectCallNode callNode) { - if (literalCallNode != null) { - literalCallNode.copyRuby2KeywordsHash(arguments, RubyRootNode.of(cachedCallTarget).getSharedMethodInfo()); - } - final Object[] frameArguments = packArguments(declarationContext, block, self, blockArgument, descriptor, arguments); return callNode.call(frameArguments); @@ -85,12 +76,7 @@ Object callBlockUncached( Object blockArgument, ArgumentsDescriptor descriptor, Object[] arguments, - LiteralCallNode literalCallNode, @Cached IndirectCallNode callNode) { - if (literalCallNode != null) { - literalCallNode.copyRuby2KeywordsHash(arguments, block.getSharedMethodInfo()); - } - final Object[] frameArguments = packArguments(declarationContext, block, self, blockArgument, descriptor, arguments); return callNode.call(block.callTarget, frameArguments); diff --git a/src/main/java/org/truffleruby/language/yield/YieldExpressionNode.java b/src/main/java/org/truffleruby/language/yield/YieldExpressionNode.java index 43c97204e9ac..3e96deac036c 100644 --- a/src/main/java/org/truffleruby/language/yield/YieldExpressionNode.java +++ b/src/main/java/org/truffleruby/language/yield/YieldExpressionNode.java @@ -19,7 +19,6 @@ import org.truffleruby.language.arguments.ArgumentsDescriptor; import org.truffleruby.language.arguments.EmptyArgumentsDescriptor; import org.truffleruby.language.arguments.KeywordArgumentsDescriptor; -import org.truffleruby.language.arguments.KeywordArgumentsDescriptorManager; import org.truffleruby.language.control.RaiseException; import com.oracle.truffle.api.CompilerDirectives; @@ -61,13 +60,9 @@ public final Object execute(VirtualFrame frame) { final RubyProc block = (RubyProc) maybeBlock; ArgumentsDescriptor descriptor = this.descriptor; - boolean ruby2KeywordsHash = false; if (isSplatted) { argumentsObjects = unsplat(argumentsObjects); - ruby2KeywordsHash = isRuby2KeywordsHash(argumentsObjects, argumentsObjects.length); - if (ruby2KeywordsHash) { - descriptor = KeywordArgumentsDescriptorManager.EMPTY; - } + descriptor = getArgumentsDescriptorAndCheckRuby2KeywordsHash(argumentsObjects, argumentsObjects.length); } // Remove empty kwargs in the caller, so the callee does not need to care about this special case @@ -76,7 +71,7 @@ public final Object execute(VirtualFrame frame) { descriptor = EmptyArgumentsDescriptor.INSTANCE; } - return getYieldNode().yield(block, descriptor, argumentsObjects, ruby2KeywordsHash ? this : null); + return getYieldNode().yield(block, descriptor, argumentsObjects); } private Object[] unsplat(Object[] argumentsObjects) { diff --git a/test/mri/tests/ruby/test_keyword.rb b/test/mri/tests/ruby/test_keyword.rb index 5b9d2cac796c..12ee9cd9dde3 100644 --- a/test/mri/tests/ruby/test_keyword.rb +++ b/test/mri/tests/ruby/test_keyword.rb @@ -2714,9 +2714,8 @@ def method_missing(*args) assert_equal([1, h1], o.baz(1, h1)) assert_equal([h1], o.baz(h1, **{})) - # TruffleRuby: CRuby copies for #send but not for Proc#call, seems inconsistent - # assert_equal([[1, h1], {}], o.foo(:pass_bar, 1, :a=>1)) - # assert_equal([[1, h1], {}], o.foo(:pass_cfunc, 1, :a=>1)) + assert_equal([[1, h1], {}], o.foo(:pass_bar, 1, :a=>1)) + assert_equal([[1, h1], {}], o.foo(:pass_cfunc, 1, :a=>1)) assert_equal(:opt, o.clear_last_opt(a: 1)) assert_nothing_raised(ArgumentError) { o.clear_last_empty_method(a: 1) } diff --git a/tool/extract_host_inlining.rb b/tool/extract_host_inlining.rb index eaf489c51367..0c4143c4713b 100644 --- a/tool/extract_host_inlining.rb +++ b/tool/extract_host_inlining.rb @@ -45,14 +45,18 @@ } lines = lines.reject { |line| - line.include?('DEAD') and line.include?('reason the invoke is dead code') + line.include?('DEAD') and line.match?(/reason (the invoke is dead code|not a method call target)/) } end # Reduce line width for unimportant information lines = lines.map { |line| - line.sub(/\[inlined\s.+?invoke\s+(true|false),/, '') + line.sub(/\[inlined\s.+?invoke\s+(true|false),\s+/, '') .sub(/,\s*incomplete\s+(true|false),/, ',') + .sub(/frequency\s+1\.0+,\s+/, '') } +min_space_before_cost = lines[2..-1].map { |line| line[/([ ]+)cost /, 1].size }.min +lines = lines.map { |line| line.sub(/[ ]{#{min_space_before_cost}}cost /, ' cost ') } + puts lines.join