x10からC++の関数を呼ぶ

# はじめに

x10はある程度は最適化してくれるものの、やはり性能はチューニングしたC,C++にはおよびません。そこでプログラムのホットスポットの関数のみC,C++で書いて、その関数をx10のコードから呼ぶことができます。
またC,C++の方がコミュニティが大きい分、便利なライブラリが多く、そのライブラリをそのまま利用できると嬉しいことがあります。

ここではnative版(C++版)x10からC++の関数を呼ぶ方法について紹介します。

参考：

- http://x10-lang.org/documentation/practical-x10-programming/native-code-integration.html
- http://x10.sourceforge.net/documentation/languagespec/x10-latest.pdf の18章

# C++の関数を呼ぶ

### コードサンプル
MyCpp.hpp, MyCpp.cpp で宣言・定義された関数を呼ぶサンプル

```NativeCppTest.x10
import x10.io.Console;
import x10.compiler.Native;
import x10.compiler.NativeCPPInclude;
import x10.compiler.NativeCPPCompilationUnit;

@NativeCPPInclude("MyCpp.hpp")
@NativeCPPCompilationUnit("MyCpp.cpp")

public class NativeCppTest {
  @Native("c++", "my_double(#1);")
  native static def double(n:Int): Int;

  public static def main( args: Rail[String] ) {
    @Native("c++", "foo();") {}

    val n = 30n;
    val n2 = double(n);
    Console.OUT.println("n2: " + n2);
  }
}
```

```MyCpp.hpp
void foo();
int my_double(int n);
```

```MyCpp.cpp
#include <iostream>
#include "MyCpp.hpp"

void foo() {
  std::cout << "hello from foo" << std::endl;
}

int my_double(int n) {
  return 2 * n;
}
```

関数を呼ぶときは２通りの書き方があります。

#### Native Static Method

C++関数をx10のstaticメソッドにマッピングする。

```x10      
@Native("c++", "my_double(#1)")
native static def double(n:Int): Int;
```

- メソッドの引数は `#1`, `#2` に埋め込まれてC++の関数が呼ばれます。
- native修飾子をつけると、x10での関数定義（native関数が見つからない場合に呼ばれる）ができなくなります。
    - つまりこの例ではmanaged版(Java版)のコンパイルはできません。
- 少なくともprimitive型は返り値にできます。ただし型推論はできないので、返り値の型（この場合はInt）とパラメータの型を明示する必要があります。
- 外部のC++ファイル`@NativeCPPInclude` でヘッダファイル、 `@NativeCPPCompilationUnit` でcppファイルをそれぞれ指定します。

#### Native Blocks

```x10
@Native("c++", "foo();") {}
```

- このように書いてx10のメソッドを作らずに呼ぶこともできます。`{}`は必須です。x10のstatementを@Nativeの中身で置き換えています。
- もし上記のコードがjavaにcompileされた場合、空のstatementが実行されるはずです。（つまり何も実行されない）
- 引数を渡す方法はない（？）が、static変数を埋め込むことができます。

### コンパイル方法

cpp,hpp,x10のファイルをすべて同一のディレクトリに置いている場合は、単純に以下のコマンドでコンパイルできます。

```shell-session
$ x10c++ NativeCppTest.x10
```

外部のライブラリをリンクする場合、インクルードパスとライブラリパス、リンクオプションを次のように指定します。

```shell-session
x10c++ Test.x10 -post '# # -I /usr/local/blas # -L /usr/local/blas -lblas'
```

最初の `#` はコンパイラの実行コマンド(g++とか)、二つ目はC++のファイルのリストとCXXFLAGS、３つ目はリンカオプションが埋め込まれ、埋め込まれた文字列が実行されます。

## Stringを引数に渡す方法

primitive型の変数はC++の適切な型の変数にマッピングされます。
しかし文字列の場合は一工夫必要です。

例えば、文字列を引数として渡してsystemコマンドを実行するメソッドを考えましょう。
次のように書くことができます。

```x10
@Native("c++", "system( (#1)->c_str() );")
native static def system(cmd:String):Int;
```

x10のStringをC++に変換すると x10::lang::String というC++のクラスに変換され、そのクラスの中に `c_str()` というメソッドが定義されています。C++の `std::string#c_str()` と同じくchar*を返します。

## 配列を引数に渡す方法

Railの0番目の要素のアドレスをCに渡す。

```scala:NativeRail.x10
import x10.compiler.*;

@NativeCPPInclude("foo.h")
@NativeCPPCompilationUnit("foo.c")
public class NativeTest {

    @Native("c++", "foo((double*)(&((#1)->raw[0])), (int*)(&((#2)->raw[0])))")
    native static def foo(tmp:Rail[double],tmp2:Rail[int]):Int;

    public static def main(args:Rail[String]) {
        t:Rail[double] = new Rail[double](3);
        t2:Rail[int] = new Rail[int](3);
	foo(t,t2);
	for(d in t) Console.OUT.println(d);
	for(i in t2) Console.OUT.println(i);
    }
}
```

```c:foo.c
int foo(double * tmp, int * tmp2) {
  tmp[0]=10.0;
  tmp[1]=11.0;
  tmp2[2]=21;
}
```

## わかっていないこと

- メモリ解放はどのタイミングで？
    - GCは効かない？たぶんC++側で明示的に解放する必要があると思うが、よくわかっていません。
- C++のクラスをX10から参照することができる？
    - X10のクラスは上のStringの例のようにC++のクラスにマップされます。
        - ユーザー定義型の場合はビルド時に生成されるC++のコードを見れば、どのようにC++のクラスにマップされたかわかります。
    - しかし、C++のオブジェクトを指す変数をx10側で参照することができるかは不明です。