diff --git a/src/main/c/cext/call.c b/src/main/c/cext/call.c index 01c9dae594be..606fe007da96 100644 --- a/src/main/c/cext/call.c +++ b/src/main/c/cext/call.c @@ -214,3 +214,7 @@ VALUE rb_eval_cmd_kw(VALUE cmd, VALUE args, int kw_splat) { return RUBY_CEXT_INVOKE("rb_eval_string", cmd); } } + +int rb_frame_method_id_and_class(ID *idp, VALUE *klassp) { + return RUBY_CEXT_INVOKE("rb_frame_method_id_and_class", idp, klassp); +} diff --git a/src/main/java/org/truffleruby/cext/CExtNodes.java b/src/main/java/org/truffleruby/cext/CExtNodes.java index f95e527881d2..8e77678b3f20 100644 --- a/src/main/java/org/truffleruby/cext/CExtNodes.java +++ b/src/main/java/org/truffleruby/cext/CExtNodes.java @@ -2071,4 +2071,35 @@ RubyArray zlibGetCRCTable() { } } + @CoreMethod(names = "rb_frame_method_and_id", onSingleton = true, required = 2) + public abstract static class FrameMethodAndId extends CoreMethodArrayArgumentsNode { + + @Specialization + boolean frameMethodAndId(Object frameMethod, Object frameId) { + final Frame callingMethodFrame = findCallingMethodFrame(); + frameMethod = RubyArguments.getMethod(callingMethodFrame); + frameId = System.identityHashCode(RubyArguments.tryGetSelf(callingMethodFrame)); + return true; + } + + @TruffleBoundary + private static Frame findCallingMethodFrame() { + return Truffle.getRuntime().iterateFrames(frameInstance -> { + final Frame frame = frameInstance.getFrame(FrameAccess.READ_ONLY); + + final InternalMethod method = RubyArguments.tryGetMethod(frame); + + if (method == null) { + return null; + } else if (method.getName().equals(/* Truffle::CExt. */ "rb_frame_method_and_id") || + method.getName().equals(/* Truffle::Interop */ "execute_without_conversion")) { + // TODO CS 11-Mar-17 must have a more precise check to skip these methods + return null; + } else { + return frame; + } + }); + } + } + }