-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathopcodes.as
More file actions
402 lines (338 loc) · 14 KB
/
Copy pathopcodes.as
File metadata and controls
402 lines (338 loc) · 14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
/* -*- indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Compile command:
// java -jar utils/asc.jar -d -m -i -AS3 -strict -import generated/builtin.abc -import generated/shell_toplevel.abc utils/opcodes.as
package {
import avmplus.System;
import avmplus.File;
final class OpCode
{
public function OpCode(isUsed : Boolean, opCode : uint, operandCount : int, canThrow : Boolean, stackMovement : int, name : String, internalOnly : Boolean)
{
m_isUsed = isUsed;
m_opCode = opCode;
m_operandCount = operandCount;
m_canThrow = canThrow;
m_stackMovement = stackMovement;
m_name = name;
m_internalOnly = internalOnly;
}
public function get used() : Boolean { return m_isUsed; }
public function get opCode() : uint { return m_opCode; }
public function get operandCount() : int { return m_operandCount; }
public function get canThrow() : Boolean { return m_canThrow; }
public function get stackMovement() : int { return m_stackMovement; }
public function get name() : String { return m_name; }
public function get internalOnly() : Boolean { return m_internalOnly; }
private var m_isUsed : Boolean;
private var m_opCode : uint;
private var m_operandCount : int;
private var m_canThrow : Boolean;
private var m_stackMovement : int;
private var m_name : String;
private var m_internalOnly : Boolean;
private static const s_hexRegEx : RegExp = /0x[0-9a-fA-F]{2}/;
}
final class OpCodes
{
public function OpCodes(opCodes : Array)
{
throw new Error("Don't consruct me!!!");
}
public static function parse(opCodesText : String) : Array
{
var abcOpCodeRegEx : RegExp = /^\w*ABC_(?P<u>(UNUSED_)?)OP(?:_F)?\(\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*\)/gm
var opCodeValue : uint = 0;
var match : Object = abcOpCodeRegEx.exec(opCodesText);
var opCodes : Array = new Array(256);
while ((match != null) && (opCodeValue < 256)){
var opCode = new OpCode(match.u.length == 0, opCodeValue, int(match.oc), match.ct == "1", int(match.sm), match.n, match.internal == "1");
opCodes[opCodeValue] = opCode;
++opCodeValue;
match = abcOpCodeRegEx.exec(opCodesText)
}
if (opCodeValue == 256) {
return opCodes;
}
return null;
}
}
class OpCodeOutput
{
public function OpCodeOutput(fileName : String)
{
this.m_fileName = fileName;
}
public function output(opCodes : Array) : void { throw new Error("Call to abstract method!!!"); }
protected function write(s : String) : void
{
File.write(m_fileName, s);
}
private static const copyright : String = <x><![CDATA[
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
]]></x>.text()[0];
protected function wrapInCommentForCLikeLanguages(header : String, body : String, footer : String) : String
{
var lines : Array = body.split("\n");
while (lines[0] == "")
lines.shift();
lines = lines.map(function (line : *) : * { return (line.length > 0 ? " * " : " *") + line; });
return "/*"
+ ((header != null) ? (" ***** " + header + " *****") : "") + "\n"
+ lines.join("\n")
+ "\n" + ((footer != null) ? (" * ***** " + footer + " *****") : "" ) + " */\n\n";
}
protected function get copyrightCommentForCLikeLanguages() : String
{
if (m_copyrightCommentForCLikeLanguages != null)
return m_copyrightCommentForCLikeLanguages;
m_copyrightCommentForCLikeLanguages = wrapInCommentForCLikeLanguages("", copyright, "");
return m_copyrightCommentForCLikeLanguages;
}
protected function get generatedFileCommentForCLikeLanguages() : String
{
if (m_generatedFileCommentForCLikeLanguages != null)
return m_generatedFileCommentForCLikeLanguages;
var slashLine : String = "//////////////////////////////////////////////////////////////////////////////////\n";
var str : String = slashLine;
str += "// GENERATED FILE: DO NOT EDIT!!! See utils/opcodes.as in the tamarin repository.\n"
str += slashLine;
str += "\n";
m_generatedFileCommentForCLikeLanguages = str;
return str;
}
private static var m_copyrightCommentForCLikeLanguages : String = null;
private static var m_generatedFileCommentForCLikeLanguages : String = null;
private var m_fileName : String;
}
class JavaOutput extends OpCodeOutput
{
public function JavaOutput(fileName : String)
{
super(fileName);
}
public override function output(opCodes : Array) : void
{
var str : String = this.copyrightCommentForCLikeLanguages;
str += this.generatedFileCommentForCLikeLanguages;
str += "package adobe.abc;\n\n"
str += "public interface ABCOpCodes {\n"
for each (var opCode : OpCode in opCodes) {
if (opCode.used) {
var opCodeHex : String = opCode.opCode.toString(16);
opCodeHex = opCodeHex.length == 1 ? "0" + opCodeHex : opCodeHex;
str += " public static final int OP_" + opCode.name + " = 0x" + opCodeHex + ";\n";
}
}
str += " public static final int operandCountTable[] = new int [] {\n";
for each (var opCode : OpCode in opCodes) {
str += " " + opCode.operandCount.toString(10) + ",\n" ;
}
str += " };\n"
str += " public static final String opNames[] = new String [] {\n";
for each (var opCode : OpCode in opCodes) {
str += " \"" + opCode.name + "\",\n" ;
}
str += " };\n"
str += "}\n";
write(str);
}
public static const ext = "java";
}
class AS3Output extends OpCodeOutput
{
public function AS3Output(fileName : String)
{
super(fileName);
}
private static function padOpName(opName : String, minLength : uint) : String
{
while (opName.length < minLength) {
opName = opName + " ";
}
return opName;
}
public override function output(opCodes : Array) : void
{
var str : String = this.copyrightCommentForCLikeLanguages;
str += this.generatedFileCommentForCLikeLanguages;
str += "// This file is to be included by its clients.\n\n"
for each (var opCode : OpCode in opCodes) {
if ((opCode.used) && (!opCode.internalOnly)) {
var opCodeHex : String = opCode.opCode.toString(16);
opCodeHex = opCodeHex.length == 1 ? "0" + opCodeHex : opCodeHex;
str += "const OP_" + opCode.name + " : int = 0x" + opCodeHex + ";\n";
}
}
var opNames : Array = new Array(256);
var maxOpNameLen : uint = 0;
for each (var opCode : OpCode in opCodes) {
var opName : String = opCode.used ? opCode.name : "OP_" + opCode.name;
if (opCode.internalOnly) {
opName = "OP_0x" + opCode.opCode.toString(16).toUpperCase();
}
opNames[opCode.opCode] = opName;
maxOpNameLen = Math.max(maxOpNameLen, opName.length);
}
str += "const opNames : Array = [\n";
for each (var opName : String in opNames) {
str += " \"" + padOpName(opName, maxOpNameLen) + "\",\n" ;
}
str += "];\n"
write(str);
}
public static const ext = "as";
}
class TextTable
{
public function TextTable(nCols : uint, minPadding : uint)
{
m_nCols = nCols;
m_minPadding = minPadding;
m_rows = new Array();
}
public function addRow(r : Array)
{
if (r.length != m_nCols)
throw new Error("Invalid row");
m_rows.push(r);
}
private static function padString(s : String, minLength : uint) : String
{
while (s.length < minLength)
s += " ";
return s;
}
private function paddedRowStrings() : Array
{
var colWidths : Array = new Array(m_nCols);
for ( var i : uint = 0; i < m_nCols; ++i) {
colWidths[i] = 0;
}
for each ( var r : Array in m_rows ) {
for ( var i : uint = 0; i < r.length; ++i )
colWidths[i] = Math.max(colWidths[i], r[i].length + m_minPadding);
}
var result : Array = new Array();
for each ( var r : Array in m_rows ) {
var rowStr : String = "";
for ( var i : uint = 0; i < r.length; ++i ) {
rowStr += padString(r[i], colWidths[i]);
}
result.push(rowStr);
}
return result;
}
public function toString() : String
{
return paddedRowStrings().join("\n");
}
private var m_nCols : uint;
private var m_minPadding : uint;
private var m_rows : Array;
}
class TblOutput extends OpCodeOutput
{
public function TblOutput(fileName : String)
{
super(fileName);
}
private static function padOpName(opName : String, minLength : uint) : String
{
while (opName.length < minLength) {
opName = opName + " ";
}
return opName;
}
public override function output(opCodes : Array) : void
{
var str : String = this.copyrightCommentForCLikeLanguages;
var comment : String = <x><![CDATA[
Includers must define an ABC_OP and ABC_UNUSED_OP macros of the following form:
#define ABC_OP(opCount, throw, stack, internal, name) ... // defines regular op code
#define ABC_UNUSED_OP(opCount, throw, stack, internal, name) ... // defines unused op code
Selected arguments can then be used within the macro expansions.
- opCount Number of operands. Uses -1 for "invalid", we can avoid that if necessary
- throw 1 if the operation can throw, 0 otherwise
- stack Stack movement not taking into account run-time names or function arguments
- internal 1 if the operation is internal to the VM, 0 otherwise
- name Unquoted name of operation.
There MUST be exactly 256 entries in this table.
The location of an opcode definition in this table determines its hex value, which is
what must correspond to what is read out of the ABC file.
Entries should never be added or removed from this table. New abc instructions may be added
by updating entries for unused op codes. Unused op codes have a "name" that is a hex value.
]]></x>.text()[0];
str += wrapInCommentForCLikeLanguages(null, comment, null);
str += "//--------------------------------------------------------------------------------------------------------\n";
var table : TextTable = new TextTable(7, 2);
table.addRow(["//", "opCount", "throw", "stack", "internal", "name", "hex"]);
for each (var opCode : OpCode in opCodes) {
var abcOP : String = opCode.used ? "ABC_OP(" : "ABC_UNUSED_OP(";
var operandCount : String = opCode.operandCount.toString(10) + ",";
var throwStr : String = (opCode.canThrow ? "1" : "0") + ",";
var stack : String = opCode.stackMovement.toString(10) + ",";
var internalOnly : String = (opCode.internalOnly ? "1" : "0") + ",";
var name : String = opCode.name + ")";
var hex : String = "// 0x" + ((opCode.opCode < 16) ? "0" : "") + opCode.opCode.toString(16).toUpperCase();
table.addRow([abcOP, operandCount, throwStr, stack, internalOnly, name, hex]);
}
str += table.toString() + "\n";
write(str);
}
public static const ext = "tbl";
}
var outputsArr : Array = [ JavaOutput, AS3Output, TblOutput ];
var outputs : Object = {}
for each (var output : * in outputsArr)
outputs[output.ext] = output;
function usage() : void
{
var supportedOutputFileStrings : Array = outputsArr.map(function (output : *) { return "outputfile." + output.ext; });
var supportedOutputsStr : String = supportedOutputFileStrings.join(" | ");
print("usage: opcodes opcodes.tbl (" + supportedOutputsStr +") [[" + supportedOutputsStr +"] ...]");
}
function main() : void {
if (System.argv.length < 1) {
print("You need to specify the opcodes.tbl file");
}
if (System.argv.length < 2) {
print("You need to specify at least one output file");
usage();
System.exit(1);
}
var opCodesFileName : String = System.argv[0]
if (!File.exists(opCodesFileName)) {
print("No such file:" + opCodesFileName);
System.exit(1);
}
var opCodesText : String = File.read(opCodesFileName);
var opCodes : Array = OpCodes.parse(opCodesText);
if (opCodes == null) {
print("Unable to parse opcodes table!");
System.exit(1);
}
for (var i : Number = 1; i < System.argv.length; ++i) {
var outputFileName : String = System.argv[i];
var dotIndex : int = outputFileName.lastIndexOf(".");
if (dotIndex != -1) {
var ext : String = outputFileName.slice(dotIndex + 1).toLowerCase();
if (ext in outputs) {
var output : * = outputs[ext];
var o : OpCodeOutput = new output(outputFileName);
o.output(opCodes);
}
else {
print("Output type for \"" + outputFileName + "\", " + ext + " is not supported\n");
System.exit(1);
}
}
}
}
main();
}