[Atelier Blue アトリエブルー]Homeプログラミング IL(CIL,MSIL) ECMA-335翻訳ドキュメント>CIL 命令セット(CIL Instruction Set)

Common Language Infrastructure (CLI)Partition III
CIL 命令セット(CIL Instruction Set)

この文書は「ECMA-335 Patirion III - CIL Instruction Set」の日本語訳です。原文はECMA-335 Patirion III - CIL Instruction Setにあります。この文書は完璧なもの(ただし、原文に忠実にする完璧ではなく、より理解しやすい方向での完璧さ)を目指していますが、内容の保証は出来ません。また、細部に独自解釈が混じっている場合もあるので、不安な場合は原文の方を参照してください。

連絡事項

目次

まだ無し

1 Scope

【この前文は適当に訳されています。気を付けて】

この明細は「共通中間言語(CIL)命令セット」、共通言語インフラストラクチャの明細の一部の詳細な記述です。Partition I【訳していないため、英語のページに飛びます】は、CLIのアーキテクチャについて記述し、CIL命令セットに関係の多くの問題の概観を提供します。その概観は、ここで記述されるような命令セットについての理解にとって必要です。

各命令記述は1セットの関連するCLIマシン命令について記述します。各命令定義は5部から成ります。

すべての命令がすべてのCLIのプロフィールに含まれるとは限らないことに注意してください。詳細は、PartitionIV【英語のドキュメント】 を参照してください。

1.1 データ型(Data Types)

Common Type System(CTS)は豊かなタイプシステムを定義し、Common Language Specification(CLS)は言語相互運用性を特徴づけます。しかし、CLI自身ははるかに簡単な型に対処します。

これらの型はユーザによって定義された値の型と内蔵型のサブセットを含めます。 サブセットは「基本的なCLI型」として一括して知られています。

オブジェクト参照とポインタ型には「null」が割り当てられる可能性があるので注意してください。「null」はCLIの中で「0(全てのビットが0)」になるように定義されています。

1.1.1 数値型(Numeric Data Types)

注意: アーキテクチャにかかわらず、1~2バイト整数も4バイト整数としてロードされ、その後は4バイト整数として扱われます。8バイト整数は種類の異なるものとして別扱いとします。このことは、通常の整数演算がonv 命令や conv.ovf 命令を実行しなくても、すべての実装において同一の結果になることを保証し、コードのポータビリティに役立ちます。

1~2バイトの整数型をもたらす変換命令が実際にスタックの値をint32(32ビット)にしますが、値は低ビットにだけ入ります(つまり、上のビットは符号付き拡張又は符号無し拡張されます)。

1~2バイトの整数の操作を正しくシミュレートするために、1~2バイト整数の形への変換がdiv、rem、shr、比較および条件付き分岐命令の前に必要です。

明白な変換指示に加えて、次の4つのケースでCLIが特別な方法で1~2バイトの整数を扱います。

  1. 代入先をローカル変数(stloc)か、引数(starg)に指定した場合、代入先が1~2バイトの整数であると宣言されているときにはあふれる分を切り捨てます。
  2. ローカル変数(ldloc)か、引数(ldarg)から読み出す場合、符号付きの1~2バイトの整数の時は符号拡張されます
  3. 1~2バイトの整数型の引数を使って「call」する場合は引数値への指示と同じ事を行います。
  4. 戻り値の型が1~2バイトの整数の場合、格納時に1~2バイトの整数への格納とされる(すなわち、CLIが自動的に切り捨てる)。そして、呼び出し側ではその値を1~2バイトの整数型としてロードします(CILが自動で0拡張または符号拡張を行います)。

最後の2つの手順では、実際の値の切り捨てがネイティブの呼び出し規約に到達しています。ですが、CILではこれの影響を受けずにまるで適切な「conv」命令を含んでいるかのように動きます。

注意: 上の仕様は、対応する実装が、中間計算型の精度に切り捨てするのを避けるのを許容します。従って、より広い精度ハードウェアレジスタの使用を許可します。また、同じであるか、より大きい精度をもたらす最適化変換アプリケーションも許可します。正確に複製可能な振る舞いが言語かアプリケーションによって要求される場合、明示的な変換が使用されてもよい。

