chris
[tamarin-stm.git] / utils / opcodes.as
blobf693389db9c34f6b73791331a0d98d9bac0acc72
1 /* -*- indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2004-2006
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Adobe AS3 Team
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
39 // Compile command:
40 // java -jar utils/asc.jar -d -m -i -AS3 -strict -import core/builtin.abc -import shell/shell_toplevel.abc utils/opcodes.as
43 package {
44 import avmplus.System;
45 import avmplus.File;
47 final class OpCode
49 public function OpCode(isUsed : Boolean, opCode : uint, operandCount : int, canThrow : Boolean, stackMovement : int, name : String, internalOnly : Boolean)
51 m_isUsed = isUsed;
52 m_opCode = opCode;
53 m_operandCount = operandCount;
54 m_canThrow = canThrow;
55 m_stackMovement = stackMovement;
56 m_name = name;
57 m_internalOnly = internalOnly;
60 public function get used() : Boolean { return m_isUsed; }
61 public function get opCode() : uint { return m_opCode; }
62 public function get operandCount() : int { return m_operandCount; }
63 public function get canThrow() : Boolean { return m_canThrow; }
64 public function get stackMovement() : int { return m_stackMovement; }
65 public function get name() : String { return m_name; }
66 public function get internalOnly() : Boolean { return m_internalOnly; }
68 private var m_isUsed : Boolean;
69 private var m_opCode : uint;
70 private var m_operandCount : int;
71 private var m_canThrow : Boolean;
72 private var m_stackMovement : int;
73 private var m_name : String;
74 private var m_internalOnly : Boolean;
76 private static const s_hexRegEx : RegExp = /0x[0-9a-fA-F]{2}/;
79 final class OpCodes
81 public function OpCodes(opCodes : Array)
83 throw new Error("Don't consruct me!!!");
86 public static function parse(opCodesText : String) : Array
88 var abcOpCodeRegEx : RegExp = /ABC_(?P<u>(UNUSED_)?)OP\(\s*(?P<oc>-?[0-9]+)\s*,\s*(?P<ct>[01])\s*,\s*(?P<sm>-?[0-9]+)\s*,\s*(?P<internal>[01])\s*,\s*(?P<n>[\S\)]+)\s*\)/g
89 var opCodeValue : uint = 0;
90 var match : Object = abcOpCodeRegEx.exec(opCodesText);
91 var opCodes : Array = new Array(256);
92 while ((match != null) && (opCodeValue < 256)){
93 var opCode = new OpCode(match.u.length == 0, opCodeValue, int(match.oc), match.ct == "1", int(match.sm), match.n, match.internal == "1");
94 opCodes[opCodeValue] = opCode;
95 ++opCodeValue;
96 match = abcOpCodeRegEx.exec(opCodesText)
99 if (opCodeValue == 256) {
100 return opCodes;
102 return null;
106 class OpCodeOutput
108 public function OpCodeOutput(fileName : String)
110 this.m_fileName = fileName;
113 public function output(opCodes : Array) : void { throw new Error("Call to abstract method!!!"); }
115 protected function write(s : String) : void
117 File.write(m_fileName, s);
120 private static const copyright : String = <x><![CDATA[
121 Version: MPL 1.1/GPL 2.0/LGPL 2.1
123 The contents of this file are subject to the Mozilla Public License Version
124 1.1 (the "License"); you may not use this file except in compliance with
125 the License. You may obtain a copy of the License at
126 http://www.mozilla.org/MPL/
128 Software distributed under the License is distributed on an "AS IS" basis,
129 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
130 for the specific language governing rights and limitations under the
131 License.
133 The Original Code is [Open Source Virtual Machine.].
135 The Initial Developer of the Original Code is
136 Adobe System Incorporated.
137 Portions created by the Initial Developer are Copyright (C) 2004-2006
138 the Initial Developer. All Rights Reserved.
140 Contributor(s):
141 Adobe AS3 Team
143 Alternatively, the contents of this file may be used under the terms of
144 either the GNU General Public License Version 2 or later (the "GPL"), or
145 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
146 in which case the provisions of the GPL or the LGPL are applicable instead
147 of those above. If you wish to allow use of your version of this file only
148 under the terms of either the GPL or the LGPL, and not to allow others to
149 use your version of this file under the terms of the MPL, indicate your
150 decision by deleting the provisions above and replace them with the notice
151 and other provisions required by the GPL or the LGPL. If you do not delete
152 the provisions above, a recipient may use your version of this file under
153 the terms of any one of the MPL, the GPL or the LGPL.
154 ]]></x>.text()[0];
156 protected function wrapInCommentForCLikeLanguages(header : String, body : String, footer : String) : String
158 var lines : Array = body.split("\n");
159 while (lines[0] == "")
160 lines.shift();
161 lines = lines.map(function (line : *) : * { return (line.length > 0 ? " * " : " *") + line; });
163 return "/*"
164 + ((header != null) ? (" ***** " + header + " *****") : "") + "\n"
165 + lines.join("\n")
166 + "\n" + ((footer != null) ? (" * ***** " + footer + " *****") : "" ) + " */\n\n";
169 protected function get copyrightCommentForCLikeLanguages() : String
171 if (m_copyrightCommentForCLikeLanguages != null)
172 return m_copyrightCommentForCLikeLanguages;
173 m_copyrightCommentForCLikeLanguages = wrapInCommentForCLikeLanguages("BEGIN LICENSE BLOCK", copyright, "END LICENSE BLOCK");
174 return m_copyrightCommentForCLikeLanguages;
177 protected function get generatedFileCommentForCLikeLanguages() : String
179 if (m_generatedFileCommentForCLikeLanguages != null)
180 return m_generatedFileCommentForCLikeLanguages;
181 var slashLine : String = "//////////////////////////////////////////////////////////////////////////////////\n";
182 var str : String = slashLine;
183 str += "// GENERATED FILE: DO NOT EDIT!!! See utils/opcodes.as in the tamarin repository.\n"
184 str += slashLine;
185 str += "\n";
186 m_generatedFileCommentForCLikeLanguages = str;
187 return str;
190 private static var m_copyrightCommentForCLikeLanguages : String = null;
191 private static var m_generatedFileCommentForCLikeLanguages : String = null;
192 private var m_fileName : String;
195 class JavaOutput extends OpCodeOutput
197 public function JavaOutput(fileName : String)
199 super(fileName);
202 public override function output(opCodes : Array) : void
204 var str : String = this.copyrightCommentForCLikeLanguages;
205 str += this.generatedFileCommentForCLikeLanguages;
206 str += "package adobe.abc;\n\n"
207 str += "public interface ABCOpCodes {\n"
208 for each (var opCode : OpCode in opCodes) {
209 if (opCode.used) {
210 var opCodeHex : String = opCode.opCode.toString(16);
211 opCodeHex = opCodeHex.length == 1 ? "0" + opCodeHex : opCodeHex;
212 str += " public static final int OP_" + opCode.name + " = 0x" + opCodeHex + ";\n";
216 str += " public static final int operandCountTable[] = new int [] {\n";
217 for each (var opCode : OpCode in opCodes) {
218 str += " " + opCode.operandCount.toString(10) + ",\n" ;
220 str += " };\n"
222 str += " public static final String opNames[] = new String [] {\n";
223 for each (var opCode : OpCode in opCodes) {
224 str += " \"" + opCode.name + "\",\n" ;
226 str += " };\n"
229 str += "}\n";
230 write(str);
233 public static const ext = "java";
237 class AS3Output extends OpCodeOutput
239 public function AS3Output(fileName : String)
241 super(fileName);
244 private static function padOpName(opName : String, minLength : uint) : String
246 while (opName.length < minLength) {
247 opName = opName + " ";
249 return opName;
252 public override function output(opCodes : Array) : void
254 var str : String = this.copyrightCommentForCLikeLanguages;
255 str += this.generatedFileCommentForCLikeLanguages;
256 str += "// This file is to be included by its clients.\n\n"
257 for each (var opCode : OpCode in opCodes) {
258 if ((opCode.used) && (!opCode.internalOnly)) {
259 var opCodeHex : String = opCode.opCode.toString(16);
260 opCodeHex = opCodeHex.length == 1 ? "0" + opCodeHex : opCodeHex;
261 str += "const OP_" + opCode.name + " : int = 0x" + opCodeHex + ";\n";
265 var opNames : Array = new Array(256);
266 var maxOpNameLen : uint = 0;
267 for each (var opCode : OpCode in opCodes) {
268 var opName : String = opCode.used ? opCode.name : "OP_" + opCode.name;
269 if (opCode.internalOnly) {
270 opName = "OP_0x" + opCode.opCode.toString(16).toUpperCase();
272 opNames[opCode.opCode] = opName;
273 maxOpNameLen = Math.max(maxOpNameLen, opName.length);
276 str += "const opNames : Array = [\n";
277 for each (var opName : String in opNames) {
278 str += " \"" + padOpName(opName, maxOpNameLen) + "\",\n" ;
280 str += "];\n"
283 write(str);
286 public static const ext = "as";
289 class TextTable
291 public function TextTable(nCols : uint, minPadding : uint)
293 m_nCols = nCols;
294 m_minPadding = minPadding;
295 m_rows = new Array();
298 public function addRow(r : Array)
300 if (r.length != m_nCols)
301 throw new Error("Invalid row");
302 m_rows.push(r);
305 private static function padString(s : String, minLength : uint) : String
307 while (s.length < minLength)
308 s += " ";
309 return s;
312 private function paddedRowStrings() : Array
314 var colWidths : Array = new Array(m_nCols);
316 for ( var i : uint = 0; i < m_nCols; ++i) {
317 colWidths[i] = 0;
320 for each ( var r : Array in m_rows ) {
321 for ( var i : uint = 0; i < r.length; ++i )
322 colWidths[i] = Math.max(colWidths[i], r[i].length + m_minPadding);
325 var result : Array = new Array();
326 for each ( var r : Array in m_rows ) {
327 var rowStr : String = "";
328 for ( var i : uint = 0; i < r.length; ++i ) {
329 rowStr += padString(r[i], colWidths[i]);
331 result.push(rowStr);
333 return result;
336 public function toString() : String
338 return paddedRowStrings().join("\n");
341 private var m_nCols : uint;
342 private var m_minPadding : uint;
343 private var m_rows : Array;
346 class TblOutput extends OpCodeOutput
348 public function TblOutput(fileName : String)
350 super(fileName);
353 private static function padOpName(opName : String, minLength : uint) : String
355 while (opName.length < minLength) {
356 opName = opName + " ";
358 return opName;
361 public override function output(opCodes : Array) : void
363 var str : String = this.copyrightCommentForCLikeLanguages;
364 var comment : String = <x><![CDATA[
365 Includers must define an ABC_OP and ABC_UNUSED_OP macros of the following form:
367 #define ABC_OP(opCount, throw, stack, internal, name) ... // defines regular op code
368 #define ABC_UNUSED_OP(opCount, throw, stack, internal, name) ... // defines unused op code
370 Selected arguments can then be used within the macro expansions.
371 - opCount Number of operands. Uses -1 for "invalid", we can avoid that if necessary
372 - throw 1 if the operation can throw, 0 otherwise
373 - stack Stack movement not taking into account run-time names or function arguments
374 - internal 1 if the operation is internal to the VM, 0 otherwise
375 - name Unquoted name of operation.
377 There MUST be exactly 256 entries in this table.
378 The location of an opcode definition in this table determines its hex value, which is
379 what must correspond to what is read out of the ABC file.
380 Entries should never be added or removed from this table. New abc instructions may be added
381 by updating entries for unused op codes. Unused op codes have a "name" that is a hex value.
382 ]]></x>.text()[0];
384 str += wrapInCommentForCLikeLanguages(null, comment, null);
385 str += "//--------------------------------------------------------------------------------------------------------\n";
387 var table : TextTable = new TextTable(7, 2);
388 table.addRow(["//", "opCount", "throw", "stack", "internal", "name", "hex"]);
389 for each (var opCode : OpCode in opCodes) {
390 var abcOP : String = opCode.used ? "ABC_OP(" : "ABC_UNUSED_OP(";
391 var operandCount : String = opCode.operandCount.toString(10) + ",";
392 var throwStr : String = (opCode.canThrow ? "1" : "0") + ",";
393 var stack : String = opCode.stackMovement.toString(10) + ",";
394 var internalOnly : String = (opCode.internalOnly ? "1" : "0") + ",";
395 var name : String = opCode.name + ")";
396 var hex : String = "// 0x" + ((opCode.opCode < 16) ? "0" : "") + opCode.opCode.toString(16).toUpperCase();
397 table.addRow([abcOP, operandCount, throwStr, stack, internalOnly, name, hex]);
400 str += table.toString() + "\n";
401 write(str);
404 public static const ext = "tbl";
407 var outputsArr : Array = [ JavaOutput, AS3Output, TblOutput ];
408 var outputs : Object = {}
409 for each (var output : * in outputsArr)
410 outputs[output.ext] = output;
412 function usage() : void
414 var supportedOutputFileStrings : Array = outputsArr.map(function (output : *) { return "outputfile." + output.ext; });
415 var supportedOutputsStr : String = supportedOutputFileStrings.join(" | ");
416 print("usage: opcodes opcodes.tbl (" + supportedOutputsStr +") [[" + supportedOutputsStr +"] ...]");
419 function main() : void {
420 if (System.argv.length < 1) {
421 print("You need to specify the opcodes.tbl file");
424 if (System.argv.length < 2) {
425 print("You need to specify at least one output file");
426 usage();
427 System.exit(1);
430 var opCodesFileName : String = System.argv[0]
431 if (!File.exists(opCodesFileName)) {
432 print("No such file:" + opCodesFileName);
433 System.exit(1);
436 var opCodesText : String = File.read(opCodesFileName);
438 var opCodes : Array = OpCodes.parse(opCodesText);
439 if (opCodes == null) {
440 print("Unable to parse opcodes table!");
441 System.exit(1);
444 for (var i : Number = 1; i < System.argv.length; ++i) {
445 var outputFileName : String = System.argv[i];
446 var dotIndex : int = outputFileName.lastIndexOf(".");
447 if (dotIndex != -1) {
448 var ext : String = outputFileName.slice(dotIndex + 1).toLowerCase();
449 if (ext in outputs) {
450 var output : * = outputs[ext];
451 var o : OpCodeOutput = new output(outputFileName);
452 o.output(opCodes);
454 else {
455 print("Output type for \"" + outputFileName + "\", " + ext + " is not supported\n");
456 System.exit(1);
463 main();