ruby/tool/ruby_vm/views/_leaf_helpers.erb
Peter Zhu 3e09822407 Fix incorrect line numbers in GC hook
If the previous instruction is not a leaf instruction, then the PC was
incremented before the instruction was ran (meaning the currently
executing instruction is actually the previous instruction), so we
should not increment the PC otherwise we will calculate the source
line for the next instruction.

This bug can be reproduced in the following script:

```
require "objspace"

ObjectSpace.trace_object_allocations_start
a =

  1.0 / 0.0
p [ObjectSpace.allocation_sourceline(a), ObjectSpace.allocation_sourcefile(a)]
```

Which outputs: [4, "test.rb"]

This is incorrect because the object was allocated on line 10 and not
line 4. The behaviour is correct when we use a leaf instruction (e.g.
if we replaced `1.0 / 0.0` with `"hello"`), then the output is:
[10, "test.rb"].

[Bug #19456]
2023-02-24 14:10:09 -05:00

79 lines
1.9 KiB
Text

%# -*- C -*-
%# Copyright (c) 2018 Urabe, Shyouhei. All rights reserved.
%#
%# This file is a part of the programming language Ruby. Permission is hereby
%# granted, to either redistribute and/or modify this file, provided that the
%# conditions mentioned in the file COPYING are met. Consult the file for
%# details.
%;
#line <%= __LINE__ + 1 %> <%=cstr __FILE__ %>
#include "iseq.h"
extern const bool rb_vm_insn_leaf_p[];
#ifdef RUBY_VM_INSNS_INFO
const bool rb_vm_insn_leaf_p[] = {
% RubyVM::Instructions.each_slice(20) do |insns|
<%= insns.map do |insn|
if insn.is_a?(RubyVM::BareInstructions)
insn.always_leaf? ? '1' : '0'
else
'0'
end
end.join(', ')
%>,
% end
};
#endif
CONSTFUNC(MAYBE_UNUSED(static bool insn_leaf_p(VALUE insn)));
bool
insn_leaf_p(VALUE insn)
{
return rb_vm_insn_leaf_p[insn];
}
// This is used to tell MJIT that this insn would be leaf if CHECK_INTS didn't exist.
// It should be used only when RUBY_VM_CHECK_INTS is directly written in insns.def.
static bool leafness_of_check_ints = false;
static bool
leafness_of_defined(rb_num_t op_type)
{
/* see also: vm_insnhelper.c:vm_defined() */
switch (op_type) {
case DEFINED_IVAR:
case DEFINED_GVAR:
case DEFINED_CVAR:
case DEFINED_YIELD:
case DEFINED_REF:
case DEFINED_ZSUPER:
return false;
case DEFINED_CONST:
case DEFINED_CONST_FROM:
/* has rb_autoload_load(); */
return false;
case DEFINED_FUNC:
case DEFINED_METHOD:
/* calls #respond_to_missing? */
return false;
default:
rb_bug("unknown operand %ld: blame @shyouhei.", op_type);
}
}
static bool
leafness_of_checkmatch(rb_num_t flag)
{
/* see also: vm_insnhelper.c:check_match() */
if (flag == VM_CHECKMATCH_TYPE_WHEN) {
return true;
}
else {
/* has rb_funcallv() */
return false;
}
}
#pragma RubyVM reset source