浮動小数点式の内部表現がその名目上の型より大きな範囲あるいは精度を持っている時に記憶位置に入れられる場合、自動的に記憶位置の型になります。これは、正確の損失あるいは範囲外値(NaN、+無限、または-無限)の生成を含んでいるかもしれません。しかしながら、もし値が変更されずにそれが記憶位置から再びロードされる場合、値は将来の使用時に内部表現で保持されているかもしれません。エイリアシング(訳注:様々な型でのアクセス)することおよび他のスレッド実行の影響(メモリ・モデル・セクションを参照)を考慮に入れ、メモリ位置が後のロードの時にまだ有効であることを保証することはコンパイラの責任です。 しかしながら、余分な正確さを持つこの自由は、明示的な変換(conv.r4またはconv.r8)の実行に続いて許されません(その時に内部表現は関連する型において正確に表現可能であるに違いない)。

注意: 特定の記憶型に変換することができない値を検知するために、変換指示(conv.r4、またはconv.r8)そして次に「ckfinite」を使用して範囲外値をチェックします。特定の記憶型に切り替える場合にアンダーフローを検知するため、変換の前後に0との比較が要求されます。

注意:これらは、デノーマライズされた浮動小数点数上の算術演算の振る舞いを指定しません。また、はそのような明細が作成されても、それを指定しません。これはIEC 60559:1989と一致します。さらに、この標準は、作成されるNaNsの正確なビット・パターンにアクセスする方法、および32ビットおよび64ビットの表現間のNaNを変換する場合振る舞いを指定しません。この振る舞いはすべて「deliberately left implementation-specific【訳不明】」です。

1.1.2 真偽値型・ブール型(Boolean Data Type)

CLIのブール型はメモリの中で1バイトを占めます。すべてが0のビットパターンは、偽(false)の値を表します。任意のビットセット(0でない整数)を備えたビットパターンは、真(true)の値を表します。

1.1.3 オブジェクト参照(Object References)

オブジェクト参照(「O」型)は完全に不透明です。これらには算術演算命令はありません。可能なたただ一つの比較オペレーションが2つのオブジェクト参照間で等しい(また等しくない)を判定できます。オブジェクト参照で定義された変換命令はありません。オブジェクト参照は、あるCILオブジェクト命令(特にnewobjおよびnewarr)によって作成されます。オブジェクト参照は、引数として渡すこと、返り値として使うこと、ローカル変数として格納することができ、配列よびオブジェクトのフィールドに格納出来ます。

1.1.4 実行時ポインタ型(Runtime Pointer Types)

ポインタには2種類あります。1つは管理されていないポインタ。もう一つは管理されたポインタ。同じ配列あるいはオブジェクト(Partition I_alink_partitionIを参照)の中へのポインタについては、次の算術演算が定義されます。

これらのオペレーションのどれも「安全なコード」の中で許可されません。

異なる種類のポインタ間での算術を使用することによるガベージコレクタへの影響を理解することは重要です。管理されていないポインタは、ガベージコレクタによってコントロールされるメモリに参照を付けてはなりません。それらの上で算術を行なうことは、システムのメモリ安全性を危険にさらすかもしれません(従って、それは安全ではありません)。しかし、それらはガベージコレクタに報告されないので、その演算への影響はありません。

しかしながら、管理されたポインタは、ガベージコレクタに報告されます。ガーベジコレクションの一部として、それらが指す位置の内容およびポインターそれ自体の両方は修正することができます。それらが、その管理下(評価スタック、呼び出しスタック、スタティック・メモリあるいは別のアロケーターの管理下のメモリ)にないメモリを指す場合、ガベージコレクタは管理されたポインタを無視するでしょう。しかしながら、管理されたポインタがガベージコレクタによってコントロールされたメモリを参照する場合、それはオブジェクトのフィールド、配列の要素あるいはちょうど配列の終了を過ぎた要素のアドレスを指示するに違いありません。アドレス算術が他の位置(割り付けられたメモリ中のオブジェクトヘッダーあるいはギャップ)を参照する、管理されたポインタを作成するために使用される場合、ガベージコレクタのオペレーションは無指定です。

1.1.4.1 アンマネージドポインタ(Unmanaged Pointers)

