Class: Ruby2CExtension::Plugins::InlineBuiltin

Inherits:
Ruby2CExtension::Plugin show all
Extended by:
Util
Includes:
Util
Defined in:
lib/ruby2cext/plugins/inline_builtin.rb

Constant Summary collapse

Class2Type =
{
    NilClass => "T_NIL",
    FalseClass => "T_FALSE",
    TrueClass => "T_TRUE",
    Fixnum => "T_FIXNUM",
    Symbol => "T_SYMBOL",
    Float => "T_FLOAT",
    Bignum => "T_BIGNUM",
    Regexp => "T_REGEXP",
    String => "T_STRING",
    Array => "T_ARRAY",
    Hash => "T_HASH",
}
Class2Match =
{
    NilClass => lambda { |obj|
        %{(#{obj} == Qnil)}
    },
    FalseClass => lambda { |obj|
        %{(#{obj} == Qfalse)}
    },
    TrueClass => lambda { |obj|
        %{(#{obj} == Qtrue)}
    },
    Fixnum => lambda { |obj|
        %{FIXNUM_P(#{obj})}
    },
    Symbol => lambda { |obj|
        %{SYMBOL_P(#{obj})}
    },
    Float => lambda { |obj|
        %{(!SPECIAL_CONST_P(#{obj}) && (RBASIC(#{obj})->klass == rb_cFloat))}
    },
    Bignum => lambda { |obj|
        %{(!SPECIAL_CONST_P(#{obj}) && (RBASIC(#{obj})->klass == rb_cBignum))}
    },
    Regexp => lambda { |obj|
        %{(!SPECIAL_CONST_P(#{obj}) && (RBASIC(#{obj})->klass == rb_cRegexp))}
    },
    String => lambda { |obj|
        %{(!SPECIAL_CONST_P(#{obj}) && (RBASIC(#{obj})->klass == rb_cString))}
    },
    Array => lambda { |obj|
        %{(!SPECIAL_CONST_P(#{obj}) && (RBASIC(#{obj})->klass == rb_cArray))}
    },
    Hash => lambda { |obj|
        %{(!SPECIAL_CONST_P(#{obj}) && (RBASIC(#{obj})->klass == rb_cHash))}
    },
}
COMMON =
{
    [:equal?,1] => {nil => lambda { |cfun, this, that|
        %{(#{this} == (#{that}) ? Qtrue : Qfalse)}
    }},
    [:'eql?',1] => {nil => lambda { |cfun, this, that|
        %{(#{this} == (#{that}) ? Qtrue : Qfalse)}
    }},
    [:'==',1] => {nil => lambda { |cfun, this, that|
        %{(#{this} == (#{that}) ? Qtrue : Qfalse)}
    }},
    [:'===',1] => {nil => lambda { |cfun, this, that|
        %{(#{this} == (#{that}) ? Qtrue : Qfalse)}
    }},
    [:'=~',1] => {nil => lambda { |cfun, this, that|
        %{Qfalse}
    }},
    [:'nil?',0] => lambda { |cfun, this|
        %{Qfalse}
    },
    [:'class',0] => lambda { |cfun, this|
        %{rb_obj_class(#{this})}
    },
}
INLINE =
{}

Instance Attribute Summary

Attributes inherited from Ruby2CExtension::Plugin

#compiler

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

args_arity, deduce_type, split_args, values

Methods inherited from Ruby2CExtension::Plugin

#global_c_code, #init_c_code

Constructor Details

#initialize(compiler) ⇒ InlineBuiltin

Returns a new instance of InlineBuiltin.



11
12
13
14
15
16
17
# File 'lib/ruby2cext/plugins/inline_builtin.rb', line 11

def initialize(compiler)
    super(compiler)
    compiler.add_preprocessor(:call, &method(:call))
    compiler.add_preprocessor(:vcall, &method(:call))
    compiler.add_preprocessor(:fcall, &method(:call))
    compiler.add_preprocessor(:inline_pass, &method(:inline_pass))
end

Class Method Details

.fixnum_binary(reuse = false) ⇒ Object

:yield: cfun, op, this, that



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/ruby2cext/plugins/inline_builtin.rb', line 264

def self.fixnum_binary(reuse=false) # :yield: cfun, op, this, that
    fix2long = lambda { |val|
        val.clone.gsub!(/\ALONG2FIX\((\d+)\)\Z/, '\1') or
        %{FIX2LONG(#{val})}
    }
    {
        Fixnum => lambda { |cfun, this, that|
            this = fix2long[this]
            that = fix2long[that]
            if reuse
                c_scope_res {
                    cfun.l("long a = #{this};")
                    cfun.l("long b = #{that};")
                    yield(cfun, "a", "b")
                }
            else
                yield(cfun, this, that)
            end
        }
    }
end

.float_binary(reuse = false) ⇒ Object

:yield: cfun, op, this, that



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/ruby2cext/plugins/inline_builtin.rb', line 371

def self.float_binary(reuse=false) # :yield: cfun, op, this, that
    handle = lambda { |cfun, this, that|
        this = %{RFLOAT(#{this})->value}
        if reuse
            c_scope_res {
                cfun.l("double a = #{this};")
                cfun.l("double b = #{that};")
                yield(cfun, "a", "b")
            }
        else
            yield(cfun, this, that)
        end
    }
    {
        Fixnum => lambda { |cfun, this, that|
            handle[cfun, this, %{((double)FIX2LONG(#{that}))}]
        },
        Float => lambda { |cfun, this, that|
            handle[cfun, this, %{RFLOAT(#{that})->value}]
        },
        Bignum => lambda { |cfun, this, that|
            handle[cfun, this, %{rb_big2dbl(#{that})}]
        },
    }
end

Instance Method Details

#call(cfun, node) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ruby2cext/plugins/inline_builtin.rb', line 19

def call(cfun, node)
    hash = node.last
    recv = hash[:recv] || [:self, {}]
    klass = deduce_type(recv)
    inline = INLINE[klass]
    inline0 = klass ? INLINE[nil] : {}
    mid = hash[:mid]
    args = hash[:args] || [:array, []]
    if :array==args.first and arity = args.last.size and
            m = (inline[[mid, arity]] || inline0[[mid, arity]])
        args = args.last
    elsif m = (inline[mid] || inline0[mid])
        return m[cfun, node, recv, args]
    else
        return node
    end
    if arity==0
        return values(cfun, (m.arity<0) ? 1 : 0, recv, &m)
    end
    args = args.clone
    first = args.shift
    if klass = deduce_type(first)
        if f = m[klass]
            return values(cfun, (f.arity<0) ? (arity+1) : 0, recv, first, *args, &f)
        else
            return node
        end
    end
    reuse = false
    m.each_value { |f| reuse = false if f.arity<0 }
    default = m[nil]
    size = m.size - (default ? 1 : 0)
    default ||= lambda { |cfun, recv, *args|
        cfun.comp([:inline_pass, :call, {
            :recv => recv,
            :mid => mid,
            :args => [:array, args]
        }])
    }
    values(cfun, reuse ? (arity+1) : 1, first, recv, *args) { |first, recv, *args|
        if size==0
            default[cfun, recv, first, *args]
        elsif size==1
            m.each { |klass, f|
                match = Class2Match[klass] or next
                cfun.c_if(match[first]) {
                    cfun.assign_res(f[cfun, recv, first, *args])
                }
            }
            cfun.c_else {
                cfun.assign_res(default[cfun, recv, first, *args])
            }
            "res"
        else
            cfun.l("switch (TYPE(#{first})) {")
            m.each { |klass, f|
                type = Class2Type[klass] or next
                cfun.l("case #{type}:")
                cfun.assign_res(f[cfun, recv, first, *args])
                cfun.l("break;")
            }
            cfun.l("default:")
                cfun.assign_res(default[cfun, recv, first, *args])
            cfun.l("}")
            "res"
        end
    }
end

#inline_pass(cfun, node) ⇒ Object



88
89
90
91
# File 'lib/ruby2cext/plugins/inline_builtin.rb', line 88

def inline_pass(cfun, node)
    node.shift
    node
end