mirror of
https://github.com/ruby/ruby.git
synced 2025-08-26 22:45:03 +02:00

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]
79 lines
1.9 KiB
Text
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
|