管理されていないポインタはC/C++のような言語の中で使用される従来のポインタです。それらの使用上の制限はありません。しかし、それらの大部分は証明することが出来ないコードになります。アンマネージドポインタは、あたかもそれらが符号なし整数(CLIではそのように扱われます)かのように、アンマネージドポインタを含んでいるマーク位置へ完全に有効ですが、特定のタイプのデータにアンマネージドポインタとしてそれらを目立たさせるほうが多くの場合よい。これは、返り値、ローカル変数あるいは引数のためにシグネチャの中で「ELEMENT_TYPE_PTR」を使用する、あるいはフィールドまたは配列要素のためにポインタ型を使用することにより行われます。

管理されていないポインタはガベージコレクタに報告されず、整数が使用することができる方法の中で使用することができます。

1.1.4.2 マネージドポインタ(&型)(Managed Pointers)

マネージドポインタ(&)は、ローカル変数、メソッドの引数、オブジェクトのフィールド、値型のフィールド、配列の要素、あるいは配列の終了を過ぎた要素が格納されるアドレス(管理された配列の中へのポインタインデックスのために)を指し示します。マネージドポインタは「null」にはなりません。(マネージドメモリを指さなくても、それらはガベージコレクタに報告されるに違いありません)

マネージドポインタは、返り値、ローカル変数、引数のためにシグネチャの中で「ELEMENT_TYPE_BYREF」を使用する、あるいはフィールドか配列要素のために「by-ref型」を使用することにより指定されます。

1.2 同系統命令表(Instruction Variant Table)

3章では、各命令が同系統命令表にまとめられて示されます。それは、命令の各変形について説明しています。「フォーマット」テーブルのは、すべての引数に加えて、命令のオペコードをリストします。

形式
(Format)
命令形式
(Assembly Format)
説明
(Description)
FE 0A <unsigned int16> Ldarga argNum fetch the address of argument argNum.
0F <unsigned int8> Ldarga.s argNum fetch the address of argument argNum, short form

「フォーマット」の最初の1つあるいは2つの番号は、この指示がどのようにコード化されるか(その「オペコード」)を示します。したがって、ldarga命令は、別の命令の終わりに「FE」続けて「0A」を保持するバイトとしてコード化されます。タイプ名は、1つの命令列の中で続くべき数を表わします。2バイトこの例において、符号なしの整数として直接扱われることになっている量は「FE 0A」オペコードに続きます。

内蔵型(int8、符号無しint8、int16、符号無しint16、int32、符号無しint32、int64、符号無しin64、float32およびfloat64)が、現われることができる固定サイズのうちのどれでも、記述をフォーマットします。これらの型は、引数用のバイトの数およびどのようにそれを解釈しなければならないか(符号付き、符号無しあるいは浮動小数点)を定義します。さらに、メタデータ・トークンが<T>として示されて現われることができます。印は4バイトの整数としてコード化されます。引数はすべて、リトル・エンディアンです。命令オペコードおよび引数のためのバイトは、できるだけ(整列パディングは終っていません)しっかりとパックされます。

「Format」には命令それぞれについて、記憶を助ける「Assembly Format」を定義します。命令列が引数を伴っているものについては、命令への引数の各々に名前を付けます。各命令引数については、「Assembly Format」に名前があります。これらの名前は、命令記述の中でその後使用されます。

1.2.1 オペコードエンコーディング(Opcode Encodings)

CIL オペコードは長さ1バイト以上です(更にオペランドが続くかもしれません)。第1のバイトが「0x00~0xEF」または「0xFC~0xFF」の範囲ものもは標準化のために予約済です。第1のバイトが「0xF0~0xFB」の範囲は空いていて、実験の目的に利用可能です。任意の方法の実験オペコードの使用は無効の、そして結果証明できない方法を与えます。

現在定義された命令コードは、表1の中で指定されます。

【表1:長いので略】

1.3 スタック推移図(Stack Transition Diagram)

スタック推移図は命令が実行される前、および後の評価スタックの状態を示します。以下は、典型的なスタック推移図です。

...,value1,value2 -> ...,result

この図は、スタックがその上に少なくとも2つの要素を持っているに違いないことを示します。また、定義では、一番上の値(「スタックのトップ」あるいは「最も最近Pushされた」)はValue2と呼ばれ、その下が(value2に先立ってPushされた)value1と呼ばれます。(このような図では、スタックはページに沿って右に成長します)。その命令はスタックからこれらの値を取り除き、それらをresultと呼ばれる別の値に取り替えます。

