SPVMネイティブAPI仕様 1.0 ベータ

# SPVMネイティブAPI仕様 1.0ベータ

SPVMドキュメント > SPVMネイティブAPI仕様

## SPVMネイティブAPI仕様

SPVMネイティブAPI仕様がこのドキュメントには記述されています。SPVMは、1.0のリリースに向けて、ベータテスト中です。SPVMネイティブAPI仕様は、警告なく変更されることがあります。

最終更新日 2019年6月5日

## 目次

## SPVMネイティブAPIとは

SPVMネイティブAPIとは、SPVMのネイティブサブルーチンの中で呼び出すことのできるC言語のAPIのことです。SPVMのネイティブサブルーチンの仕様についてもここに記述されます。

- ネイティブサブルーチンの定義方法
- SPVMのサブルーチンの引数をネイティブサブルーチンで受け取る
- ネイティブサブルーチンの戻り値を、SPVMのサブルーチンの戻り値として返す
- SPVMの配列の要素をC言語の配列として取得

作成したネイティブサブルーチンは、SPVMから呼び出すことができます。

## SPVMネイティブサブルーチンの宣言

SPVMネイティブサブルーチンの宣言は、サブルーチンのディスクリプタ「native」を使うことによって行います。サブルーチンのブロックを書かずに、セミコロンで終わります。以下は、Foo::Barというモジュールの中で宣言する場合の例です。

    # Foo/Bar.spvm
    package Foo::Bar {
      native sub sum : int ($num1 : int, $num2 : int);
    }

## ネイティブサブルーチンの定義

ネイティブサブルーチンの定義は、ネイティブソースファイルの中で行います。ネイティブソースファイルは、SPVMのモジュールの拡張子を、対象の言語の拡張子に変えたものになります。たとえばC言語であれば「.c」に変えたものです。C++であれば、「.cpp」に変えたものです。これは、ネイティブサブルーチンの設定において、変更することができます。

    # モジュール名がFoo::Barの場合のネイティブソースファイル
    Foo/Bar.c

ネイティブソースファイルを作成するときは、合わせてネイティブ設定ファイルを作成する必要があります。ネイティブ設定ファイルは、SPVMのモジュールの拡張子を「.config」に変えたものになります。ネイティブ設定ファイルが存在しない場合は、例外が発生します。

    # モジュール名がFoo::Barの場合のネイティブ設定ファイル
    Foo/Bar.config

ネイティブ設定ファイルはPerlのソースコードです。SPVM::Builder::Configオブジェクトをソースコードの最後に記述して、返却しなければなりません。そうでない場合は、例外が発生します。

SPVMと同じC99で、C言語を書きたい場合は、以下のように記述します。

    use strict;
    use warnings;

    use SPVM::Builder::Config;
    my $bconf = SPVM::Builder::Config->new_c99;

    $bconf;

C99以外でコンパイルしたい場合や、ライブラリを追加したい場合はSPVM::Builder::Configのドキュメントのサンプルを見てください。

ネイティブサブルーチンの定義は、ネイティブソースファイルの中で行います。この場合の例は「Foo/Bar.c」です。

    #include "spvm_native.h"

    int32_t SPNATIVE__Foo__Bar__sum(SPVM_ENV* env, SPVM_VALUE* stack) {

      int32_t num1 = stack[0].ival;
      int32_t num2 = stakc[1].ival;

      int32_t total = num1 + num2;

      stack[0].ival = total;

      return SPVM_SUCCESS;
    }

ネイティブソースファイルの先頭で「spvm_native.h」をインクルードしてください。このヘッダファイルには、SPVMネイティブAPIと必要な構造体が定義されています。

ネイティブサブルーチンの定義は、簡単なC言語の関数です。

ネイティブサブルーチンのCにおける関数名は「SPNATIVE__」で始まり、モジュール名の「::」を「__」に変換したものが続き、「__」が続き、サブルーチン名で終わります。SPVMにおけるサブルーチン名との対応が正しくない場合は、コンパイルエラーが発生します。

引数は二つで、第一引数は、実行環境の情報を持った「SPVM_ENV* env」で、第二引数は引数と戻り値に利用される「SPVM_VALUE* stack」です。

