Runtime assembler in C++

View: New views
5 Messages — Rating Filter:   Alert me  

Runtime assembler in C++

by Pippijn van Steenhoven :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Lightning List,

I am currently working on a C++ front-end for GNU Lightning. What I have
right now is a working parser for things like this:

  # mnemonic      op1             op2             op3     ret
  prolog          1
  arg_ui                                                  => $in
  getarg_ui       %v0             $in
  blti_ui         !forward        %v0             2       => @ref
  subi_ui         %v1             %v0             1
  subi_ui         %v2             %v0             2
  prepare_i       1
  pusharg_ui      %v1
  finish          @self         # The self-pointer is a pointer to the
                                # beginning of the code block (entry
                                # point). cf. fib.c
  retval_i        %v1
  prepare_i       1
  pusharg_ui      %v2
  finish          @self
  retval_i        %v2
  addi_ui         %v1             %v1             1
  addr_ui         %ret            %v1             %v2
  ret
 
  patch           @ref
  movi_i          %ret            1
  ret
 
This is the "fib" example. It has a limited form of type checking.
basically just whether you are passing imm, reg or insn. I do not yet
have differently sized types. Everything that is an immediate is passed
as int32_t. This might cause breakage on 64 bit platforms but I don't
know how to do the differently sized types, yet. I do not use the macros
directly, anymore. Instead, for each mnemonic, I use a C++ function. This
has produced many error messages. I fixed some, but I don't know whether
the fixes are correct. As far as I can remember (unfortunately I didn't
document my changes, so I'll probably redo them with documentation), I
added an _s32P macro which was used but missing and the LEAQmr
instruction for x86_64 which looks like this:

  #define LEAQmr(MD, MB, MI, MS, RD)      (_REXQmr(MB, MI, RD),           _OO_r_X         (0x8d                ,_r8(RD)           ,MD,MB,MI,MS            ))

I am pretty new to machine code and therefore, I am not sure whether this
code is correct. There is a long list of instructions that do not work on
x86_64 because they do not exist or some other macro is being used
incorrectly. I am aware that x86_64 support is new, but even on i386-32,
many instructions do not exist. If you are interested, I can generate
this list.

The current assembler supports the following checks:

- Type checking (imm, reg, insn)
- Argument count check
- Return value check (it has to be used, even if you discard it)

It can also store the parsed lightning-asm code in a platform independent
(big endian) bytecode format. The parser does not check whether the
instruction exists. It just assumes it does. Only when the code is
actually assembled into machine code or stored to bytecode, these checks
are performed. The bytecode is very simple. Each instruction consists of
a 4-byte header, 0, 1, 2 or 3 argument blocks and an optional return
value block. The header looks like this:

  Bytes         Content
  1             Whether or not the instruction returns a value
  1             Argument count (0, 1, 2 or 3)
  2             Opcode

Each argument block starts with a 1-byte type-code which may be one of
var, label, call, reg_r, reg_v, reg_fp, reg_ret, imm. After that, it
depends on whether the operand is a string or an integer. String operands
are currently only var, label and call. Strings are stored with a 2-byte
length indicator and then the string content. Integers are stored as
4-byte blocks. The optional return block is just a string with its 2-byte
length. It refers to the variable or label name in which the return value
is stored. That's all.

By the way, is there any reason to have more than one "variable"?
Variables are integers returned by an instruction. Currently, the only
instructions that do this in my assembler are the lightning arg_*
instructions. I use a map<string, imm32> for them but I might as well
just store the value and give it a fixed name.

This is a lot of fun and I welcome any comments.

Regards,
 
--
Pippijn van Steenhoven


_______________________________________________
Lightning mailing list
Lightning@...
http://lists.gnu.org/mailman/listinfo/lightning

signature.asc (196 bytes) Download Attachment

Re: Runtime assembler in C++

by Paolo Bonzini-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Pippijn van Steenhoven wrote:

> I do not yet
> have differently sized types. Everything that is an immediate is passed
> as int32_t. This might cause breakage on 64 bit platforms but I don't
> know how to do the differently sized types, yet. I do not use the macros
> directly, anymore. Instead, for each mnemonic, I use a C++ function. This
> has produced many error messages. I fixed some, but I don't know whether
> the fixes are correct. As far as I can remember (unfortunately I didn't
> document my changes, so I'll probably redo them with documentation), I
> added an _s32P macro which was used but missing and the LEAQmr
> instruction for x86_64 which looks like this:
>
>   #define LEAQmr(MD, MB, MI, MS, RD)      (_REXQmr(MB, MI, RD),           _OO_r_X         (0x8d                ,_r8(RD)           ,MD,MB,MI,MS            ))

These two I will look at.

>  There is a long list of instructions that do not work on
> x86_64 because they do not exist or some other macro is being used
> incorrectly. I am aware that x86_64 support is new, but even on i386-32,
> many instructions do not exist. If you are interested, I can generate
> this list.

Yes, thanks!  This can indeed be helpful, if only to stress test the
back-ends.

> By the way, is there any reason to have more than one "variable"?
> Variables are integers returned by an instruction. Currently, the only
> instructions that do this in my assembler are the lightning arg_*
> instructions.

Yes, I don't remember other instructions that return arbitrary integers.
  I don't understand your question exactly, but: 1) there can be >1
argument to a function; 2) you could use fixed names like $1, $2, $3 --
but then, checking that these fixed names were actually defined is
almost as complicated as keeping the map<>.

Paolo


_______________________________________________
Lightning mailing list
Lightning@...
http://lists.gnu.org/mailman/listinfo/lightning

Re: Runtime assembler in C++

by Pippijn van Steenhoven :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Here are the error logs from each backend. Note that jit_state::pointer
is the union. By the way, what is the reason for the many function
pointer types in the jit_code union? Isn't one function pointer and one
data pointer type sufficient? After all, you still have to cast.

--
Pippijn van Steenhoven

== Branch ==

bltr_f          ‘jit_bltr_f’ was not declared in this scope
bler_f          ‘jit_bler_f’ was not declared in this scope
bgtr_f          ‘jit_bgtr_f’ was not declared in this scope
bger_f          ‘jit_bger_f’ was not declared in this scope
beqr_f          ‘jit_beqr_f’ was not declared in this scope
bner_f          ‘jit_bner_f’ was not declared in this scope
bunltr_f        ‘jit_bunltr_f’ was not declared in this scope
bunler_f        ‘jit_bunler_f’ was not declared in this scope
bungtr_f        ‘jit_bungtr_f’ was not declared in this scope
bunger_f        ‘jit_bunger_f’ was not declared in this scope
buneqr_f        ‘jit_buneqr_f’ was not declared in this scope
bltgtr_f        ‘jit_bltgtr_f’ was not declared in this scope
bordr_f         ‘jit_bordr_f’ was not declared in this scope
bunordr_f       ‘jit_bunordr_f’ was not declared in this scope


== Compare ==

ltr_f           ‘jit_ltr_f’ was not declared in this scope
ler_f           ‘jit_ler_f’ was not declared in this scope
gtr_f           ‘jit_gtr_f’ was not declared in this scope
ger_f           ‘jit_ger_f’ was not declared in this scope
eqr_f           ‘jit_eqr_f’ was not declared in this scope
ner_f           ‘jit_ner_f’ was not declared in this scope
unltr_f         ‘jit_unltr_f’ was not declared in this scope
unler_f         ‘jit_unler_f’ was not declared in this scope
ungtr_f         ‘jit_ungtr_f’ was not declared in this scope
unger_f         ‘jit_unger_f’ was not declared in this scope
uneqr_f         ‘jit_uneqr_f’ was not declared in this scope
ltgtr_f         ‘jit_ltgtr_f’ was not declared in this scope
ordr_f          ‘jit_ordr_f’ was not declared in this scope
unordr_f        ‘jit_unordr_f’ was not declared in this scope


== Function ==

prolog  ‘_jit_prolog’ was not declared in this scope
leaf    ‘_jit_prolog’ was not declared in this scope


== Jump ==

ret     ‘_jit_epilog’ was not declared in this scope


== Transfer ==

extr_f_d        ‘jit_extr_f_d’ was not declared in this scope
extr_d_f        ‘jit_extr_d_f’ was not declared in this scope
extr_i_f        ‘jit_extr_i_f’ was not declared in this scope
extr_i_d        ‘jit_extr_i_d’ was not declared in this scope
roundr_f_i      ‘jit_roundr_f_i’ was not declared in this scope
roundr_f_l      ‘jit_roundr_f_l’ was not declared in this scope
roundr_d_l      ‘jit_roundr_d_l’ was not declared in this scope
truncr_f_i      ‘jit_truncr_f_i’ was not declared in this scope
truncr_f_l      ‘jit_truncr_f_l’ was not declared in this scope
truncr_d_l      ‘jit_truncr_d_l’ was not declared in this scope
floorr_f_i      ‘jit_floorr_f_i’ was not declared in this scope
floorr_f_l      ‘jit_floorr_f_l’ was not declared in this scope
floorr_d_l      ‘jit_floorr_d_l’ was not declared in this scope
ceilr_f_i       ‘jit_ceilr_f_i’ was not declared in this scope
ceilr_f_l       ‘jit_ceilr_f_l’ was not declared in this scope
ceilr_d_l       ‘jit_ceilr_d_l’ was not declared in this scope


== Unary ==

negr_f          ‘jit_negr_f’ was not declared in this scope
notr_c          ‘jit_xori_c’ was not declared in this scope
notr_uc         ‘jit_xori_c’ was not declared in this scope
notr_s          ‘jit_xori_s’ was not declared in this scope
notr_us         ‘jit_xori_s’ was not declared in this scope

== Branch ==

bltr_f          ‘jit_bltr_f’ was not declared in this scope
bltr_d          ‘jit_bltr_d’ was not declared in this scope
bler_f          ‘jit_bler_f’ was not declared in this scope
bler_d          ‘jit_bler_d’ was not declared in this scope
bgtr_f          ‘jit_bgtr_f’ was not declared in this scope
bgtr_d          ‘jit_bgtr_d’ was not declared in this scope
bger_f          ‘jit_bger_f’ was not declared in this scope
bger_d          ‘jit_bger_d’ was not declared in this scope
beqr_f          ‘jit_beqr_f’ was not declared in this scope
beqr_d          ‘jit_beqr_d’ was not declared in this scope
bner_f          ‘jit_bner_f’ was not declared in this scope
bner_d          ‘jit_bner_d’ was not declared in this scope
bunltr_f        ‘jit_bunltr_f’ was not declared in this scope
bunltr_d        ‘jit_bunltr_d’ was not declared in this scope
bunler_f        ‘jit_bunler_f’ was not declared in this scope
bunler_d        ‘jit_bunler_d’ was not declared in this scope
bungtr_f        ‘jit_bungtr_f’ was not declared in this scope
bungtr_d        ‘jit_bungtr_d’ was not declared in this scope
bunger_f        ‘jit_bunger_f’ was not declared in this scope
bunger_d        ‘jit_bunger_d’ was not declared in this scope
buneqr_f        ‘jit_buneqr_f’ was not declared in this scope
buneqr_d        ‘jit_buneqr_d’ was not declared in this scope
bltgtr_f        ‘jit_bltgtr_f’ was not declared in this scope
bltgtr_d        ‘jit_bltgtr_d’ was not declared in this scope
bordr_f         ‘jit_bordr_f’ was not declared in this scope
bordr_d         ‘jit_bordr_d’ was not declared in this scope
bunordr_f       ‘jit_bunordr_f’ was not declared in this scope
bunordr_d       ‘jit_bunordr_d’ was not declared in this scope


== Transfer ==

roundr_f_l      ‘jit_roundr_f_l’ was not declared in this scope
roundr_d_l      ‘jit_roundr_d_l’ was not declared in this scope
truncr_f_l      ‘jit_truncr_f_l’ was not declared in this scope
truncr_d_l      ‘jit_truncr_d_l’ was not declared in this scope
floorr_f_l      ‘jit_floorr_f_l’ was not declared in this scope
floorr_d_l      ‘jit_floorr_d_l’ was not declared in this scope
ceilr_f_l       ‘jit_ceilr_f_l’ was not declared in this scope
ceilr_d_l       ‘jit_ceilr_d_l’ was not declared in this scope


== Unary ==

notr_c          ‘jit_xori_c’ was not declared in this scope
notr_uc         ‘jit_xori_c’ was not declared in this scope
notr_s          ‘jit_xori_s’ was not declared in this scope
notr_us         ‘jit_xori_s’ was not declared in this scope

== Binary operations ==

addxr_ul        ‘jit_addxr_l’ was not declared in this scope
addxr_l         ‘jit_addxr_l’ was not declared in this scope
addxi_ul        ‘jit_addxi_l’ was not declared in this scope
addxi_l         ‘jit_addxi_l’ was not declared in this scope
addcr_ul        ‘jit_addcr_l’ was not declared in this scope
addcr_l         ‘jit_addcr_l’ was not declared in this scope
addci_ul        ‘jit_addci_l’ was not declared in this scope
addci_l         ‘jit_addci_l’ was not declared in this scope
subxr_l         ‘jit_subxr_l’ was not declared in this scope
subxi_ul        ‘jit_subxi_l’ was not declared in this scope
subxi_l         ‘jit_subxi_l’ was not declared in this scope
subcr_ul        ‘jit_subcr_l’ was not declared in this scope
subcr_l         ‘jit_subcr_l’ was not declared in this scope
subci_ul        ‘jit_addci_l’ was not declared in this scope
subci_l         ‘jit_addci_l’ was not declared in this scope
mulr_l          ‘jit_mulr_l’ was not declared in this scope
mulr_ul         ‘jit_mulr_ul’ was not declared in this scope
muli_l          ‘jit_muli_l’ was not declared in this scope
muli_ul         ‘jit_muli_ul’ was not declared in this scope
hmulr_l         ‘jit_hmulr_l’ was not declared in this scope
hmulr_ul        ‘jit_hmulr_ul’ was not declared in this scope
hmuli_l         ‘jit_hmuli_l’ was not declared in this scope
hmuli_ul        ‘jit_hmuli_ul’ was not declared in this scope
divr_l          ‘jit_divr_l’ was not declared in this scope
divr_ul         ‘jit_divr_ul’ was not declared in this scope
divi_l          ‘jit_divi_l’ was not declared in this scope
divi_ul         ‘jit_divi_ul’ was not declared in this scope
modr_l          ‘jit_modr_l’ was not declared in this scope
modr_ul         ‘jit_modr_ul’ was not declared in this scope
modi_l          ‘jit_modi_l’ was not declared in this scope
modi_ul         jit_modi_ul’ was not declared in this scope
ori_l           macro "jit_qop_" requires 5 arguments, but only 4 given
ori_ul          macro "jit_qop_" requires 5 arguments, but only 4 given
xori_l          macro "jit_qop_" requires 5 arguments, but only 4 given
xori_ul         macro "jit_qop_" requires 5 arguments, but only 4 given
lshr_l          macro "jit_qop_" requires 5 arguments, but only 3 given
lshr_ul         macro "jit_qop_" requires 5 arguments, but only 3 given
rshr_l          macro "jit_qop_" requires 5 arguments, but only 3 given
rshr_ul         macro "jit_qop_" requires 5 arguments, but only 3 given


== Comparison ==

ltr_l   ‘jit_ltr_l’ was not declared in this scope
ltr_ul  ‘jit_ltr_ul’ was not declared in this scope
ltr_p   ‘jit_ltr_ul’ was not declared in this scope
lti_l   ‘jit_lti_l’ was not declared in this scope
lti_ul  ‘jit_lti_ul’ was not declared in this scope
lti_p   ‘jit_lti_ul’ was not declared in this scope
ler_l   ‘jit_ler_l’ was not declared in this scope
ler_ul  ‘jit_ler_ul’ was not declared in this scope
ler_p   ‘jit_ler_ul’ was not declared in this scope
lei_l   ‘jit_lei_l’ was not declared in this scope
lei_ul  ‘jit_lei_ul’ was not declared in this scope
lei_p   ‘jit_lei_ul’ was not declared in this scope
gtr_l   ‘jit_gtr_l’ was not declared in this scope
gtr_ul  ‘jit_gtr_ul’ was not declared in this scope
gtr_p   ‘jit_gtr_ul’ was not declared in this scope
gti_l   ‘jit_gti_l’ was not declared in this scope
gti_ul  ‘jit_gti_ul’ was not declared in this scope
gti_p   ‘jit_gti_ul’ was not declared in this scope
ger_l   ‘jit_ger_l’ was not declared in this scope
ger_ul  ‘jit_ger_ul’ was not declared in this scope
ger_p   ‘jit_ger_ul’ was not declared in this scope
gei_l   ‘jit_gei_l’ was not declared in this scope
gei_ul  ‘jit_gei_ul’ was not declared in this scope
gei_p   ‘jit_gei_ul’ was not declared in this scope
eqr_l   ‘jit_eqr_l’ was not declared in this scope
eqr_ul  ‘jit_eqr_l’ was not declared in this scope
eqr_p   ‘jit_eqr_l’ was not declared in this scope
eqi_l   ‘jit_eqi_l’ was not declared in this scope
eqi_ul  ‘jit_eqi_l’ was not declared in this scope
eqi_p   ‘jit_eqi_l’ was not declared in this scope
ner_l   ‘jit_ner_l’ was not declared in this scope
ner_ul  ‘jit_ner_l’ was not declared in this scope
ner_p   ‘jit_ner_l’ was not declared in this scope
nei_l   ‘jit_nei_l’ was not declared in this scope
nei_ul  ‘jit_nei_l’ was not declared in this scope
nei_p   ‘jit_nei_l’ was not declared in this scope


== Load ==

ldr_ui  ‘jit_ldr_ui’ was not declared in this scope
ldr_ul  ‘jit_ldr_ul’ was not declared in this scope
ldi_ui  ‘jit_ldi_ui’ was not declared in this scope
ldi_ul  ‘jit_ldi_ul’ was not declared in this scope
ldxr_ui ‘jit_ldxr_ui’ was not declared in this scope
ldxr_ul ‘jit_ldxr_ul’ was not declared in this scope
ldxi_ui ‘jit_ldxi_ui’ was not declared in this scope
ldxi_ul ‘jit_ldxi_ul’ was not declared in this scope


== Transfer ==

extr_c_l        warning: left shift count >= width of type
extr_s_l        warning: left shift count >= width of type
extr_i_l        warning: left shift count >= width of type
extr_f_d        ‘jit_extr_f_d’ was not declared in this scope
extr_d_f        ‘jit_extr_d_f’ was not declared in this scope


== Unary ==

negr_f          ‘jit_negr_f’ was not declared in this scope
negr_d          ‘jit_negr_d’ was not declared in this scope
notr_c          ‘jit_xori_c’ was not declared in this scope
notr_uc         ‘jit_xori_c’ was not declared in this scope
notr_s          ‘jit_xori_s’ was not declared in this scope
notr_us         ‘jit_xori_s’ was not declared in this scope
notr_l          macro "jit_qop_" requires 5 arguments, but only 4 given
notr_ul         macro "jit_qop_" requires 5 arguments, but only 4 given

== Branch ==

bltr_f          ‘jit_bltr_f’ was not declared in this scope
bltr_d          macro "JZm" passed 4 arguments, but takes just 1
                ‘union jit_state::pointer’ has no member named ‘ppc’
bler_f          ‘jit_bler_f’ was not declared in this scope
bler_d          ‘JNCm’ was not declared in this scope
                ‘union jit_state::pointer’ has no member named ‘ppc’
bgtr_f          ‘jit_bgtr_f’ was not declared in this scope
bgtr_d          macro "JZm" passed 4 arguments, but takes just 1
                ‘union jit_state::pointer’ has no member named ‘ppc’
bger_f          ‘jit_bger_f’ was not declared in this scope
bger_d          ‘JNCm’ was not declared in this scope
                ‘union jit_state::pointer’ has no member named ‘ppc’
beqr_f          ‘jit_beqr_f’ was not declared in this scope
beqr_d          macro "JZm" passed 4 arguments, but takes just 1
                ‘union jit_state::pointer’ has no member named ‘ppc’
bner_f          ‘jit_bner_f’ was not declared in this scope
bner_d          macro "JNZm" passed 4 arguments, but takes just 1
                ‘union jit_state::pointer’ has no member named ‘ppc’
bunltr_f        ‘jit_bunltr_f’ was not declared in this scope
bunltr_d        ‘JCm’ was not declared in this scope
                ‘union jit_state::pointer’ has no member named ‘ppc’
bunler_f        ‘jit_bunler_f’ was not declared in this scope
bunler_d        macro "JNZm" passed 4 arguments, but takes just 1
                ‘union jit_state::pointer’ has no member named ‘ppc’
bungtr_f        ‘jit_bungtr_f’ was not declared in this scope
bungtr_d        ‘JCm’ was not declared in this scope
                ‘union jit_state::pointer’ has no member named ‘ppc’
bunger_f        ‘jit_bunger_f’ was not declared in this scope
bunger_d        macro "JNZm" passed 4 arguments, but takes just 1
                ‘union jit_state::pointer’ has no member named ‘ppc’
buneqr_f        ‘jit_buneqr_f’ was not declared in this scope
buneqr_d        ‘JCm’ was not declared in this scope
                ‘union jit_state::pointer’ has no member named ‘ppc’
bltgtr_f        ‘jit_bltgtr_f’ was not declared in this scope
bltgtr_d        ‘JNCm’ was not declared in this scope
                ‘union jit_state::pointer’ has no member named ‘ppc’
bordr_f         ‘jit_bordr_f’ was not declared in this scope
bordr_d         ‘JNCm’ was not declared in this scope
                ‘union jit_state::pointer’ has no member named ‘ppc’
bunordr_f       ‘jit_bunordr_f’ was not declared in this scope
bunordr_d       ‘JCm’ was not declared in this scope
                ‘union jit_state::pointer’ has no member named ‘ppc’


== Transfer ==

roundr_f_l      ‘jit_roundr_f_l’ was not declared in this scope
roundr_d_l      ‘jit_roundr_d_l’ was not declared in this scope
truncr_f_l      ‘jit_truncr_f_l’ was not declared in this scope
truncr_d_l      ‘jit_truncr_d_l’ was not declared in this scope
floorr_f_l      ‘jit_floorr_f_l’ was not declared in this scope
floorr_d_l      ‘jit_floorr_d_l’ was not declared in this scope
ceilr_f_l       ‘jit_ceilr_f_l’ was not declared in this scope
ceilr_d_l       ‘jit_ceilr_d_l’ was not declared in this scope


== Unary ==

notr_c          ‘jit_xori_c’ was not declared in this scope
notr_uc         ‘jit_xori_c’ was not declared in this scope
notr_s          ‘jit_xori_s’ was not declared in this scope
notr_us         ‘jit_xori_s’ was not declared in this scope


_______________________________________________
Lightning mailing list
Lightning@...
http://lists.gnu.org/mailman/listinfo/lightning

signature.asc (196 bytes) Download Attachment

Re: Runtime assembler in C++

by Pippijn van Steenhoven :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Actually, I was using an older version from CVS. I checked out the git
repository now and many were fixed. I will create new lists later. One
question:

    leaf (2);
    int ofs = arg_i ();
    getarg_i (R0, ofs);
    ofs = arg_i ();
    getarg_i (R1, ofs);
    addr_i (RET, R0, R1);
    ret ();

Can this be written as:

    leaf (2);
    getarg_i (R0, arg_i ());
    getarg_i (R1, arg_i ());
    addr_i (RET, R0, R1);
    ret ();

In all cases, or are there cases where this does not work? I am
thinking of the function evaluation with functions returning
immediates.

Regards,
Pippijn


_______________________________________________
Lightning mailing list
Lightning@...
http://lists.gnu.org/mailman/listinfo/lightning

Re: Runtime assembler in C++

by Paolo Bonzini-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Pippijn van Steenhoven wrote:
> Actually, I was using an older version from CVS. I checked out the git
> repository now and many were fixed. I will create new lists later.

Thanks!

>     leaf (2);
>     int ofs = arg_i ();
>     getarg_i (R0, ofs);
>     ofs = arg_i ();
>     getarg_i (R1, ofs);
>     addr_i (RET, R0, R1);
>     ret ();
>
> Can this be written as:
>
>     leaf (2);
>     getarg_i (R0, arg_i ());
>     getarg_i (R1, arg_i ());
>     addr_i (RET, R0, R1);
>     ret ();
>
> In all cases, or are there cases where this does not work? I am
> thinking of the function evaluation with functions returning
> immediates.

It might cause double evaluation of macro arguments.  If everything's
wrapped (as you did) in a C++ class, it's not a problem.

Paolo


_______________________________________________
Lightning mailing list
Lightning@...
http://lists.gnu.org/mailman/listinfo/lightning