Class: JIT::Function

Inherits:
Object
  • Object
show all
Defined in:
lib/jit/function.rb,
ext/jit_ext.c

Defined Under Namespace

Classes: Case, If, Loop

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.build(*args, &block) ⇒ Object

Create a JIT::Context and compile a new function within that context.



193
194
195
196
197
# File 'lib/jit/function.rb', line 193

def self.build(*args, &block)
  JIT::Context.build do |context|
    JIT::Function.compile(context, *args, &block)
  end
end

.function=(Function) {|function| ... } ⇒ Object

Create a new function, begin compiling it, and pass the function to the block.

Yields:

  • (function)


392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'ext/jit_ext.c', line 392

static VALUE function_s_compile(int argc, VALUE * argv, VALUE klass)
{
  VALUE function = create_function(argc, argv, klass);
  rb_yield(function);
  function_compile(function);
#ifdef HAVE_RB_ENSURE
  rb_ensure(
      function_compile,
      function,
      function_abandon_if_exception,
      function);
#else
  /* Rubinius does not yet have rb_ensure */
  function_compile(function);
  function_abandon_if_exception(function);
#endif
  return function;
}

.level=(function) ⇒ Object

Get the maximum optimization level (which should be the same for any function).



948
949
950
951
# File 'ext/jit_ext.c', line 948

static VALUE function_max_optimization_level(VALUE klass)
{
  return INT2NUM(jit_function_get_max_optimization_level());
}

.function=(Function) ⇒ Object

Create a new function.



364
365
366
367
368
369
370
371
372
# File 'ext/jit_ext.c', line 364

static VALUE function_s_new(int argc, VALUE * argv, VALUE klass)
{
  if(rb_block_given_p())
  {
    rb_raise(rb_eArgError, "Function.new does not take a block");
  }

  return create_function(argc, argv, klass);
}

Instance Method Details

#apply(arg1[, arg2 [, ... ]]) ⇒ Object Also known as: call

Call a compiled function. Each argument passed in will be converted to the type specified by the function’s signature.

If the function’s signature is Type::RUBY_VARARG_SIGNATURE, then the arguments will be passed in with the first parameter the count of the number of arguments, the second parameter a pointer to an array containing the second through the last argument, and the third parameter the explicit self (that is, the first argument passed to apply).



771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
# File 'ext/jit_ext.c', line 771

static VALUE function_apply(int argc, VALUE * argv, VALUE self)
{
  jit_function_t function;
  jit_type_t signature;
  int j, n;
  void * * args;
  char * arg_data;
  int signature_tag;

  Data_Get_Struct(self, struct _jit_function, function);
  signature = jit_function_get_signature(function);
  n = jit_type_num_params(signature);

  /* void pointers to each of the arguments */
  args = ALLOCA_N(void *, n);

  /* the actual data */
  /* TODO: we need to allocate the proper size (but 8 bytes per arg
   * should be sufficient for now) */
  arg_data = (char *)ALLOCA_N(char, 8 * n);

  signature_tag = (int)jit_function_get_meta(function, RJT_TAG_FOR_SIGNATURE);
  if(signature_tag == JIT_TYPE_FIRST_TAGGED + RJT_RUBY_VARARG_SIGNATURE)
  {
    jit_VALUE result;
    int f_argc = argc - 1;
    VALUE f_self = *(VALUE *)argv;
    VALUE * f_argv = ((VALUE *)argv) + 1;
    void * f_args[3];
    f_args[0] = &f_argc;
    f_args[1] = &f_argv;
    f_args[2] = &f_self;
    jit_function_apply(function, f_args, &result);
    return result;
  }

  if(argc != n)
  {
    rb_raise(
        rb_eArgError,
        "Wrong number of arguments (expected %d but got %d)",
        n,
        argc);
  }

  for(j = 0; j < n; ++j)
  {
    jit_type_t arg_type = jit_type_get_param(signature, j);
    int kind = jit_type_get_kind(arg_type);
    switch(kind)
    {
      case JIT_TYPE_INT:
      {
        *(int *)arg_data = NUM2INT(argv[j]);
        args[j] = (int *)arg_data;
        arg_data += sizeof(int);
        break;
      }

      case JIT_TYPE_UINT:
      {
        *(int *)arg_data = NUM2UINT(argv[j]);
        args[j] = (int *)arg_data;
        arg_data += sizeof(int);
        break;
      }

      case JIT_TYPE_FIRST_TAGGED + RJT_OBJECT:
      {
        *(VALUE *)arg_data = argv[j];
        args[j] = (VALUE *)arg_data;
        arg_data += sizeof(VALUE);
        break;
      }

      case JIT_TYPE_FIRST_TAGGED + RJT_ID:
      {
        *(ID *)arg_data = SYM2ID(argv[j]);
        args[j] = (ID *)arg_data;
        arg_data += sizeof(ID);
        break;
      }

      case JIT_TYPE_FIRST_TAGGED + RJT_FUNCTION_PTR:
      {
        *(Void_Function_Ptr *)arg_data =
          (Void_Function_Ptr)NUM2ULONG(rb_to_int(argv[j]));
        args[j] = (Void_Function_Ptr *)(arg_data);
        arg_data += sizeof(Void_Function_Ptr);
        break;
      }

      default:
        rb_raise(rb_eTypeError, "Unsupported type %d", kind);
    }
  }

  {
    jit_type_t return_type = jit_type_get_return(signature);
    int return_kind = jit_type_get_kind(return_type);
    switch(return_kind)
    {
      case JIT_TYPE_INT:
      {
        jit_int result;
        jit_function_apply(function, args, &result);
        return INT2NUM(result);
      }

      case JIT_TYPE_FLOAT32:
      {
        jit_float32 result;
        jit_function_apply(function, args, &result);
        return rb_float_new(result);
      }

      case JIT_TYPE_FLOAT64:
      {
        jit_float64 result;
        jit_function_apply(function, args, &result);
        return rb_float_new(result);
      }

      case JIT_TYPE_FIRST_TAGGED + RJT_OBJECT:
      {
        jit_VALUE result;
        jit_function_apply(function, args, &result);
        return result;
      }

      case JIT_TYPE_FIRST_TAGGED + RJT_ID:
      {
        jit_ID result;
        jit_function_apply(function, args, &result);
        return ID2SYM(result);
      }

      default:
        rb_raise(rb_eTypeError, "Unsupported return type %d", return_kind);
    }
  }
}

