Skip to content

Conditional assignment of field does two lookups #7891

@headius

Description

@headius

For a simple @a ||= foo it appears we are looking for @a twice, as shown in this IR:

[] jruby $ ruby -Xir.print -e '@a ||= object_id'
2023-08-16T00:10:34.389-05:00 [main] INFO JVMVisitor : Printing JIT IR for -e:
begin SCRIPT_BODY<-e>
flags: [BINDING_HAS_ESCAPED, REQUIRES_DYNSCOPE, REQUIRES_BLOCK, FLAGS_COMPUTED]
signature(pre=0,opt=0,post=0,rest=NONE,kwargs=0,kwreq=0,kwrest=-1)

block #1 (out: 7,2): LBL_2:-1
  0:  %v_4 := copy(nil<>)
  1:          push_method_frame(frameName: -e, visibility: PRIVATE)
  2:          push_method_binding

block #2 (out: 3,4,8): LBL_3:-1
  0: %self := recv_self
  1:          line_num(lineNumber: 0, coverage: false, oneshot: false)
  2:  %v_3 := runtime_helper(self<%self>, fstr<@a>, fstr<instance-variable>, helperMethod: IS_DEFINED_INSTANCE_VAR)
  3:  %v_2 := copy(%v_3)
  4:          b_nil(ipc<LBL_1:10>, %v_3, jumpTarget: LBL_1:10, value: %v_3)

block #3 (out: 4,8): LBL_4:-1
  0:  %v_4 := get_field(self<%self>, name: @a)
  1:  %v_2 := copy(%v_4)

block #4 (out: 5,6,8): LBL_1:10
  0:          b_true(ipc<LBL_0:15>, %v_2, jumpTarget: LBL_0:15, value: %v_2)

block #5 (out: 7,8): LBL_5:-1
  0:  %v_5 := call_0o(self<%self>, callType: VARIABLE, name: object_id, potentiallyRefined: false, flags: 0)
  1:          put_field(self<%self>, %v_5, name: @a, operand1: %self, operand2: %v_5)
  2:          pop_binding
  3:          pop_method_frame
  4:          return(%v_5)

block #8 (out: 7): _GLOBAL_ENSURE_BLOCK__0:-1
  0:  %v_6 := recv_jruby_exc
  1:          pop_binding
  2:          pop_method_frame
  3:          throw(%v_6)

block #7 (out: 8): LBL_6:-1
  0:          return(nil<>)

block #6 (out: 7,8): LBL_0:15
  0:          pop_binding
  1:          pop_method_frame
  2:          return(%v_4)

The defined part of the lookup uses the IS_DEFINED_INSTANCE_VAR runtime helper, which by necessity will try to access the instance vars of the class and check for the given name.

If it is defined, it does a second lookup via get_field.

This should be reduced to a single operation.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions