Skip to content

ZJIT: Write elements to an array at once on Insn::NewArray #829

@k0kubun

Description

@k0kubun

Insn::NewArray calls rb_ary_push for each element, which is slower than what the interpreter does (rb_ec_ary_new_from_values).

For example, this code:

def test(a, b, c, d)
  [a, b, c, d]
end

test(1, 2, 3, 4)

results in:

  # Insn: v23 NewArray v15, v16, v17, v18
  # save PC to CFP
  0x5ff7238370fe: movabs r11, 0x5ff7463eae40
  0x5ff723837108: mov qword ptr [r13], r11
  # call rb_ary_new_capa
  0x5ff72383710c: push rsi
  0x5ff72383710d: push rdx
  0x5ff72383710e: push rcx
  0x5ff72383710f: push r8
  0x5ff723837111: mov edi, 4
  0x5ff723837116: call 0x5ff727c8f6e0
  0x5ff72383711b: pop r8
  0x5ff72383711d: pop rcx
  0x5ff72383711e: pop rdx
  0x5ff72383711f: pop rsi
  # call rb_ary_push
  0x5ff723837120: mov rdi, rax
  0x5ff723837123: push rdi
  0x5ff723837124: push rsi
  0x5ff723837125: push rdx
  0x5ff723837126: push rcx
  0x5ff723837127: push r8
  0x5ff723837129: push r8
  0x5ff72383712b: call 0x5ff727c8a510
  0x5ff723837130: pop r8
  0x5ff723837132: pop r8
  0x5ff723837134: pop rcx
  0x5ff723837135: pop rdx
  0x5ff723837136: pop rsi
  0x5ff723837137: pop rdi
  # call rb_ary_push
  0x5ff723837138: push rdi
  0x5ff723837139: push rsi
  0x5ff72383713a: push rdx
  0x5ff72383713b: push rcx
  0x5ff72383713c: push r8
  0x5ff72383713e: push r8
  0x5ff723837140: mov rsi, rdx
  0x5ff723837143: call 0x5ff727c8a510
  0x5ff723837148: pop r8
  0x5ff72383714a: pop r8
  0x5ff72383714c: pop rcx
  0x5ff72383714d: pop rdx
  0x5ff72383714e: pop rsi
  0x5ff72383714f: pop rdi
  # call rb_ary_push
  0x5ff723837150: push rdi
  0x5ff723837151: push rsi
  0x5ff723837152: push rdx
  0x5ff723837153: push rcx
  0x5ff723837154: push r8
  0x5ff723837156: push r8
  0x5ff723837158: mov rsi, rcx
  0x5ff72383715b: call 0x5ff727c8a510
  0x5ff723837160: pop r8
  0x5ff723837162: pop r8
  0x5ff723837164: pop rcx
  0x5ff723837165: pop rdx
  0x5ff723837166: pop rsi
  0x5ff723837167: pop rdi
  # call rb_ary_push
  0x5ff723837168: push rdi
  0x5ff723837169: push rsi
  0x5ff72383716a: push rdx
  0x5ff72383716b: push rcx
  0x5ff72383716c: push r8
  0x5ff72383716e: push r8
  0x5ff723837170: mov rsi, r8
  0x5ff723837173: call 0x5ff727c8a510
  0x5ff723837178: pop r8
  0x5ff72383717a: pop r8
  0x5ff72383717c: pop rcx
  0x5ff72383717d: pop rdx
  0x5ff72383717e: pop rsi
  0x5ff72383717f: pop rdi

but we shouldn't need to make 5 different C function calls.

Similarly to Insn::NewHash, gen_new_array should use gen_push_opnds and make a single C function call of rb_ec_ary_new_from_values, which newarray in insns.def uses. YJIT uses that function too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions