backtracie 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backtracie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivo Anjo
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-16 00:00:00.000000000 Z
11
+ date: 2022-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: debase-ruby_core_source
@@ -45,9 +45,13 @@ files:
45
45
  - README.adoc
46
46
  - backtracie.gemspec
47
47
  - ext/backtracie_native_extension/backtracie.c
48
+ - ext/backtracie_native_extension/backtracie_frames.c
49
+ - ext/backtracie_native_extension/backtracie_private.h
50
+ - ext/backtracie_native_extension/c_test_helpers.c
48
51
  - ext/backtracie_native_extension/extconf.rb
49
- - ext/backtracie_native_extension/ruby_shards.c
50
- - ext/backtracie_native_extension/ruby_shards.h
52
+ - ext/backtracie_native_extension/public/backtracie.h
53
+ - ext/backtracie_native_extension/strbuilder.c
54
+ - ext/backtracie_native_extension/strbuilder.h
51
55
  - lib/backtracie.rb
52
56
  - lib/backtracie/location.rb
53
57
  - lib/backtracie/version.rb
@@ -55,7 +59,7 @@ homepage: https://github.com/ivoanjo/backtracie
55
59
  licenses:
56
60
  - LGPL-3.0+
57
61
  metadata: {}
58
- post_install_message:
62
+ post_install_message:
59
63
  rdoc_options: []
60
64
  require_paths:
61
65
  - lib
@@ -71,8 +75,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
75
  - !ruby/object:Gem::Version
72
76
  version: '0'
73
77
  requirements: []
74
- rubygems_version: 3.1.4
75
- signing_key:
78
+ rubygems_version: 3.3.7
79
+ signing_key:
76
80
  specification_version: 4
77
81
  summary: Ruby gem for beautiful backtraces
78
82
  test_files: []