1.4 英語の記述(English Description)【今回は日本語ね】

英語の記述は、フォーマットおよびスタック推移だけでは明白でない命令に関するどんな詳細も記述します。

1.5 オペランド型表( Operand Type Table)

多くのCIL処理がスタック上で数値のオペランドをとります。これらの処理はそれらがどのようにオペランドの型に対処するかに依存して、いくつかのカテゴリーに分類されます。次の表は有効な型のオペランドおよび結果の型を要約します。ここで引用されたタイプが、CIL立証のようなツールによって使用されるもっと詳細な型ではなくCLIによってトレースされるような型であることに注目してください。CLIによってトレースされた型は次のとおりです。「int32」「int64」「native int」「F」「O」および「&」。

「A op B (オペコードは add, div, mul, rem, sub)」。下記の表はオペランド型の個々の可能な組み合わせのために、結果の型を示します。マークされないマスは無効なCIL命令を示します。暗くなったマスは、検証可能でないCIL命令を示します。命令のリストを備えたマスはそれらの命令にのみ有効です。

表2:2項演算
A's Type B's Type
int32 int64 native int F & O
int32 int32   native int   &(add)  
int64   int64        
native int native int   native int   &(add)  
F       F    
& &(add, sub)   &(add, sub)   native int(sub)  
O            

次の表は「neg命令」のものです。マークされない箱は無効なCIL命令を示します。この命令の有効な用途はすべて検証可能です。

表3:単項演算
ペランドの型 int32 int64 native int F & O
戻り値の型 int32 int64 native int F    

下の表は、スタック上のトップ2つの値に基づいて、ブールの返り値または分岐を行う命令についてです。beq、beq.s、bge、bge.s、bge.un、bge.un.s、bgt、bgt.s、bgt.un、bgt.un.s、ble、ble.s、ble.un、ble.un.s、blt、blt.s、blt.un、blt.un.s、bne.un、bne.un.s、ceq、cgt、cgt.un、clt、clt.un、に使用されます。「OK」そのオペランドタイプが全ての処理について有効であることを示しています。何も書かれていないマスは無効なCIL命令を示しています。暗くなったマスは、検証可能でないCIL命令を示します。命令のリストを備えたマスはそれらの命令にのみ有効です。

表4:バイナリ比較と分岐命令
  int32 int64 native int F & O
int32 OK   OK      
int64   OK        
native int OK   OK   Beq[.s],
bne.un[.s],
ceq
 
F       OK    
&     beq[.s],
bne.un[.s],
ceq
  OK1  
O           beq[.s],
bne.un[.s],
ceq2
  1. beqを除いて、両方のオペランドが同じ配列要素へのポインタであると知られている場合、これらの組み合わせはbne.un(あるいは短いバージョン)あるいはceqで意味を持ちます。しかしながら、CLIはこの強制をチェックしないためのセキュリティ問題はありません。

    注意 : 2つのオペランドが同じ配列へポインタでない場合、結果は、ガベージコレクトの中の2つの関係ないデータ項目の距離です。この距離は、次のガーベジコレクションで変わるでしょう。本質的に、結果は有用なものではなく計算するために使用することができません。

  2. cgt.unはObjectRefs(O)で許容されていて検証可能です。 nullとObjectRefを比べるとき、これは一般的に使用されます(「compare-not-equal」命令(それはそうでなければより多くの明白な解決になるだろう)はありません)。【訳:変】

and、div.un、not、or、rem.un、xorを使用した場合、これらの命令は整数型でのみ作動します。また、div.unとrem.unの命令は符号なし整数としてそれらの引数を扱い、符号無しの結果に対応するビットパターンを出力します。しかしながら、CLIの明細に記述されるように、CLIはスタック上の符号有り・符号なし整数を区別しません。そのnot命令は単項で、入力と同じタイプを返します。shlおよびshr命令はそれらの最初のオペランドと同じタイプを返します。また、それらの2番目のオペランドは符号無しネイティブ整数型であるに違いありません。空白のマスは無効なCIL、命令です。他のすべてのマスは、オペランドの検証可能な組み合わせを表します。

表5:整数演算
  int32 int64 native int F & O
int32 int32   native int      
int64   int64        
native int native int   native int      
F            
&            
O            

