Udon の実行モデル
Udon の命令は 9 種類で、値を計算するのは EXTERN だけです(a + b も足し算の関数を名前で呼びます)。
| 命令 | 何をするか |
|---|---|
NOP | 何もしない |
PUSH | ヒープアドレスをスタックに積む |
POP | スタックの先頭を捨てる |
JUMP_IF_FALSE | 積んだアドレスの値が false なら、指定の位置へ跳ぶ |
JUMP | 指定の位置へ跳ぶ |
EXTERN | 外部の関数を 1 本呼ぶ |
ANNOTATION | 何もしない(引数を 1 つ取る) |
JUMP_INDIRECT | 積んだアドレスの値を飛び先にして跳ぶ |
COPY | スタックが指す 2 つのアドレスのあいだで値を写す |
呼べる関数の範囲
Section titled “呼べる関数の範囲”呼べるのは Udon が公開している一覧にあるものだけで、C# の側にあるメソッドでも、一覧に無ければ
TUKI0101、型なら TUKI0102 のエラーになります(エラー)。
呼び出し先とジャンプ先の決定
Section titled “呼び出し先とジャンプ先の決定”呼ぶ関数の名前はシグネチャの文字列として命令列に書き込まれ、飛び先を実行時に決められる命令は
JUMP_INDIRECT だけです(コンパイラはこれをメソッドからの return に使います)。
実行環境による制約
Section titled “実行環境による制約”| 書き方 | 理由 | 出る番号 |
|---|---|---|
| 関数を値として扱う構文 | 呼ぶ先は命令の側に書いてあり、実行時に差し替えられません | デリゲートとラムダが TUKI0108 |
| 少しずつ値を返す構文 | 1 回の実行はエントリポイントから終わりまで通しで進みます | yield が TUKI0001 |
| 実行時に名前でメンバを解決する構文 | 呼ぶ先の名前はコンパイルの時に決まります | dynamic が TUKI0102 |
ヒープの構成
Section titled “ヒープの構成”| 格納先 | ヒープと呼ぶ 1 本の配列だけです |
| ローカル変数の領域 | ありません。値はすべてヒープ変数に格納されます |
| ヒープ変数の型と数 | 1 つずつ型を持ち、数はコンパイルの時に決まります。実行中に増やす手段はありません |
| 配列 | 要素をいくつ持っていても 1 つのヒープ変数に載ります。長さは実行時に決めた値でかまいませんが、作ったあとで変える書き方はありません(配列) |
プログラムの単位
Section titled “プログラムの単位”| 単位 | 1 つのファイルが 1 つのプログラム。中の具象の Behaviour が本体です(2 つ目を同じファイルに書くと TUKI0109。ファイル構成と名前空間) |
| 始まる場所 | main はありません。実行環境が呼ぶイベントと、名前で呼ばれるメソッドです(イベント) |
Main という名前 | 書けますが、実行環境は呼びません |
using UnityEngine;using Tsukimi;
public class BcMain : TsukimiBehaviour{ void Start() { Debug.Log(1); // => 1 }
public static void Main() { }}エントリポイントからたどれないコード
Section titled “エントリポイントからたどれないコード”| 命令になるもの | エントリポイントからの呼び出しをたどって到達したメソッドだけ |
| エントリポイント | イベントと、public を付けたメソッド |
| 命令にならないもの | public が付いておらず、どこからも呼ばれないメソッド。ヒープ変数も使いません |
| それでも受ける検査 | 対応している構文かどうかは見ます。呼び忘れたメソッドの中に非対応の構文があれば、そこでエラーになります |
ヒープの上限
Section titled “ヒープの上限”上限は 3 つあり、どれもコンパイル時のエラーになります。
| 上限 | 数えるもの | 診断 |
|---|---|---|
| ヒープ変数 1,048,576 個 | struct を展開したフィールドと、各メソッドの引数とローカル変数(struct を使うプログラムだけ数えます) | TUKI0104 |
| 具体化した組 256 | ジェネリックを具体化した組の総数 | TUKI0105 |
| 入れ子 8 段 | 型引数の入れ子の深さ | TUKI0105 |
TUKI0105 の 2 つは TUKI0104 より先に実行されます。
| 上限 | 決めているもの |
|---|---|
| ヒープ変数 1,048,576 個 | 実行環境がヒープに許す最大の数です |
| 大きさを指定しないヒープ 512 個 | アセンブラにヒープサイズを指定しなかった場合の既定値です。上限ではなく、この言語のプログラムは必要な大きさを渡して組むので、512 個を超えるプログラムもそのまま動作します |
| ジェネリックの 2 つ | コンパイラが増殖を防ぐために置いている数です。実行環境の側の制限ではありません |
ヒープ変数の消費要因
Section titled “ヒープ変数の消費要因”| 消費するもの | 数え方 |
|---|---|
| フィールド | 宣言した数だけ使います。struct は中身を並べた形になるので、メンバの数だけ使います |
| メソッドの引数とローカル変数 | 実行環境にローカル変数の領域が無いので、メソッドの中で宣言した変数もここに格納されます |
| 定数と計算の途中の値 | ソースに書いていない値も、コンパイルの過程で格納先が必要です |
| 外部の関数のシグネチャ文字列 | 呼ぶ関数の種類ごとに 1 つ使います。同じ関数を何度呼んでも増えませんが、種類が増えるとそのぶん変数の枠が減ります |
実使用量との差
Section titled “実使用量との差”TUKI0104 が数えるのはフィールドと引数とローカル変数だけで、組み立てのときに実際に必要な数には、
定数と計算の途中の値、それにシグネチャの文字列が加わります。この数は見積もりです。
実行が停止する条件
Section titled “実行が停止する条件”実行環境に例外の仕組みが無いので、throw も try / catch もエラーになります
(文と制御構文)。
using UnityEngine;using Tsukimi;
public class ExCatchTypeless : TsukimiBehaviour{ void Start() { try { Debug.Log(1); } catch { Debug.Log(2); } }}失敗しうる操作は、呼ぶ前に条件を調べる形でしか書けません(checked が非対応なのも同じ理由です)。
実行時に停止する操作
Section titled “実行時に停止する操作”| 操作 | 起きること | 例のある場所 |
|---|---|---|
| 整数のゼロ除算 | 実行が停止します。小数を 0 で割ったときは Infinity になります | 数値のあふれと変換 |
| 範囲の外へ出る数値の変換 | 実行が停止します。変換する外部の関数が範囲を検査しています | 数値のあふれと変換 |
| null の参照のメンバの呼び出し | 実行が停止し、実行環境がエラーを出します | null と参照 |
停止後の挙動
Section titled “停止後の挙動”停止するとそのイベントの残りは実行されず、ログには、停止したことと、失敗した外部の関数の シグネチャが出ます。そのプログラムが以後どのイベントにも反応しなくなることがあり、 復帰する手段はありません(オブジェクトを再生成するか、再配置することになります)。