#case(value) ⇒ Object

An abstraction for a multi-way conditional.

Example usage:

function.case(value1)
.when(value2) {
  # value1 == value2
}.when(value3) {
  # value1 == value3
} .else {
  # all other cases fell through
} .end

Caution: if you omit end, then the generated code will have undefined behavior, but there will be no warning generated.



90
91
92
# File 'lib/jit/function.rb', line 90

def case(value)
  return Case.new(self, value)
end

#compileObject

Begin compiling a function.



347
348
349
350
351
352
353
354
355
356
# File 'ext/jit_ext.c', line 347

static VALUE function_compile(VALUE self)
{
  jit_function_t function;
  Data_Get_Struct(self, struct _jit_function, function);
  if(!jit_function_compile(function))
  {
    rb_raise(rb_eRuntimeError, "Unable to compile function");
  }
  return self;
}

#is_compiled=(function) ⇒ Boolean

Determine whether a function is compiled.

Returns:

  • (Boolean)


1013
1014
1015
1016
1017
1018
# File 'ext/jit_ext.c', line 1013

static VALUE function_is_compiled(VALUE self)
{
  jit_function_t function;
  Data_Get_Struct(self, struct _jit_function, function);
  return jit_function_is_compiled(function) ? Qtrue : Qfalse;
}

#value=(function) ⇒ Object

Create a constant value with the given type.



563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
# File 'ext/jit_ext.c', line 563

static VALUE function_const(VALUE self, VALUE type_v, VALUE constant)
{
  jit_function_t function;
  jit_type_t type;
  jit_value_t value;

  Data_Get_Struct(self, struct _jit_function, function);

  type_v = lookup_const(rb_cType, type_v);
  check_type("type", rb_cType, type_v);
  Data_Get_Struct(type_v, struct _jit_type, type);

  value = create_const(function, type, constant);
  return Data_Wrap_Struct(rb_cValue, 0, 0, value);
}

#context=(function) ⇒ Object

Get a function’s context.



1000
1001
1002
1003
1004
1005
# File 'ext/jit_ext.c', line 1000

static VALUE function_get_context(VALUE self)
{
  jit_function_t function;
  Data_Get_Struct(self, struct _jit_function, function);
  return (VALUE)jit_function_get_meta(function, RJT_CONTEXT);
}

#str=(function) ⇒ Object

Dump the instructions in a function to a string.



959
960
961
962
963
964
965
966
967
968
969
970
971
972
# File 'ext/jit_ext.c', line 959