下の表はシフト演算についてのものです。シフト演算のためのオペランドおよび結果の正しい組み合わせを表しています(shl、shr、shr.un)。空白のマスは無効なCIL命令を示します。他のすべてのマスは、オペランドの検証可能な組み合わせを表示します。もしも、「シフトする量」オペランドが「シフトされる」オペランドより大きい幅の場合、結果は実装に依存します。(例えばint32整数が37ビットシフトした場合)

表6:シフト演算
  シフトする量
int32 int64 native int F & O
シフトされる側 int32 int32   int32      
int64 int64   int64      
native int native int   native int      
F            
&            
O            

下の表はオーバーフロー付きの演算に関する命令についての表です。目標データ型の中で結果を表わすことができない場合、これらの命令は例外を生成します。add.ovf, add.ovf.un, mul.ovf, mul.ovf.un, sub.ovf, sub.ovf.un命令です。暗くなったマスは検証可能ではありません。また、空白のマスは無効なCIL命令を示しています。

表7:オーバーフロー付き算術演算

 

int32

int64

native int

F

&

O

int32 int32   native int   &
add.ovf.un
 
int64   int64        
native int native int   native int   &
add.ovf.un
 
F            
& &
add.ovf.un,
sub.ovf.un
  &
add.ovf.un,
sub.ovf.un
  native int
sub.ovf.un
 
O            

下の表は変換命令についてのものです。これらの命令は、評価スタック上のトップのアイテムをある数値の型から別の型に変換します。結果型は、命令の一部として指定されたデータ型として表現可能なことを保証されます(つまり、conv.u2命令は、符号無しint16に格納することができる値を返します)。しかしながら、スタックには、最小で4バイトの値しか格納できません。conv.<型>,conv.ovf.<型>,conv.ovf.<型>.un命令が使えます。暗くなったマスは検証可能でない命令を示します。また、空白のマスは無効なCIL命令を示しています。

表8:変換命令
Convert-To Input (from evaluation stack)
int32 int64 native int F & O
int8
unsigned int8
int16
unsigned int16
Truncate1 Truncate1 Truncate1 Truncate to zero2    
int32
unsigned int32
Nop Truncate1 Truncate1 Truncate to zero2    
int64 Sign extend Nop Sign extend Truncate to zero2 Stop GC tracking Stop GC tracking
unsigned int64 Zero extend Nop Zero extend Truncate to zero2 Stop GC tracking Stop GC tracking
native int Sign extend Truncate1 Nop Truncate to zero2 Stop GC tracking Stop GC tracking
native unsigned int Zero extend Truncate1 Nop Truncate to zero2 Stop GC tracking Stop GC tracking
All Float Types To Float To Float To Float Change precision3    
  1. 「Truncate(切り詰める)」は単に大きな桁のバイトが無視されます。また、スタックに積む場合に4バイトの幅よりも狭い場合には、0拡張または符号拡張が行われます。たとえば、0x1234 ABCDを評価スタックから8ビットのデータに変換すると、結果0xCDを返します。目標型がint8だった場合、0xFFFF FFCDを返すために符号拡張されます。目標型が符号無しint8だった場合、0x0000 00CDを返すために0拡張されます。
  2. 「Truncate to zero(0方向へ切り捨て)」は、浮動小数点式の数が0方向への切り捨てによって整数に変換されるだろうということを意味します。したがって、「1.1」は「1」に変換されます。また「-1.1」は「-1」に変換されます。
  3. 評価スタックで利用可能な現在の正確さから指示によって指定された正確さに切り替えます。スタックが出力サイズより多くの正確さを持っている場合、変換は、結果の低位ビットを計算するためにIEC 60559:1989「 直近への丸め(round to nearest)」モードを使用して行なわれます。
  4. 「Stop GC Tracking(ガベージコレクタ追跡停止)」は変換後のアイテムの値がガベージコレクション操作に報告されないことを意味しています(つまり、ガベージコレクションによってその値は追跡されません)。

1.6 暗黙の引数強制(Implicit Argument Coercion)

CLIは6つの型(int32, native int, int64, F, O, &)のみに働いていますが、メタデータははるかに豊富なモデルをメソッドの引数に提供します。メソッドの呼び出しの時、CLIは次の表の中に詳述されている暗黙の型変換を行ないます(概念的に、それは適切なconvを挿入します。それらの結果は切り捨てや、丸め誤差があるかもしれないです)。「OK」と書かれているマスは、暗黙の変換が行われます。暗くなっている箱は検証可能でない変換です。また、無効な変換は空白のマスになっています(コンパイラーは目的の効果を得るために明示的なconv.*やconv.*. ovf命令を使うことも出来ます)。