戻り値の型は「int32_t」です。サブルーチンが例外を発生させる場合は「SPVM_EXCEPTION」、それ以外の場合は「SPVM_SUCCESS」を返却します。

上記のサンプルでは、SPVMのint型の引数を二つ受け取り、合計を計算し、戻り値を返すということを行っています。

## ネイティブサブルーチンのコンパイル

ネイティブサブルーチンは、Perlをコンパイルしたコンパイラで、コンパイルされて、OSに応じた、動的に読み可能な共有ライブラリにコンパイルされます。Unix/Linuxにおいては、共有ライブラリ(.so)、Windowsにおいてはダイナミックリンクライブラリ(.dll)などです。

動的に読み可能な共有ライブラリへのコンパイルは、SPVMのコンパイル時に行われます。コンパイルのときに、ビルドディレクトリが存在していなければなりません。ビルドディレクトリが存在しない場合は、例外が発生します。

ビルドディレクトリのデフォルトは、実行したPerlスクリプトが存在するディレクトリの「spvm_build」ディレクトリで、環境変数「SPVM_BUILD_DIR」で変更することができます。

PerlからSPVMネイティブサブルーチンを利用したい場合は実行したPerlスクリプトが存在するディレクトリに「spvm_build」ディレクトリ作成します。

    script.pl
    spvm_build/

中間的に生成されるオブジェクトファイルは、ビルドディレクトリの下の「work/object」の下に生成されます。オブジェクトファイル名は、SPVMのモジュールの拡張子を「.o」に変えたものになります。

    spvm_build/work/object/Foo/Bar.o

動的に読み可能な共有ライブラリは、ビルドディレクトリの下の「work/lib」の下に生成されます。動的に読み可能な共有ライブラリのファイル名は、SPVMのモジュールの拡張子を、OSに応じた、動的に読み可能な共有ライブラリの拡張子に変えたものになります。

    # Unix/Linux
    spvm_build/work/object/Foo/Bar.so

    # Windows
    spvm_build/work/object/Foo/Bar.dll

## 引数の取得

- 引数とスタック
- byte型の引数の取得
- short型の引数の取得
- int型の引数の取得
- long型の引数の取得
- float型の引数の取得
- double型の引数の取得
- オブジェクト型の引数の取得
- 引数のスタック
- byteのリファレンス型の引数の取得
- shortのリファレンス型の引数の取得
- intのリファレンス型の引数の取得
- longのリファレンス型の引数の取得
- floatのリファレンス型の引数の取得
- doubleのリファレンス型の引数の取得
- 複数数値型の引数の取得

### 引数とスタック

スタックとは、ネイティブサブルーチンの定義における第二引数で渡される「SPVM_VALUE* stack」のことで、この中に引数が格納されています。

    int32_t SPNATIVE__Foo__Bar__sum(SPVM_ENV* env, SPVM_VALUE* stack) {

    }

SPVM_VALUEは、SPVMの値を格納するためのC言語の共用体です。数値型、オブジェクト型、リファレンス型の値を保存できます。

「SPVM_VALUE* stack」の「SPVM_VALUE型の配列」の先頭のポインタです。SPVM側からコールされたネイティブサブルーチンの引数の値がこの配列に設定されます。

たとえば、int型の第一引数の値を取得する場合は、以下のように書きます。

    int32_t args1 = stack[0].ival;

たとえば、long型の第二引数の値を取得する場合は、以下のように書きます。

    int64_t args2 = stack[0].lval;

### byte型の引数の取得

SPVMのbyte型の引数を取得するには、bvalフィールドにアクセスします。C言語のint8_t型に代入します。

    int8_t args1 = stack[0].bval;

### short型の引数の取得

SPVMのshort型の引数を取得するには、svalフィールドにアクセスします。C言語のint16_t型に代入します。

    int16_t args1 = stack[0].sval;

### int型の引数の取得

SPVMのint型の引数を取得するには、ivalフィールドにアクセスします。C言語のint32_t型に代入します。

    int32_t args1 = stack[0].ival;

### long型の引数の取得

SPVMのlong型の引数を取得するには、lvalフィールドにアクセスします。C言語のint64_t型に代入します。

    int64_t args1 = stack[0].lval;