static VALUE function_dump(VALUE self)
{
#ifdef HAVE_FMEMOPEN
  jit_function_t function;
  char buf[16*1024]; /* TODO: big enough? */
  FILE * fp = fmemopen(buf, sizeof(buf), "w");
  Data_Get_Struct(self, struct _jit_function, function);
  jit_dump_function(fp, function, 0);
  fclose(fp);
  return rb_str_new2(buf);
#else
  rb_raise(rb_eNotImpError, "Not implemented: missing fmemopen");
#endif
}

#get_param(idx) ⇒ Object

Get the value that corresponds to a specified function parameter.

call-seq:

value = function.get_param(index)


417
418
419
420
421
422
423
424
425
# File 'ext/jit_ext.c', line 417

static VALUE function_get_param(VALUE self, VALUE idx)
{
  jit_function_t function;
  jit_value_t value;
  Data_Get_Struct(self, struct _jit_function, function);
  value = jit_value_get_param(function, NUM2INT(idx));
  raise_memory_error_if_zero(value);
  return Data_Wrap_Struct(rb_cValue, 0, 0, value);
}

#if(cond, end_label = Label.new, &block) ⇒ Object

An abstraction for conditionals.

Example usage:

function.if(condition) {
  # condition is true
} .elsif(condition2) {
  # condition2 is true
} .else {
  # condition1 and condition2 are false
} .end

Caution: if you omit end, then the generated code will have undefined behavior, but there will be no warning generated.



19
20
21
22
23
24
25
26
# File 'lib/jit/function.rb', line 19

def if(cond, end_label = Label.new, &block)
  false_label = Label.new
  insn_branch_if_not(cond, false_label)
  block.call
  insn_branch(end_label)
  insn_label(false_label)
  return If.new(self, end_label)
end

#value=(function) ⇒ Object

Generate an instruction to call the specified function.



628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
# File 'ext/jit_ext.c', line 628

static VALUE function_insn_call(int argc, VALUE * argv, VALUE self)
{
  jit_function_t function;

  VALUE name_v;
  VALUE called_function_v;
  VALUE args_v;
  VALUE flags_v = Qnil;

  char const * name;
  jit_function_t called_function;
  jit_type_t signature;
  jit_value_t * args;
  jit_value_t retval;
  int flags;
  size_t num_args;

  rb_scan_args(argc, argv, "3*", &name_v, &called_function_v, &flags_v, &args_v);

  Data_Get_Struct(self, struct _jit_function, function);

  name = STR2CSTR(name_v);

  check_type("called function", rb_cFunction, called_function_v);
  Data_Get_Struct(called_function_v, struct _jit_function, called_function);

  num_args = RARRAY_LEN(args_v);
  args = ALLOCA_N(jit_value_t, num_args);

  signature = jit_function_get_signature(function);
  convert_call_args(function, args, args_v, signature);

  flags = NUM2INT(flags_v);

  retval = jit_insn_call(
      function, name, called_function, 0, args, num_args, flags);
  return Data_Wrap_Struct(rb_cValue, 0, 0, retval);
}

#value=(function) ⇒ Object

Generate an instruction to call a native function.



673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
# File 'ext/jit_ext.c', line 673

static VALUE function_insn_call_native(int argc, VALUE * argv, VALUE self)
{
  jit_function_t function;

  VALUE name_v;
  VALUE args_v;
  VALUE function_ptr_v;
  VALUE signature_v;
  VALUE flags_v;

  char const * name;
  jit_value_t * args;
  jit_value_t retval;
  void * function_ptr;
  jit_type_t signature;
  int flags;
  size_t num_args;

  rb_scan_args(argc, argv, "4*", &name_v, &function_ptr_v, &signature_v, &flags_v, &args_v);

  Data_Get_Struct(self, struct _jit_function, function);
  
  if(SYMBOL_P(name_v))
  {
    name = rb_id2name(SYM2ID(name_v));
  }
  else
  {
    name = StringValuePtr(name_v);
  }

  function_ptr = (void *)NUM2ULONG(function_ptr_v);

  Data_Get_Struct(signature_v, struct _jit_type, signature);

  num_args = RARRAY_LEN(args_v);
  args = ALLOCA_N(jit_value_t, num_args);

  if(num_args != jit_type_num_params(signature))
  {
    rb_raise(
        rb_eArgError,
        "Wrong number of arguments passed for %s (expecting %d but got %d)", 
        name,
        jit_type_num_params(signature),
        num_args);
  }

  convert_call_args(function, args, args_v, signature);

  flags = NUM2INT(flags_v);

  retval = jit_insn_call_native(
      function, name, function_ptr, signature, args, num_args, flags);
  return Data_Wrap_Struct(rb_cValue, 0, 0, retval);
}