表9:暗黙の引数変換
Type In Signature Stack Parameter
int32 native int int64 F & O
int8 OK OK        
unsigned int8, bool OK OK        
int16 OK OK        
unsigned int16, char OK OK        
int32 OK OK        
unsigned int32 OK OK        
int64     OK      
unsigned int64     OK      
native int OK
Sign extend
OK        
native unsigned int OK
Zero extend
OK
Zero extend
       
float32       Note4    
float64       Note4    
Class           OK
Value Type (Note2) Note1 Note1 Note1 Note1    
By-Ref( & )   OK
Start GC tracking
    OK  
Ref Any(Note3)            
  1. 内蔵の型を値型であることを要求されるパラメーターへ渡すことは許可されません。
  2. CLIのスタックは値型を含むことができます。スタック上の特別の値型が対応するパラメータによって要求されたクラスと正確に一致する場合、これらは単に渡されるかもしれません。
  3. Ref Anyを構築し渡す特殊命令があります。
  4. CLIは、その内部Fタイプを使用して、浮動小数点引数を通ることを許されます、clause 1.1.1を見てください【まだ訳していません。英語のドキュメントへのリンク】。CILジェネレーターはもちろん明示的なconv.r4、conv.r4.ovfあるいは同様の命令を含んでいるかもしれません。

この表に関するさらなる注:

1.7 CILコードに対する制限

確実さのために、CILコードには詳細な制限があります。

これらはCILからネイティブコードへの単純なコンパイラを構築することをより容易にするために課されて、いくつかのさらなる制限もあります。このセクションは適用される一般的な制限と、個々の命令のためにあります。

1.7.1 命令ストリーム

メソッドの実装は下に指定されるようにコード化されて、CIL命令から連続するブロックによって提供されます。メソッドのための命令ブロックのアドレスと長さは、ファイル・フォーマットで指定されます( Partition II_alink_partitionII, Common Intermediate Language Physical Layout【英語のページ飛びます】を参照)。第1の命令は、命令ブロックの第1のバイト(最低のアドレス)にあります。

命令は可変サイズです。各命令のサイズは、命令バイト自体の内容(を解読することによって)から決定することができます。サイズ、また、命令内のバイトの注文は各命令定義によって指定されます。命令は、バイトストリームの中で詰め物をせずに続きます。アラインメントおよびバイトオーダー両方に関係しません。

各命令は、バイトの正確な数を占めます。また、命令ブロックの終了まで、次の命令は次のバイトに直ちに始まります。命令ブロックが(指定されたブロックの長さまでに)完全な最後の指示を形成せずに終了することは無効です。

命令プリフィックスは、新しい命令を導入せずに命令の長さを拡張します。1つ以上のプリフィックスがある命令は、第1の命令プリフィックスの第1のバイトにからのみ始まります。

【ここの囲みは間違っている可能性大です。】

注意:命令ブロックの終了まで、それが分岐の目標でなくても、どんなコントロールを移す命令の後に続く命令はデコードされます。コントロールが到達不可能な場合でも命令が命令ストリームへと現れるかもしれません。相対アドレスなデータアドレッシングモードはありません。また、生のデータは、直接命令ストリームの内に埋め込むことができません。ある命令は命令の一部として即値を埋め込むことを可能にします。しかしながら、それは命令ストリームに直接埋め込まれていた生のデータの許可と異なります。到達不能コードがマシンに生成されたコードの結果現われるかもしれないし許可されます。しかし、それは、常に適切に決まった命令シーケンスの形をしているに違いありません。

命令ストリームは、翻訳の実行に先立って翻訳することができます。また、関連する命令ブロックが廃棄されます。したがって、コード・アドレスを捕らえて操作するcall、retなどのような命令さえ、CIL命令ストリームのアドレスの代わりに翻訳されたアドレス上で作動するために仮想になることができます。


ページの一番上へ
初版2006-4-5 最終2006-8-11
[Atelier Blue アトリエブルー]Homeプログラミング IL(CIL,MSIL) ECMA-335翻訳ドキュメント>CIL 命令セット(CIL Instruction Set)