@@ -1,533 +0,0 @@
1
- // backtracie: Ruby gem for beautiful backtraces
2
- // Copyright (C) 2021 Ivo Anjo <ivo@ivoanjo.me>
3
- //
4
- // This file is part of backtracie.
5
- //
6
- // backtracie is free software: you can redistribute it and/or modify
7
- // it under the terms of the GNU Lesser General Public License as published by
8
- // the Free Software Foundation, either version 3 of the License, or
9
- // (at your option) any later version.
10
- //
11
- // backtracie is distributed in the hope that it will be useful,
12
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- // GNU Lesser General Public License for more details.
15
- //
16
- // You should have received a copy of the GNU Lesser General Public License
17
- // along with backtracie. If not, see <http://www.gnu.org/licenses/>.
18
-
19
- // -----------------------------------------------------------------------------
20
- // The file below has modified versions of code extracted from the Ruby project.
21
- // The Ruby project copyright and license follow:
22
- // -----------------------------------------------------------------------------
23
-
24
- // Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
25
- // You can redistribute it and/or modify it under either the terms of the
26
- // 2-clause BSDL (see the file BSDL), or the conditions below:
27
-
28
- // 1. You may make and give away verbatim copies of the source form of the
29
- // software without restriction, provided that you duplicate all of the
30
- // original copyright notices and associated disclaimers.
31
-
32
- // 2. You may modify your copy of the software in any way, provided that
33
- // you do at least ONE of the following:
34
-
35
- // a. place your modifications in the Public Domain or otherwise
36
- // make them Freely Available, such as by posting said
37
- // modifications to Usenet or an equivalent medium, or by allowing
38
- // the author to include your modifications in the software.
39
-
40
- // b. use the modified software only within your corporation or
41
- // organization.
42
-
43
- // c. give non-standard binaries non-standard names, with
44
- // instructions on where to get the original software distribution.
45
-
46
- // d. make other distribution arrangements with the author.
47
-
48
- // 3. You may distribute the software in object code or binary form,
49
- // provided that you do at least ONE of the following:
50
-
51
- // a. distribute the binaries and library files of the software,
52
- // together with instructions (in the manual page or equivalent)
53
- // on where to get the original distribution.
54
-
55
- // b. accompany the distribution with the machine-readable source of
56
- // the software.
57
-
58
- // c. give non-standard binaries non-standard names, with
59
- // instructions on where to get the original software distribution.
60
-
61
- // d. make other distribution arrangements with the author.
62
-
63
- // 4. You may modify and include the part of the software into any other
64
- // software (possibly commercial). But some files in the distribution
65
- // are not written by the author, so that they are not under these terms.
66
-
67
- // For the list of those files and their copying conditions, see the
68
- // file LEGAL.
69
-
70
- // 5. The scripts and library files supplied as input to or produced as
71
- // output from the software do not automatically fall under the
72
- // copyright of the software, but belong to whomever generated them,
73
- // and may be sold commercially, and may be aggregated with this
74
- // software.
75
-
76
- // 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
77
- // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
78
- // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
79
- // PURPOSE.
80
-
81
- // -----------------------------------------------------------------------------
82
-
83
- // ruby_shards.c contains a number of borrowed functions from the MRI Ruby (usually 3.0.0) source tree:
84
- // * A few were copy-pasted verbatim, and are dependencies for other functions
85
- // * A few were copy-pasted and then changed so we can add features and fixes
86
- // * A few were copy-pasted verbatim, with the objective of backporting their 3.0.0 behavior to earlier Ruby versions
87
- // `git blame` usually documents which functions were added for what reason.
88
-
89
- // Note that since the RUBY_MJIT_HEADER is a very special header, meant for internal use only, it has a number of quirks:
90
- //
91
- // 1. I've seen a few segfaults when trying to call back into original Ruby functions. E.g. even if the API is used
92
- // correctly, just the mere inclusion of RUBY_MJIT_HEADER causes usage to crash. Thus, as much as possible, it's
93
- // better to define functions OUTSIDE this file.
94
- //
95
- // 2. On Windows, I've observed "multiple definition of `something...'" (such as `rb_vm_ep_local_ep') whenever there
96
- // are multiple files in the codebase that include the RUBY_MJIT_HEADER.
97
- // It looks like (some?) Windows versions of Ruby define a bunch of functions in the RUBY_MJIT_HEADER itself
98
- // without marking them as "static" (e.g. not visible to the outside of the file), and thus the linker then complains
99
- // when linking together several files which all have these non-private symbols.
100
- // One possible hacky solution suggested by the internets is to use the "-Wl,-allow-multiple-definition" linker
101
- // flags to ignore this problem; instead I've chosen to implement all usage of the RUBY_MJIT_HEADER on this file --
102
- // no other file in backtracie shall include RUBY_MJIT_HEADER.
103
- // It's a simpler approach, and hopefully avoids any problems.
104
-
105
- #include "extconf.h"
106
-
107
- #ifndef PRE_MJIT_RUBY
108
- #ifndef RUBY_MJIT_HEADER_INCLUDED
109
- #define RUBY_MJIT_HEADER_INCLUDED
110
- #include RUBY_MJIT_HEADER
111
- #endif
112
- #endif
113
-
114
- #include "ruby_shards.h"
115
-
116
- #ifdef PRE_MJIT_RUBY
117
- #include <iseq.h>
118
- #include <regenc.h>
119
- #endif
120
-
121
- #ifdef PRE_EXECUTION_CONTEXT
122
- // The thread and its execution context were separated on Ruby 2.5; prior to that, everything was part of the thread
123
- #define rb_execution_context_t rb_thread_t
124
- #endif
125
-
126
- #ifdef PRE_VM_ENV_RENAMES
127
- #define VM_ENV_LOCAL_P VM_EP_LEP_P
128
- #define VM_ENV_PREV_EP VM_EP_PREV_EP
129
- #define VM_ENV_DATA_INDEX_ME_CREF -1
130
- #define VM_FRAME_RUBYFRAME_P(cfp) RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)
131
- #endif
132
-
133
- /**********************************************************************
134
- vm_backtrace.c -
135
- $Author: ko1 $
136
- created at: Sun Jun 03 00:14:20 2012
137
- Copyright (C) 1993-2012 Yukihiro Matsumoto
138
- **********************************************************************/
139
-
140
- inline static int
141
- calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
142
- {
143
- VM_ASSERT(iseq);
144
- VM_ASSERT(iseq->body);
145
- VM_ASSERT(iseq->body->iseq_encoded);
146
- VM_ASSERT(iseq->body->iseq_size);
147
- if (! pc) {
148
- /* This can happen during VM bootup. */
149
- VM_ASSERT(iseq->body->type == ISEQ_TYPE_TOP);
150
- VM_ASSERT(! iseq->body->local_table);
151
- VM_ASSERT(! iseq->body->local_table_size);
152
- return 0;
153
- }
154
- else {
155
- ptrdiff_t n = pc - iseq->body->iseq_encoded;
156
- VM_ASSERT(n <= iseq->body->iseq_size);
157
- VM_ASSERT(n >= 0);
158
- ASSUME(n >= 0);
159
- size_t pos = n; /* no overflow */
160
- if (LIKELY(pos)) {
161
- /* use pos-1 because PC points next instruction at the beginning of instruction */
162
- pos--;
163
- }
164
- return rb_iseq_line_no(iseq, pos);
165
- }
166
- }
167
-
168
- static VALUE
169
- id2str(ID id)
170
- {
171
- VALUE str = rb_id2str(id);
172
- if (!str) return Qnil;
173
- return str;
174
- }
175
- #define rb_id2str(id) id2str(id)
176
-
177
- // Hacked version of Ruby's rb_profile_frames from Ruby 3.0.0 with the following changes:
178
- // 1. Instead of just using the rb_execution_context_t for the current thread, the context is received as an argument,
179
- // thus allowing the sampling of any thread in the VM, not just the current one.
180
- // 2. It gathers a lot more data: originally you'd get only a VALUE (either iseq or the cme, depending on the case),
181
- // and the line number. The hacked version returns a whole raw_location with a lot more info.
182
- // 3. It correctly ignores the dummy frame at the bottom of the main Ruby thread stack, thus mimicking the behavior of
183
- // Ruby's backtrace_each (which is the function that is used to implement Thread#backtrace and friends)
184
- // 4. Removed the start argument (upstream was broken anyway -- https://github.com/ruby/ruby/pull/2713 -- so we can
185
- // re-add later if needed)
186
- static int backtracie_rb_profile_frames_for_execution_context(
187
- rb_execution_context_t *ec,
188
- int limit,
189
- raw_location *raw_locations
190
- ) {
191
- int i = 0;
192
- const rb_control_frame_t *cfp = ec->cfp;
193
- const rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
194
- const rb_callable_method_entry_t *cme = 0;
195
-
196
- // Hack #3 above: Here we go back one frame in addition to what the original Ruby rb_profile_frames method did.
197
- // Why? According to backtrace_each() in vm_backtrace.c there's two "dummy frames" (what MRI calls them) at the
198
- // bottom of the stack, and we need to skip them both.
199
- // I have no idea why the original rb_profile_frames omits this. Without this, sampling `Thread.main` always
200
- // returned one more frame than the regular MRI APIs (which use the aforementioned backtrace_each internally).
201
- end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp);
202
-
203
- for (i = 0; i < limit && cfp != end_cfp;) {
204
- // Initialize the raw_location, to avoid issues
205
- raw_locations[i].is_ruby_frame = false;
206
- raw_locations[i].should_use_iseq = false;
207
- raw_locations[i].vm_method_type = 0;
208
- raw_locations[i].line_number = 0;
209
- raw_locations[i].iseq = Qnil;
210
- raw_locations[i].callable_method_entry = Qnil;
211
- raw_locations[i].original_id = Qnil;
212
-
213
- // The current object this is getting called on!
214
- raw_locations[i].self = cfp->self;
215
-
216
- cme = rb_vm_frame_method_entry(cfp);
217
-
218
- if (cfp->iseq && !cfp->pc) {
219
- // Do nothing -- this frame should not be used
220
- // Bugfix: rb_profile_frames did not do this (skip a frame when there's no pc), but backtrace_each did, and that
221
- // caused the "Backtracie.backtrace_locations when sampling a map from an enumerable returns the same number of items as the Ruby API"
222
- // test to fail -- Backtracie returned one more frame than Ruby. I suspect that, as usual, this is yet another case where
223
- // rb_profile_frames fails us.
224
- } else if (VM_FRAME_RUBYFRAME_P(cfp)) {
225
- raw_locations[i].is_ruby_frame = true;
226
- raw_locations[i].iseq = (VALUE) cfp->iseq;
227
-
228
- if (cme) {
229
- raw_locations[i].callable_method_entry = (VALUE) cme;
230
- raw_locations[i].vm_method_type = cme->def->type;
231
- }
232
-
233
- if (!(cme && cme->def->type == VM_METHOD_TYPE_ISEQ)) {
234
- // This comes from the original rb_profile_frames logic, which would only return the iseq when the cme
235
- // type is not VM_METHOD_TYPE_ISEQ
236
- raw_locations[i].should_use_iseq = true;
237
- }
238
-
239
- raw_locations[i].line_number = calc_lineno(cfp->iseq, cfp->pc);
240
-
241
- i++;
242
- } else {
243
- if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
244
- raw_locations[i].is_ruby_frame = false;
245
- raw_locations[i].callable_method_entry = (VALUE) cme;
246
- raw_locations[i].vm_method_type = cme->def->type;
247
- raw_locations[i].line_number = 0;
248
- raw_locations[i].original_id = ID2SYM(cme->def->original_id);
249
-
250
- i++;
251
- }
252
- }
253
-
254
- cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
255
- }
256
-
257
- return i;
258
- }
259
-
260
- int backtracie_rb_profile_frames(int limit, raw_location *raw_locations) {
261
- #ifndef PRE_EXECUTION_CONTEXT
262
- return backtracie_rb_profile_frames_for_execution_context(GET_EC(), limit, raw_locations);
263
- #else
264
- // FIXME: Figure out how to make GET_EC (GET_THREAD) work for Ruby <= 2.4
265
- return 0;
266
- #endif
267
- }
268
-
269
- bool backtracie_is_thread_alive(VALUE thread) {
270
- // In here we're assuming that what we got is really a Thread or its subclass. This assumption NEEDS to be verified by
271
- // the caller, otherwise I see a segfault in your future.
272
- rb_thread_t *thread_pointer = (rb_thread_t*) DATA_PTR(thread);
273
-
274
- return !(thread_pointer->to_kill || thread_pointer->status == THREAD_KILLED);
275
- }
276
-
277
- int backtracie_rb_profile_frames_for_thread(VALUE thread, int limit, raw_location *raw_locations) {
278
- if (!backtracie_is_thread_alive(thread)) return 0;
279
-
280
- // In here we're assuming that what we got is really a Thread or its subclass. This assumption NEEDS to be verified by
281
- // the caller, otherwise I see a segfault in your future.
282
- rb_thread_t *thread_pointer = (rb_thread_t*) DATA_PTR(thread);
283
-
284
- #ifndef PRE_EXECUTION_CONTEXT
285
- return backtracie_rb_profile_frames_for_execution_context(thread_pointer->ec, limit, raw_locations);
286
- #else
287
- return backtracie_rb_profile_frames_for_execution_context(thread_pointer, limit, raw_locations);
288
- #endif
289
- }
290
-
291
- VALUE backtracie_called_id(raw_location *the_location) {
292
- if (the_location->callable_method_entry == Qnil) return Qnil;
293
-
294
- return ID2SYM(
295
- ((rb_callable_method_entry_t *) the_location->callable_method_entry)
296
- ->called_id
297
- );
298
- }
299
-
300
- VALUE backtracie_defined_class(raw_location *the_location) {
301
- if (the_location->callable_method_entry == Qnil) return Qnil;
302
-
303
- return \
304
- ((rb_callable_method_entry_t *) the_location->callable_method_entry)
305
- ->defined_class;
306
- }
307
-
308
- bool backtracie_iseq_is_block(raw_location *the_location) {
309
- if (the_location->iseq == Qnil) return false;
310
-
311
- return ((rb_iseq_t *) the_location->iseq)->body->type == ISEQ_TYPE_BLOCK;
312
- }
313
-
314
- bool backtracie_iseq_is_eval(raw_location *the_location) {
315
- if (the_location->iseq == Qnil) return false;
316
-
317
- return ((rb_iseq_t *) the_location->iseq)->body->type == ISEQ_TYPE_EVAL;
318
- }
319
-
320
- VALUE backtracie_refinement_name(raw_location *the_location) {
321
- VALUE defined_class = backtracie_defined_class(the_location);
322
- if (defined_class == Qnil) return Qnil;
323
-
324
- VALUE refinement_module = rb_class_of(defined_class);
325
- if (!FL_TEST(refinement_module, RMODULE_IS_REFINEMENT)) return Qnil;
326
-
327
- // The below bits are inspired by Ruby's rb_mod_to_s(VALUE)
328
- ID id_refined_class;
329
- CONST_ID(id_refined_class, "__refined_class__");
330
- VALUE refined_class = rb_attr_get(refinement_module, id_refined_class);
331
- if (refined_class == Qnil) return Qnil;
332
-
333
- VALUE result = rb_inspect(refined_class);
334
- rb_str_concat(result, rb_str_new2("$refinement@"));
335
- ID id_defined_at;
336
- CONST_ID(id_defined_at, "__defined_at__");
337
- rb_str_concat(result, rb_inspect(rb_attr_get(refinement_module, id_defined_at)));
338
-
339
- return result;
340
- }
341
-
342
- // For more details on the objective of this backport, see the comments on ruby_shards.h
343
- // This is used for Ruby < 3.0.0
344
- #ifdef CFUNC_FRAMES_BACKPORT_NEEDED
345
-
346
- static const rb_callable_method_entry_t *
347
- cframe(VALUE frame)
348
- {
349
- if (frame == Qnil) return NULL;
350
-
351
- if (RB_TYPE_P(frame, T_IMEMO)) {
352
- switch (imemo_type(frame)) {
353
- case imemo_ment:
354
- {
355
- const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
356
- switch (cme->def->type) {
357
- case VM_METHOD_TYPE_CFUNC:
358
- return cme;
359
- default:
360
- return NULL;
361
- }
362
- }
363
- default:
364
- return NULL;
365
- }
366
- }
367
-
368
- return NULL;
369
- }
370
-
371
- static const rb_iseq_t *
372
- frame2iseq(VALUE frame)
373
- {
374
- if (frame == Qnil) return NULL;
375
-
376
- if (RB_TYPE_P(frame, T_IMEMO)) {
377
- switch (imemo_type(frame)) {
378
- case imemo_iseq:
379
- return (const rb_iseq_t *)frame;
380
- case imemo_ment:
381
- {
382
- const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
383
- switch (cme->def->type) {
384
- case VM_METHOD_TYPE_ISEQ:
385
- return cme->def->body.iseq.iseqptr;
386
- default:
387
- return NULL;
388
- }
389
- }
390
- default:
391
- break;
392
- }
393
- }
394
- rb_bug("frame2iseq: unreachable");
395
- }
396
-
397
- VALUE
398
- backported_rb_profile_frame_method_name(VALUE frame)
399
- {
400
- const rb_callable_method_entry_t *cme = cframe(frame);
401
- if (cme) {
402
- ID mid = cme->def->original_id;
403
- return id2str(mid);
404
- }
405
- const rb_iseq_t *iseq = frame2iseq(frame);
406
- return iseq ? rb_iseq_method_name(iseq) : Qnil;
407
- }
408
-
409
- #endif // CFUNC_FRAMES_BACKPORT_NEEDED
410
-
411
- #ifdef CLASSPATH_BACKPORT_NEEDED
412
- static VALUE
413
- frame2klass(VALUE frame)
414
- {
415
- if (frame == Qnil) return Qnil;
416
-
417
- if (RB_TYPE_P(frame, T_IMEMO)) {
418
- const rb_callable_method_entry_t *cme = (rb_callable_method_entry_t *)frame;
419
-
420
- if (imemo_type(frame) == imemo_ment) {
421
- return cme->defined_class;
422
- }
423
- }
424
- return Qnil;
425
- }
426
-
427
- VALUE
428
- backported_rb_profile_frame_classpath(VALUE frame)
429
- {
430
- VALUE klass = frame2klass(frame);
431
-
432
- if (klass && !NIL_P(klass)) {
433
- if (RB_TYPE_P(klass, T_ICLASS)) {
434
- klass = RBASIC(klass)->klass;
435
- }
436
- else if (FL_TEST(klass, FL_SINGLETON)) {
437
- klass = rb_ivar_get(klass, id__attached__);
438
- if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE))
439
- return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass);
440
- }
441
- return rb_class_path(klass);
442
- }
443
- else {
444
- return Qnil;
445
- }
446
- }
447
-
448
- // Oddly enough, this method is on debug.h BUT NOT on the MJIT header. Since I've had
449
- // crashes when trying to combine the MJIT header with the regular Ruby headers, let's
450
- // just supply the declaration for this function, as otherwise the build seems to fail
451
- // on macOS in CI.
452
- VALUE rb_profile_frame_singleton_method_p(VALUE frame);
453
-
454
- static VALUE
455
- qualified_method_name(VALUE frame, VALUE method_name)
456
- {
457
- if (method_name != Qnil) {
458
- VALUE classpath = backported_rb_profile_frame_classpath(frame);
459
- VALUE singleton_p = rb_profile_frame_singleton_method_p(frame);
460
-
461
- if (classpath != Qnil) {
462
- return rb_sprintf("%"PRIsVALUE"%s%"PRIsVALUE,
463
- classpath, singleton_p == Qtrue ? "." : "#", method_name);
464
- }
465
- else {
466
- return method_name;
467
- }
468
- }
469
- else {
470
- return Qnil;
471
- }
472
- }
473
-
474
- VALUE
475
- backported_rb_profile_frame_qualified_method_name(VALUE frame)
476
- {
477
- VALUE method_name = backported_rb_profile_frame_method_name(frame);
478
-
479
- return qualified_method_name(frame, method_name);
480
- }
481
- #endif // CLASSPATH_BACKPORT_NEEDED
482
-
483
- #ifdef PRE_MJIT_RUBY
484
-
485
- // A few extra functions copied from the Ruby sources, needed to support Ruby < 2.6
486
-
487
- /**********************************************************************
488
- vm_insnhelper.c - instruction helper functions.
489
- $Author$
490
- Copyright (C) 2007 Koichi Sasada
491
- **********************************************************************/
492
-
493
- static rb_callable_method_entry_t *
494
- check_method_entry(VALUE obj, int can_be_svar)
495
- {
496
- if (obj == Qfalse) return NULL;
497
-
498
- #if VM_CHECK_MODE > 0
499
- if (!RB_TYPE_P(obj, T_IMEMO)) rb_bug("check_method_entry: unknown type: %s", rb_obj_info(obj));
500
- #endif
501
-
502
- switch (imemo_type(obj)) {
503
- case imemo_ment:
504
- return (rb_callable_method_entry_t *)obj;
505
- case imemo_cref:
506
- return NULL;
507
- case imemo_svar:
508
- if (can_be_svar) {
509
- return check_method_entry(((struct vm_svar *)obj)->cref_or_me, FALSE);
510
- }
511
- default:
512
- #if VM_CHECK_MODE > 0
513
- rb_bug("check_method_entry: svar should not be there:");
514
- #endif
515
- return NULL;
516
- }
517
- }
518
-
519
- const rb_callable_method_entry_t *
520
- rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
521
- {
522
- const VALUE *ep = cfp->ep;
523
- rb_callable_method_entry_t *me;
524
-
525
- while (!VM_ENV_LOCAL_P(ep)) {
526
- if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me;
527
- ep = VM_ENV_PREV_EP(ep);
528
- }
529
-
530
- return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
531
- }
532
-
533
- #endif