#insn_returnObject #insn_return(value) ⇒ Object

Emit an instruction to return from the function. If value is specified, return the given value, otherwise return void.



738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
# File 'ext/jit_ext.c', line 738

static VALUE function_insn_return(int argc, VALUE * argv, VALUE self)
{
  jit_function_t function;
  jit_value_t value = 0;
  VALUE value_v = Qnil;

  rb_scan_args(argc, argv, "01", &value_v);

  if(value_v != Qnil)
  {
    Data_Get_Struct(value_v, struct _jit_value, value);
  }

  Data_Get_Struct(self, struct _jit_function, function);
  jit_insn_return(function, value);

  return Qnil;
}

#level=(function) ⇒ Object

Get the optimization level for a function.



920
921
922
923
924
925
# File 'ext/jit_ext.c', line 920

static VALUE function_optimization_level(VALUE self)
{
  jit_function_t function;
  Data_Get_Struct(self, struct _jit_function, function);
  return INT2NUM(jit_function_get_optimization_level(function));
}

#optimization_level=(level) ⇒ Object

Set the optimization level for a function.



933
934
935
936
937
938
939
# File 'ext/jit_ext.c', line 933

static VALUE function_set_optimization_level(VALUE self, VALUE level)
{
  jit_function_t function;
  Data_Get_Struct(self, struct _jit_function, function);
  jit_function_set_optimization_level(function, NUM2INT(level));
  return level;
}

#param(n) ⇒ Object

An alias for get_param



182
183
184
# File 'lib/jit/function.rb', line 182

def param(n)
  self.get_param(n)
end

#return(result) ⇒ Object

An alias for insn_return



187
188
189
# File 'lib/jit/function.rb', line 187

def return(result)
  self.insn_return(result)
end

#ptr=(function) ⇒ Object

Return a pointer to a closure for a function. This pointer can be passed into other functions as a function pointer.



981
982
983
984
985
986
987
988
989
990
991
992
# File 'ext/jit_ext.c', line 981

static VALUE function_to_closure(VALUE self)
{
  jit_function_t function;
  struct Closure * closure;
  VALUE closure_v = Data_Make_Struct(
      rb_cClosure, struct Closure, mark_closure, free, closure);
  Data_Get_Struct(self, struct _jit_function, function);
  closure->function = self;
  closure->function_ptr =
    (Void_Function_Ptr)jit_function_to_closure(function);
  return closure_v;
}

#unless(cond, end_label = Label.new, &block) ⇒ Object

An abstraction for an inverted conditional.

Example usage:

function.unless(condition) {
  # condition is false
} .elsunless(condition2) {
  # condition2 is false
} .else {
  # condition1 and condition2 are true
} .end

Caution: if you omit end, then the generated code will have undefined behavior, but there will be no warning generated.



42
43
44
45
46
47
48
49
# File 'lib/jit/function.rb', line 42

def unless(cond, end_label = Label.new, &block)
  true_label = Label.new
  insn_branch_if(cond, true_label)
  block.call
  insn_branch(end_label)
  insn_label(true_label)
  return If.new(self, end_label)
end

#until(&block) ⇒ Object

Usage:

until { <condition> }.do { |loop|
  # loop body
} .end


125
126
127
128
129
130
131
132
# File 'lib/jit/function.rb', line 125

def until(&block)
  start_label = Label.new
  done_label = Label.new
  insn_label(start_label)
  insn_branch_if(block.call, done_label)
  loop = Loop.new(self, start_label, done_label)
  return loop
end

#value=(function) ⇒ Object #value=(function) ⇒ Object

Create a value (placeholder/variable) with the given type.



457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'ext/jit_ext.c', line 457

static VALUE function_value(int argc, VALUE * argv, VALUE self)
{
  VALUE type_v = Qnil;
  VALUE initial_value_v = Qnil;

  VALUE new_value = Qnil;

  rb_scan_args(argc, argv, "11", &type_v, &initial_value_v);

  new_value = function_value_klass(self, type_v, rb_cValue);

  if(argc > 1)
  {
    function_insn_store(
        self,
        new_value,
        coerce_to_jit(self, type_v, initial_value_v));
  }

  return new_value;
}

#while(&block) ⇒ Object

Usage:

while { <condition> }.do { |loop|
  # loop body
} .end


140
141
142
143
144
145
146
147
# File 'lib/jit/function.rb', line 140

def while(&block)
  start_label = Label.new
  done_label = Label.new
  insn_label(start_label)
  insn_branch_if_not(block.call, done_label)
  loop = Loop.new(self, start_label, done_label)
  return loop
end