### float型の引数の取得

SPVMのfloat型の引数を取得するには、fvalフィールドにアクセスします。C言語のfloat型に代入します。

    float args1 = stack[0].fval;

### double型の引数の取得

SPVMのdouble型の引数を取得するには、dvalフィールドにアクセスします。C言語のdouble型に代入します。

    double args1 = stack[0].dval;

### オブジェクト型の引数の取得

SPVMのobject型の引数を取得するには、ovalフィールドにアクセスします。C言語のvoid*型に代入します。

    void* args1 = stack[0].oval;

### byteのリファレンス型の引数の取得

SPVMのbyteのリファレンス型の引数を取得するには、brefフィールドにアクセスします。C言語のint8_t*型に代入します。

    int8_t* args1 = stack[0].bref;

### shortのリファレンス型の引数の取得

SPVMのshortのリファレンス型の引数を取得するには、srefフィールドにアクセスします。C言語のint16_t*型に代入します。

    int16_t* args1 = stack[0].sref;

### intのリファレンス型の引数の取得

SPVMのintのリファレンス型の引数を取得するには、irefフィールドにアクセスします。C言語のint32_t*型に代入します。

    int32_t* args1 = stack[0].iref;

### longのリファレンス型の引数の取得

SPVMのlongのリファレンス型の引数を取得するには、lrefフィールドにアクセスします。C言語のint64_t*型に代入します。

    int64_t* args1 = stack[0].lref;

### floatのリファレンス型の引数の取得

SPVMのfloatのリファレンス型の引数を取得するには、frefフィールドにアクセスします。C言語のfloat*型に代入します。

    float* args1 = stack[0].fref;

### doubleのリファレンス型の引数の取得

SPVMのdoubleのリファレンス型の引数を取得するには、drefフィールドにアクセスします。C言語のdouble*型に代入します。

    double* args1 = stack[0].dref;

### 複数数値型の引数の取得

ネイティブサブルーチンにおいては、複数数値型の引数は、複数の引数に代入されます。

たとえば、SPVM::Complex_2d型の引数の場合は、二つの引数から取得します。フィールド名からはアクセスできないことに注意してください。

    double args_re = stack[0].dval;
    double args_im = stack[1].dval;

## 戻り値の設定

- 戻り値とスタック
- byte型の戻り値の設定
- short型の戻り値の設定
- int型の戻り値の設定
- long型の戻り値の設定
- float型の戻り値の設定
- double型の戻り値の設定
- オブジェクト型の戻り値の設定
- 複数数値型の戻り値の設定

### 戻り値とスタック

ネイティブサブルーチンは、C言語のreturn文によって戻り値を返すのではなく、スタックを使って戻り値を設定します。

たとえば、int型の戻り値を返す場合は、以下のように書きます。

    stack[0].ival = 3;

たとえば、long型の第二引数の値を取得する場合は、以下のように書きます。

    stack[0].lval = 56;

### byte型の戻り値の設定

SPVMのbyte型の戻り値を設定するには、bvalフィールドに代入します。C言語のint8_t型の値を代入します。

    int8_t retval;
    stack[0].bval = retval;

### short型の戻り値の設定

SPVMのshort型の戻り値を設定するには、svalフィールドに代入します。C言語のint16_t型の値を代入します。

    int16_t retval;
    stack[0].sval = retval;

### int型の戻り値の設定

SPVMのint型の戻り値を設定するには、ivalフィールドに代入します。C言語のint32_t型の値を代入します。

    int32_t retval;
    stack[0].ival = retval;

### long型の戻り値の設定

SPVMのlong型の戻り値を設定するには、lvalフィールドに代入します。C言語のint64_t型の値を代入します。

    int64_t retval;
    stack[0].lval = retval;

### float型の戻り値の設定

SPVMのfloat型の戻り値を設定するには、fvalフィールドに代入します。C言語のfloat型の値を代入します。

    float retval;
    stack[0].fval = retval;

### double型の戻り値の設定

SPVMのdouble型の戻り値を設定するには、dvalフィールドに代入します。C言語のdouble型の値を代入します。

    double retval;
    stack[0].dval = retval;

### オブジェクト型の戻り値の設定

