OSDN Git Service

e347883ca371c2adba5953f5b0a8e885b5bd01ea
[chnosproject/AI004.git] / webcpu / webcpu.js
1 //WebCPUは、このディレクトリにあるファイルで完結している。
2
3 function WebCPU_Exception(errno, infoArray){
4         this.errno = errno;
5         this.infoArray = infoArray;
6 }
7 WebCPU_Exception.prototype = {
8         errorMessageList: [
9                 "Trap.",
10                 "Pre-compile error.",
11                 "Execution error.",
12         ],
13         getMessageString: function(){
14                 var s = "";
15                 s += "Error" + this.errno.toString().toUpperCase();
16                 if(this.errno < 0 || this.errorMessageList.length <= this.errno){
17                         s += ":Unknown\n";
18                 } else{
19                         s += ":" + this.errorMessageList[this.errno] + "\n";
20                 }
21                 if(this.infoArray){
22                         s += "  >" + this.infoArray.toString() + "\n";
23                 }
24                 return s;
25         },
26 }
27 // throw new WebCPU_Exception(2, [""]);
28
29 function WebCPU(){
30         //APIクラスインスタンス取得
31         this.API = new WebCPU_API();
32
33         //DOMオブジェクト連携
34         this.debugMessageText = null;
35         this.debugIntegerRegisterText = null;
36         this.debugPointerRegisterText = null;
37         //デバッグコンソール設定
38         this.debugMessageBuffer = "";
39         var that = this;
40         this.messageTimer = null;
41         
42         //メモリ
43         //メモリはラベルごとにページとして区切られ、それらの配列が一つのメモリとなる。
44         this.mainMemory = new WebCPU_Memory();
45         this.memoryPageCounter = 0;
46         this.memoryInstructionCounter = 0;
47         this.stopFlag = false;
48         
49         //レジスタ配列
50         this.registers = new Object;
51         this.registers.Integer = new Array(64);
52         
53         //初期化
54         this.reset();
55         
56         //命令リスト
57         this.instruction = new Array(0xFF + 1);
58         //命令テーブル初期化
59         for(var i = 0; i < this.instruction.length; i++){
60                 this.instruction[i] = WebCPU_Instruction_Undefined;
61         }
62         //
63         this.instruction[0x00] = WebCPU_Instruction_NOP;
64         this.instruction[0x01] = WebCPU_Instruction_LB;
65         this.instruction[0x02] = WebCPU_Instruction_LIMM;
66         this.instruction[0x03] = WebCPU_Instruction_PLIMM;
67         this.instruction[0x04] = WebCPU_Instruction_CND;
68         this.instruction[0x08] = WebCPU_Instruction_LMEM;
69         this.instruction[0x09] = WebCPU_Instruction_SMEM;
70         this.instruction[0x0E] = WebCPU_Instruction_PADD;
71         this.instruction[0x0F] = WebCPU_Instruction_PDIF;
72         //
73         this.instruction[0x10] = WebCPU_Instruction_TernaryOperation;
74         this.instruction[0x11] = WebCPU_Instruction_TernaryOperation;
75         this.instruction[0x12] = WebCPU_Instruction_TernaryOperation;
76         this.instruction[0x14] = WebCPU_Instruction_TernaryOperation;
77         this.instruction[0x15] = WebCPU_Instruction_TernaryOperation;
78         this.instruction[0x16] = WebCPU_Instruction_TernaryOperation;
79         this.instruction[0x18] = WebCPU_Instruction_TernaryOperation;
80         this.instruction[0x19] = WebCPU_Instruction_TernaryOperation;
81         this.instruction[0x1A] = WebCPU_Instruction_TernaryOperation;
82         this.instruction[0x1B] = WebCPU_Instruction_TernaryOperation;
83         //
84         this.instruction[0x1E] = WebCPU_Instruction_PCP;
85         //
86         this.instruction[0x20] = WebCPU_Instruction_TernaryOperation;
87         this.instruction[0x21] = WebCPU_Instruction_TernaryOperation;
88         this.instruction[0x22] = WebCPU_Instruction_TernaryOperation;
89         this.instruction[0x23] = WebCPU_Instruction_TernaryOperation;
90         this.instruction[0x24] = WebCPU_Instruction_TernaryOperation;
91         this.instruction[0x25] = WebCPU_Instruction_TernaryOperation;
92         this.instruction[0x26] = WebCPU_Instruction_TernaryOperation;
93         this.instruction[0x27] = WebCPU_Instruction_TernaryOperation;
94         //
95         this.instruction[0x28] = WebCPU_Instruction_TernaryOperation;
96         this.instruction[0x29] = WebCPU_Instruction_TernaryOperation;
97         this.instruction[0x2A] = WebCPU_Instruction_TernaryOperation;
98         this.instruction[0x2B] = WebCPU_Instruction_TernaryOperation;
99         this.instruction[0x2C] = WebCPU_Instruction_TernaryOperation;
100         this.instruction[0x2D] = WebCPU_Instruction_TernaryOperation;
101         //
102         this.instruction[0x32] = WebCPU_Instruction_MALLOC;
103         this.instruction[0x34] = WebCPU_Instruction_DATA;
104         //
105         this.instruction[0xFE] = WebCPU_Instruction_REMARK;
106         
107         this.message("<<< Initialized >>>\n");
108 }
109 WebCPU.prototype = {
110         loadBinaryText: function(binStr){
111                 //引数はフロントエンドコードのHex文字列も可能。(Not implemented.)
112                 //改行やスペースも含まれていてよい。
113                 //シグネチャも含まれていてよい
114                 binStr = replaceAll(binStr, " ", "");
115                 binStr = replaceAll(binStr, "\n", "");
116                 binStr = replaceAll(binStr, "\r", "");
117                 binStr = replaceAll(binStr, "\t", "");
118                 binStr = binStr.toUpperCase();
119                 if(binStr.substr(0, 4) == "05E1"){
120                         //シグネチャあり
121                         this.message("LoadBinaryText:OSECPU signature found.\n", 10);
122                         if(binStr.substr(4, 2) == "00"){
123                                 //BackEndCode
124                                 this.message("LoadBinaryText:This is BackEndCode.\n", 10);
125                                 binStr = binStr.substr(6);
126                         } else{
127                                 //FrontEndCode
128                                 this.message("LoadBinaryText:This is FrontEndCode.\n", 10);
129                                 binStr = binStr.substr(4);
130                                 this.loadFrontEndBinaryText(binStr);
131                                 return;
132                         }
133                 } else{
134                         this.message("LoadBinaryText:OSECPU signature NOT found.\n", 1);
135                 }
136                 this.loadBackEndBinaryText(binStr);
137         },
138         loadBackEndBinaryText: function(binStr){
139                 //引数はバックエンドコードのHex文字列表現でスペースなどの他の文字の混入は認められない。
140                 this.message("****LoadBackEndBinaryText****\n", 30);
141                 this.mainMemory.initMemory();
142                 this.memoryPageCounter = 0;
143                 this.memoryInstructionCounter = 0;
144                 
145                 try{
146                         for(var i = 0; i < binStr.length; ){
147                                 //命令解釈
148                                 var id = parseInt(binStr.substr(i, 2), 16);
149                                 i += 2;
150                                 var instr = new this.instruction[id](id);
151                                 instr.binOffset = (i >> 1) - 1;
152                                 var instrarglen = instr.loadArguments(binStr, i);
153                                 if(isNaN(parseInt(instrarglen))){
154                                         throw new WebCPU_Exception(1, ["Invalid instrarglen."]);
155                                 }
156                                 //instrarglenをバイト単位から文字列単位に変換し、さらに引数部分のみのサイズに補正する。
157                                 instrarglen = (instrarglen - 1) * 2;
158                                 //命令オペランド長チェック
159                                 if(instrarglen > binStr.length - i){
160                                         //オペランドの長さ分だけのバイナリがなかった、つまり不完全な状態で途切れている
161                                         throw new WebCPU_Exception(1, ["Invalid instrarglen."]);
162                                 }
163                                 i+= instrarglen;
164                                 
165                                 if(id == 0x01){
166                                         //ラベル命令だったのでメモリページを新たにする。
167                                         this.mainMemory.addMemoryPage(new WebCPU_MemoryPage());
168                                         this.memoryPageCounter++;
169                                         this.memoryInstructionCounter = 0;
170                                 }
171                                 
172                                 this.mainMemory.root[this.memoryPageCounter].addMemoryData(instr);
173                         }
174                 } catch(e){
175                         this.message("****LoadBackEndBinaryText Abort:\n", 1);
176                         if(e instanceof WebCPU_Exception){
177                                 this.message(e.getMessageString(), 1);
178                         } else{
179                                 throw e;
180                         }
181                         this.showDisassembledCode();
182                         this.mainMemory.initMemory();
183                         this.memoryPageCounter = 0;
184                         this.memoryInstructionCounter = 0;
185                 }
186                 this.showDisassembledCode();
187                 this.message("****LoadBackEndBinaryText End****\n", 30);
188                 
189                 this.memoryPageCounter = 0;
190                 this.memoryInstructionCounter = 0;
191                 this.reset();
192         },
193         loadFrontEndBinaryText: function(binStr){
194                 //引数はフロントエンドコードのHex文字列表現でスペースなどの他の文字の混入は認められない。
195                 this.message("****LoadFrontEndBinaryText****\n", 40);
196                 this.mainMemory.initMemory();
197                 this.memoryPageCounter = 0;
198                 this.memoryInstructionCounter = 0;
199                 //フロントエンドコードデコーダーの読み込み
200                 this.loadBinaryText(decoderBinaryString);
201                 //変換準備
202                 var backendMaxSize = 65535;
203                 var temp0MaxSize = 2 * 1024 * 1024;
204                 var temp1MaxSize = 16 * 1024;
205                 var temp2MaxSize = 64;
206                 var temp3MaxSize = 4 * 1024 + 1;
207                 var temp4MaxSize = 256;
208                 var m;
209                 //P02 = T_UINT8:  &backend[2] (出力バッファ先頭)
210                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8, backendMaxSize);
211                 this.registers.Pointer[0x02] = new WebCPU_Pointer(m);
212                 //P03 = T_UINT8:  &backend[backend-maxsize] (出力バッファの限界)
213                 this.registers.Pointer[0x03] = this.registers.Pointer[0x02].getCopy();
214                 this.registers.Pointer[0x03].addressOffset = backendMaxSize;
215                 //P04 = T_UINT8:  &frontend[2] (入力データ先頭)
216                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8);
217                 this.registers.Pointer[0x04] = new WebCPU_Pointer(m);
218                 this.registers.Pointer[0x04].addressOffset = 0;
219                 this.registers.Pointer[0x04].memoryPage.data[1].data = new Array();
220                 var a = this.registers.Pointer[0x04].memoryPage.data[1].data;
221                 var i;
222                 for(i = 0; i * 2 < binStr.length; i++){
223                         a.push(parseInt(binStr.substr(i * 2, 2), 16));
224                 }
225                 //P05 = T_UINT8:  &frontend[frontend-size] (入力データの終端:最終バイトの次のアドレス)
226                 this.registers.Pointer[0x05] = this.registers.Pointer[0x04].getCopy();
227                 this.registers.Pointer[0x05].addressOffset = i;
228                 //P06 = T_UINT8:  &temp0[0] (要素数が2M以上のテンポラリバッファ)
229                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8, temp0MaxSize);
230                 this.registers.Pointer[0x06] = new WebCPU_Pointer(m);
231                 //P07 = T_UINT8:  &temp0[temp-maxsize]
232                 this.registers.Pointer[0x07] = this.registers.Pointer[0x06].getCopy();
233                 this.registers.Pointer[0x07].addressOffset = temp0MaxSize;
234                 //P0A = T_UINT32: &temp1[0] (要素数が16Kくらいあれば十分なバッファ)
235                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT32, temp1MaxSize);
236                 this.registers.Pointer[0x0A] = new WebCPU_Pointer(m);
237                 //P0B = T_SINT32: &temp2[0] (要素数が64のバッファ:Pxxレジスタの個数)
238                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.SINT32, temp2MaxSize);
239                 this.registers.Pointer[0x0B] = new WebCPU_Pointer(m);
240                 //P0C = T_SINT32: &temp3[0] (要素数が4Kのバッファ:登録可能ラベル数)
241                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.SINT32, temp3MaxSize);
242                 this.registers.Pointer[0x0C] = new WebCPU_Pointer(m);
243                 //P0D = T_UINT8:  &temp4[0] (要素数が256のバッファ)
244                 m = this.mainMemory.allocateMemoryPage(WebCPU.pType.UINT8, temp4MaxSize);
245                 this.registers.Pointer[0x0D] = new WebCPU_Pointer(m);
246                 //変換
247                 this.execute();
248                 /*
249                 P02 == バックエンドコードの終端, つまり P02 - &backend[0] = バックエンドコードのサイズ
250                 */
251                 if(this.registers.Integer[0x00] == 0){
252                         //R00 == 0 正常終了
253                         var binData = this.registers.Pointer[0x02].memoryPage.data[1];
254                         var binStr = "";
255                         for(var i = 0; i < this.registers.Pointer[0x02].addressOffset; i++){
256                                 binStr += ("00" + binData.data[i].toString(16)).slice(-2);
257                         }
258                         this.message("[" + binStr + "]\n");
259                         this.loadBackEndBinaryText(binStr);
260                         this.reset();
261                 } else{
262                         //R00 != 0 変換失敗
263                         this.message("loadFrontEndBinaryText: Translate failed.\n");
264                 }
265                 
266                 this.message("****LoadFrontEndBinaryText End****\n", 40);
267         },
268         executeStepIn: function(){
269                 //ステップ実行する。
270                 //一回実行するたびに再描画する。
271                 var retv = this.executeStepIn_Internal(true);
272                 this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0);
273                 return retv;
274         },
275         executeStepIn_Internal: function(isManualStepIn){
276                 //ステップ実行の内部部分。
277                 //終端到達時は1を、まだ後続命令がある場合は0を返す。
278                 //終了時にのみ再描画を行う
279                 if(this.stopFlag){
280                         this.message(">stepIn:Break.\n", 2);
281                         this.stopFlag = false;
282                         this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0);
283                         return 2;
284                 }
285                 var instr = this.fetchMemoryNext();
286                 if(instr === undefined){
287                         this.message(">stepIn:control reached end of binary.\n", 2);
288                         this.API.API_flushWin(this, this.API.mainWindowCanvas.width, this.API.mainWindowCanvas.height, 0, 0);
289                         return 1;
290                 }
291                 if(isManualStepIn){
292                         this.message(">stepIn:" + this.memoryPageCounter + "-" + (this.memoryInstructionCounter - 1) + ":" + instr.toString() + "\n", 20);
293                 }
294                 instr.execute(this);
295                 //これ以降this.memoryInstructionCounterが今実行した命令を指すとは限らない。(JMP系命令のため)
296                 /*
297                 //ブレークポイント
298                 if(this.memoryPageCounter == 233 && this.memoryInstructionCounter == 0){
299                         this.message(">stepIn:Breakpoint.\n", 2);
300                         return 3;
301                 }
302                 */
303                 return 0;
304         },
305         execute: function(){
306                 //最速で実行する
307                 for(;;){
308                         if(this.executeStepIn_Internal(false) != 0){
309                                 return;
310                         }
311                 }
312         },
313         reset: function(){
314                 //実行環境をリセットする。メモリ内容は保持される。
315                 for(var i = 0; i < this.registers.Integer.length; i++){
316                         this.registers.Integer[i] = 0;
317                 }
318                 this.registers.Pointer = new Array(64);
319                 for(var i = 0; i < this.registers.Pointer.length; i++){
320                         this.registers.Pointer[i] = new WebCPU_Pointer(null);
321                 }
322                 //Set P28 for API  calling.
323                 this.registers.Pointer[0x28].memoryType = 0xC0FFEE;
324                 //
325                 this.memoryPageCounter = 0;
326                 this.memoryInstructionCounter = 0;
327                 this.stopFlag = false;
328                 //reset window
329                 if(this.API.mainWindowCanvas){
330                         this.API.setMainWindowCanvasDOMObject(this.API.mainWindowCanvas);
331                 }
332                 this.message("<<< Reset >>>\n");
333         },
334         fetchMemoryNext: function(){
335                 if(this.mainMemory.root[this.memoryPageCounter].data.length <= this.memoryInstructionCounter){
336                         this.memoryPageCounter++;
337                         if(this.mainMemory.root.length <= this.memoryPageCounter){
338                                 this.memoryPageCounter--;
339                                 return undefined;
340                         }
341                         this.memoryInstructionCounter -= this.mainMemory.root[this.memoryPageCounter - 1].data.length;
342                 }
343                 var retv = this.mainMemory.root[this.memoryPageCounter].data[this.memoryInstructionCounter];
344                 this.memoryInstructionCounter++;
345                 return retv;
346         },
347         setMainWindowCanvasDOMObject: function(id){
348                 this.API.setMainWindowCanvasDOMObject(document.getElementById(id));
349         },
350         setDebugMessageDOMObject: function(name){
351                 if(name){
352                         this.debugMessageText = document.getElementsByName(name)[0];
353                         if(!this.debugMessageText){
354                                 this.debugMessageText = document.getElementById(name);
355                         }
356                 } else{
357                         this.debugMessageText = null;
358                 }
359                 this.setDebugTimer();
360         },
361         setDebugIntegerRegisterDOMObject: function(name){
362                 if(name){
363                         this.debugIntegerRegisterText = document.getElementsByName(name)[0];
364                         if(!this.debugIntegerRegisterText){
365                                 this.debugIntegerRegisterText = document.getElementById(name);
366                         }
367                 } else{
368                         this.debugIntegerRegisterText = null;
369                 }
370                 this.setDebugTimer();
371         },
372         setDebugPointerRegisterDOMObject: function(name){
373                 this.debugPointerRegisterText = document.getElementsByName(name)[0];
374                 if(name){
375                         this.debugPointerRegisterText = document.getElementsByName(name)[0];
376                         if(!this.debugPointerRegisterText){
377                                 this.debugPointerRegisterText = document.getElementById(name);
378                         }
379                 } else{
380                         this.debugPointerRegisterText = null;
381                 }
382                 this.setDebugTimer();
383         },
384         setDebugTimer: function(){
385                 if(!this.debugMessageText && !this.debugIntegerRegisterText && !this.debugPointerRegisterText){
386                         //すべて無効だったらタイマーの動作自体を止める
387                         window.clearTimeout(this.messageTimer);
388                         this.messageTimer = null;
389                         WebCPU_Instruction.prototype.isEnabledPrintSourceRegister = false;
390                         WebCPU_Instruction.prototype.isEnabledPrintDestinationRegister = false;
391                 } else if(!this.messageTimer){
392                         //どれかが有効でかつタイマーが止まっていたらスタートさせる
393                         var that = this;
394                         this.messageTimer = window.setInterval(function(){that.debugShowTick();}, 50);
395                         WebCPU_Instruction.prototype.isEnabledPrintSourceRegister = true;
396                         WebCPU_Instruction.prototype.isEnabledPrintDestinationRegister = true;
397                 }
398         },
399         debugShowTick: function(){
400                 if(this.debugMessageText && this.debugMessageBuffer != ""){
401                         var str = this.debugMessageText.innerHTML + this.debugMessageBuffer;
402                         this.debugMessageBuffer = "";
403                         if(str.length > WebCPU.maxDebugStringLength){
404                                 str = str.slice(str.length - (WebCPU.maxDebugStringLength >> 1));
405                         }
406                         this.debugMessageText.innerHTML = str;
407                         this.debugMessageText.scrollTop = this.debugMessageText.scrollHeight;
408                 }
409                 this.refreshDebugIntegerRegisterText();
410                 this.refreshDebugPointerRegisterText();
411         },
412         message: function(str, id){
413                 //id:メッセージの種類
414                 //省略:常に表示する
415                 //1:Error
416                 //2:Warning
417                 //10:バイナリ読み込みデバッグ
418                 //20:実行時詳細情報
419                 //30:バックエンドバイナリ読み込みデバッグ
420                 //40:フロントエンドバイナリ読み込みデバッグ
421                 if(this.debugMessageText != null){
422                         if(
423                                 true ||
424                                 id == 1 || 
425                                 id == 2 || 
426                                 id == 30
427                         ){
428                                 this.debugMessageBuffer += str;
429                         }
430                 } else if(id == 1){
431                         //エラーのときmessageが無効であればalertで表示する。
432                         window.alert(str);
433                 }
434         },
435         showDisassembledCode: function(){
436                 for(var i = 0; i < this.mainMemory.root.length; i++){
437                         for(var j = 0; j < this.mainMemory.root[i].data.length; j++){
438                                 var instr = this.mainMemory.root[i].data[j];
439                                 this.message("+0x" + instr.binOffset.toString(16).toUpperCase() + ":" + i + "-" + j + ":" + instr.toString() + "\n", 30);
440                         }
441                         this.message(" - - - - \n", 30);
442                 }
443         },
444         refreshDebugIntegerRegisterText: function(){
445                 if(this.debugIntegerRegisterText != null){
446                         this.debugIntegerRegisterText.innerHTML = "";
447                         for(var i = 0; i < this.registers.Integer.length; i++){
448                                 this.debugIntegerRegisterText.innerHTML += "R" +  ("00" + i.toString(16)).slice(-2).toUpperCase() + ":0x" + this.registers.Integer[i].toString(16).toUpperCase() + "\n";
449                         }
450                 }
451         },
452         refreshDebugPointerRegisterText: function(){
453                 if(this.debugPointerRegisterText != null){
454                         this.debugPointerRegisterText.innerHTML = "";
455                         for(var i = 0; i < this.registers.Pointer.length; i++){
456                                 if(this.registers.Pointer[i]){
457                                         this.debugPointerRegisterText.innerHTML += "P" +  ("00" + i.toString(16)).slice(-2).toUpperCase() + ":" + this.registers.Pointer[i].toString() + "\n";
458                                 } else{
459                                         this.debugPointerRegisterText.innerHTML += "P" +  ("00" + i.toString(16)).slice(-2).toUpperCase() + ":(null)\n";
460                                 }
461                         }
462                 }
463         },
464         goToPointerRegister: function(reg0P){
465                 //レジスタはいじらない
466                 //goto
467                 var p = this.registers.Pointer[reg0P];
468                 if(p.memoryType == 1){
469                         //VPtr
470                         this.memoryPageCounter = this.mainMemory.getMemoryPageCountFromMemoryPageInstance(p.memoryPage);
471                         if(this.memoryPageCounter !== undefined){
472                                 this.memoryInstructionCounter = 0;
473                                 this.message("JMP:page " + this.memoryPageCounter + "\n", 20);
474                         } else{
475                                 throw new WebCPU_Exception(2, ["memoryPage not found in mainMemory."]);
476                         }
477                 } else{
478                         throw new WebCPU_Exception(2, ["Can't goto Memory page type is not VPtr."]);
479                 }
480         },
481         createBackendBinaryString: function(){
482                 var s = "05E100";
483                 var instr;
484                 
485                 this.reset();
486                 for(;;){
487                         instr = this.fetchMemoryNext();
488                         if(instr === undefined){
489                                 break;
490                         }
491                         s += instr.createBinaryString(this);
492                 }
493                 return s;
494         },
495         staticOptimize: function(){
496                 //静的最適化
497                 //連続するラベル命令の削除
498                 //一つのメモリページにラベル命令のみがある場合は、それを次のメモリページのラベル名に置換する
499                 var mpage;
500                 var removePageIndexStack = new Array();
501                 var labelIDStack = new Array();
502                 var labelID;
503                 var newLabelID;
504                 for(var i = 0; i < this.mainMemory.root.length; i++){
505                         mpage = this.mainMemory.root[i];
506                         if(mpage instanceof WebCPU_MemoryPage && mpage.data[0] instanceof WebCPU_Instruction_LB){
507                                 //メモリページ
508                                 if(mpage.data.length == 1){
509                                         //ラベルしかないので削除候補に追加
510                                         labelIDStack.push(mpage.data[0].imm32);
511                                         removePageIndexStack.push(i);
512                                 } else{
513                                         //これは必要なラベル命令
514                                         if(labelIDStack.length != 0){
515                                                 for(;;){
516                                                         labelID = labelIDStack.pop();
517                                                         if(labelID == undefined){
518                                                                 break;
519                                                         }
520                                                         this.mainMemory.root.splice(removePageIndexStack[0], 1);
521                                                         i--;
522                                                         this.staticOptimize_ReplaceLabelNumber(labelID, mpage.data[0].imm32);
523                                                 }
524                                                 removePageIndexStack = new Array();
525                                         }
526                                 }
527                         }
528                 }
529                 if(labelIDStack.length != 0){
530                         //プログラム末尾のラベル命令は削除しないようにする
531                         newLabelID = labelIDStack.pop();
532                         for(;;){
533                                 labelID = labelIDStack.pop();
534                                 if(labelID == undefined){
535                                         break;
536                                 }
537                                 this.mainMemory.root.splice(removePageIndexStack[0], 1);
538                                 i--;
539                                 this.staticOptimize_ReplaceLabelNumber(labelID, newLabelID);
540                         }
541                 }
542         },
543         staticOptimize_ReplaceLabelNumber: function(from, to){
544                 var mpage;
545                 var instr;
546                 for(var i = 0, iLen = this.mainMemory.root.length; i < iLen; i++){
547                         mpage = this.mainMemory.root[i];
548                         for(var j = 0, jLen = mpage.data.length; j < jLen; j++){
549                                 instr = mpage.data[j];
550                                 if(instr instanceof WebCPU_Instruction_PLIMM){
551                                         if(instr.imm32 == from){
552                                                 instr.imm32 = to;
553                                         }
554                                 }
555                         }
556                 }
557         }
558 }
559
560 //数値計算
561 function parseSignedInt32(hexStr){
562         //文字列を16進32bit符号あり整数として変換する。
563         var i = parseInt(hexStr, 16);
564         if(i > 0x7fffffff){
565                 //-
566                 return -(~i + 1);
567         }
568         //+
569         return i;
570 }
571
572 function parseSignedInt(hexStr, bits){
573         //文字列を16進符号あり整数として変換する。
574         //32bitまで対応
575         var i = parseInt(hexStr, 16);
576         if(i >= (1 << (bits - 1))){
577                 //-
578                 return -(((0xffffffff >>> (32 - bits)) - i) + 1);
579         }
580         //+
581         return i;
582 }
583
584 function toHexString8(v){
585         return ("00" + v.toString(16).toUpperCase()).slice(-2);
586 }
587
588 function toHexString32(v){
589         if(v < 0){
590                 v = 0x100000000 + v;
591         }
592         return ("00000000" + v.toString(16).toUpperCase()).slice(-8);
593 }
594
595 function replaceAll(str, org, dest){
596         //文字列str中にある文字列orgを文字列destにすべて置換する。
597         //http://www.syboos.jp/webjs/doc/string-replace-and-replaceall.html
598         return str.split(org).join(dest);
599 }