1 of 9

Meetup #70

monochrome

2 of 9

fn add(jit: &mut monoasm::JitMemory, lhs: u64, rhs: u64) -> monoasm::DestLabel {

let overflow = jit.label();

monoasm! { jit,

subq R(lhs), 1;

addq R(lhs), R(rhs);

jo overflow;

}

overflow

}

improvement in monoasm

  • ジャンプの飛び先などを表すラベル構造体 DestLabel
  • label()で新しいラベルを取得できる
  • ジャンプ命令を先に作っておき、飛ぶ先のコードは後で作る、という使い方もできる。

fn overflow(jit: &mut JitMemory, overflow: DestLabel, deopt: DestLabel) {

monoasm! {jit,

overflow:

movq rdi, (Value::symbol_from_str("_arith_overflow").id());

jmp deopt;

}

}

3 of 9

Problem

  • DestLabel構造体の実体は単なるusize(コピー自由)
  • fixupに必要な情報はJitMemory内にある
  • finalize()で全ラベルのfixupを行う
  • ラベルの数がどんどん増えていくとfixupの手間もどんどん増える
  • 「今後使われ得ないラベル」は削除したい

0f

80

xx

xx

xx

xx

label:

calculate displacement

Fixup

4 of 9

Solution

  • DestLabel構造体をRcに変更
  • fixupに必要な情報はDestLabel自身が保持
  • 実アドレスと紐づけられた時点でfixupを行う
  • 「今後使われ得ないラベル」は自動的に削除される

pub struct DestLabel(std::rc::Rc<std::cell::RefCell<LabelInfo>>);

5 of 9

optimization in monoruby:specialization

Integer#times

1000.times do |i|

puts i

end

class Integer

def times

..

end

end

do |i|

puts i

end

100.times do |i,j|

i+j

end

do |i,j|

i+j

end

100.times do |*i|

i

end

do |*i|

i

end

class Integer

def times

..

end

end

6 of 9

optimization in monoruby:specialization

1000.times do |i|

puts i

end

do |i|

puts i

end

def times

unless block_given?

return self.to_enum(:times)

end

i = 0

while i < self

yield i

i += 1

end

self

end

7 of 9

optimization in monoruby:specialization

1000.times do |i|

puts i

end

do |i|

puts i

end

def times

unless block_given?

return self.to_enum(:times)

end

i = 0

while i < 1000

yield i

i += 1

end

1000

end

self == 100

block_given? == true

8 of 9

optimization in monoruby:specialization

BEFORE

| | 3.4.1 --yjit| monoruby| monoruby --no-jit|

|:----------------------|------------:|------------:|-----------------:|

|integer_times | 76.192k| 138.327k| 108.395k|

|integer_step | 59.779k| 132.380k| 102.997k|

|array_each | 31.639k| 169.738k| 129.978k|

|array_map | 26.003k| 135.393k| 107.073k|

|array_map_ | 26.527k| 133.081k| 105.664k|

|array_each_with_index | 25.428k| 56.232k| 58.778k|

AFTER

| | 3.4.1 --yjit| monoruby| monoruby --no-jit|

|:----------------------|------------:|------------:|-----------------:|

|integer_times | 83.943k| 439.358k| 48.489k|

|integer_step | 69.005k| 439.353k| 47.679k|

|array_each | 35.721k| 185.300k| 40.710k|

|array_map | 29.547k| 131.570k| 30.951k|

|array_map_ | 29.705k| 165.150k| 32.933k|

|array_each_with_index | 27.931k| 182.880k| 26.492k|

9 of 9

optimization in monoruby:specialization

Class#new

class Class

def new(...)

o = allocate

o.initialize(...) if o.respond_to?(:initialize)

o

end

end

  • selfのpolymorphism:
    • Array.new, Hash.new, ...
  • argument forwarding