SPVMのobject型の戻り値を設定するには、ovalフィールドに代入します。C言語のvoid*型の値を代入します。

    void* retval;
    stack[0].oval = retval;

### 複数数値型の戻り値の設定

ネイティブサブルーチンにおいては、複数数値型の戻り値は、複数の戻り値に代入します。

たとえば、SPVM::Complex_2d型の戻り値の場合は、二つの戻り値を設定します。

    double retval_re;
    double retval_im;
    stack[0].dval = retval_re;
    stack[1].dval = retval_im;

## ネイティブAPIのインデックス

ネイティブAPIは、名前に対応するインデックスを持っています。この番号は、ネイティブサブルーチンののバイナリ互換性を保つために、永続的に維持されます。新しいAPIの追加の場合は、末尾に追加されます。

    0     runtime_package_vars_heap_offset
    1     object_header_byte_size
    2     weaken_backref_head
    3     object_ref_count_offset
    4     object_basic_type_id_offset
    5     object_type_dimension_offset
    6     object_runtime_type_offset
    7     object_flag_offset
    8     object_length_offset
    9     byte_object_basic_type_id
    10    short_object_basic_type_id
    11    int_object_basic_type_id
    12    long_object_basic_type_id
    13    float_object_basic_type_id
    14    double_object_basic_type_id
    15    runtime
    16    exception_object
    17    native_mortal_stack
    18    native_mortal_stack_top
    19    native_mortal_stack_capacity
    20    basic_type_id
    21    field_id
    22    field_offset
    23    pkgvar_id
    24    sub_id
    25    method_sub_id
    26    new_obj_raw
    27    new_obj
    28    new_barray_raw
    29    new_barray
    30    new_sarray_raw
    31    new_sarray
    32    new_iarray_raw
    33    new_iarray
    34    new_larray_raw
    35    new_larray
    36    new_farray_raw
    37    new_farray
    38    new_darray_raw
    39    new_darray
    40    new_oarray_raw
    41    new_oarray
    42    new_marray_raw
    43    new_marray
    44    new_varray_raw
    45    new_varray
    46    new_str_raw
    47    new_str
    48    new_str_len_raw
    49    new_str_len
    50    new_pointer_raw
    51    new_pointer
    52    concat_raw
    53    concat
    54    new_stack_trace_raw
    55    new_stack_trace
    56    len
    57    belems
    58    selems
    59    ielems
    60    lelems
    61    felems
    62    delems
    63    oelems
    64    set_oelems
    65    bfield
    66    sfield
    67    ifield
    68    lfield
    69    ffield
    70    dfield
    71    ofield
    72    set_bfield
    73    set_sfield
    74    set_ifield
    75    set_lfield
    76    set_ffield
    77    set_dfield
    78    set_ofield
    79    bpkgvar
    80    spkgvar
    81    ipkgvar
    82    lpkgvar
    83    fpkgvar
    84    dpkgvar
    85    opkgvar
    86    set_bpkgvar
    87    set_spkgvar
    88    set_ipkgvar
    89    set_lpkgvar
    90    set_fpkgvar
    91    set_dpkgvar
    92    set_opkgvar
    93    pointer
    94    set_pointer
    95    call_sub
    96    exception
    97    set_exception
    98    ref_count
    99    inc_ref_count
    100   dec_ref_count
    101   enter_scope
    102   push_mortal
    103   leave_scope
    104   remove_mortal
    105   is_type
    106   has_callback
    107   object_basic_type_id
    108   object_type_dimension
    109   weaken
    110   isweak
    111   unweaken
    112   alloc_memory_block_zero
    113   free_memory_block
    114   memory_blocks_count
    115   type_name_raw
    116   type_name
    117   new_env
    118   free_env

## ネイティブAPIの一覧

