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ネイティブサブルーチンの宣言は、サブルーチンのディスクリプタ「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

引数の取得

引数とスタック

スタックとは、ネイティブサブルーチンの定義における第二引数で渡される「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;

戻り値の設定

戻り値とスタック

ネイティブサブルーチンは、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