- runtime_package_vars_heap_offset
- object_header_byte_size
- weaken_backref_head
- object_ref_count_offset
- object_basic_type_id_offset
- object_type_dimension_offset
- object_runtime_type_offset
- object_flag_offset
- object_length_offset
- byte_object_basic_type_id
- short_object_basic_type_id
- int_object_basic_type_id
- long_object_basic_type_id
- float_object_basic_type_id
- double_object_basic_type_id
- runtime
- exception_object
- native_mortal_stack
- native_mortal_stack_top
- native_mortal_stack_capacity
- basic_type_id
- field_id
- field_offset
- pkgvar_id
- sub_id
- method_sub_id
- new_obj_raw
- new_obj
- new_barray_raw
- new_barray
- new_sarray_raw
- new_sarray
- new_iarray_raw
- new_iarray
- new_larray_raw
- new_larray
- new_farray_raw
- new_farray
- new_darray_raw
- new_darray
- new_oarray_raw
- new_oarray
- new_marray_raw
- new_marray
- new_varray_raw
- new_varray
- new_str_raw
- new_str
- new_str_len_raw
- new_str_len
- new_pointer_raw
- new_pointer
- concat_raw
- concat
- new_stack_trace_raw
- new_stack_trace
- len
- belems
- selems
- ielems
- lelems
- felems
- delems
- oelems
- set_oelems
- bfield
- sfield
- ifield
- lfield
- ffield
- dfield
- ofield
- set_bfield
- set_sfield
- set_ifield
- set_lfield
- set_ffield
- set_dfield
- set_ofield
- bpkgvar
- spkgvar
- ipkgvar
- lpkgvar
- fpkgvar
- dpkgvar
- opkgvar
- set_bpkgvar
- set_spkgvar
- set_ipkgvar
- set_lpkgvar
- set_fpkgvar
- set_dpkgvar
- set_opkgvar
- pointer
- set_pointer
- call_sub
- exception
- set_exception
- ref_count
- inc_ref_count
- dec_ref_count
- enter_scope
- push_mortal
- leave_scope
- remove_mortal
- is_type
- has_callback
- object_basic_type_id
- object_type_dimension
- weaken
- isweak
- unweaken
- alloc_memory_block_zero
- free_memory_block
- memory_blocks_count
- type_name_raw
- type_name
- new_env
- free_env

### runtime_package_vars_heap_offset

### object_header_byte_size

### weaken_backref_head

### object_ref_count_offset

### object_basic_type_id_offset

### object_type_dimension_offset

### object_runtime_type_offset

### object_flag_offset

### object_length_offset

### byte_object_basic_type_id

### short_object_basic_type_id

### int_object_basic_type_id

### long_object_basic_type_id

### float_object_basic_type_id

### double_object_basic_type_id

### runtime

### exception_object

### native_mortal_stack

### native_mortal_stack_top

### native_mortal_stack_capacity

### basic_type_id

### field_id

### field_offset

### pkgvar_id

### sub_id

### method_sub_id

### new_obj_raw

### new_obj

### new_barray_raw

### new_barray

### new_sarray_raw

### new_sarray

### new_iarray_raw

### new_iarray

### new_larray_raw

### new_larray

### new_farray_raw

### new_farray

### new_darray_raw

### new_darray

### new_oarray_raw

### new_oarray

### new_marray_raw

### new_marray

### new_varray_raw

### new_varray

### new_str_raw

### new_str

### new_str_len_raw

### new_str_len

### new_pointer_raw

### new_pointer

### concat_raw

### concat

### new_stack_trace_raw

### new_stack_trace

### len

### belems

### selems

### ielems

### lelems

### felems

### delems

### oelems

### set_oelems

### bfield

### sfield

### ifield

### lfield

### ffield

### dfield

### ofield

### set_bfield

### set_sfield

### set_ifield

### set_lfield

### set_ffield

### set_dfield

### set_ofield

### bpkgvar

### spkgvar

### ipkgvar

### lpkgvar

### fpkgvar

### dpkgvar

### opkgvar

### set_bpkgvar

### set_spkgvar

### set_ipkgvar

### set_lpkgvar

### set_fpkgvar

### set_dpkgvar

### set_opkgvar

### pointer

### set_pointer

### call_sub

### exception

### set_exception

### ref_count

### inc_ref_count

### dec_ref_count

### enter_scope

### push_mortal

### leave_scope

### remove_mortal

### is_type

### has_callback

### object_basic_type_id

### object_type_dimension

### weaken

### isweak

### unweaken

### alloc_memory_block_zero

### free_memory_block

### memory_blocks_count

### type_name_raw

### type_name

### new_env

### free_env