15 Commits
10 changed files with 243 additions and 263 deletions
+10 -1
View File
@@ -1,9 +1,18 @@
RABCDAsm Changelog
==================
RABCDAsm v1.4 (2011.02.xx)
RABCDAsm v1.5 (2011.04.14)
--------------------------
* Fixed v1.4 constant pool regression
* Added support for memory-access and sign-extend opcodes
* Speed optimizations
* Documentation updates
RABCDAsm v1.4 (2011.03.07)
--------------------------
* Source code ported to D2
* Add support for forward-references for TypeName-kind Multinames
* Correctly order classes by dependencies (extends/implements) and reference
count
+10 -14
View File
@@ -48,27 +48,23 @@ bytecode with the following properties:
Compiling from source
---------------------
RABCDAsm is written in the [D programming language, version 1][d1]. It uses one
third-party library, [std2][] (for some fancy template stuff).
RABCDAsm is written in the [D programming language, version 2][d2].
Assuming you have [dmd][], [git][] and [svn][] installed, compiling should be
as straight-forward as:
Assuming you have [dmd][] and [git][] installed, compiling should be as
straight-forward as:
git clone git://github.com/CyberShadow/RABCDAsm.git
cd RABCDAsm
svn co http://svn.dsource.org/projects/std2/trunk/std2/std2
dmd rabcdasm abcfile asprogram disassembler autodata murmurhash2a
dmd rabcasm abcfile asprogram assembler autodata murmurhash2a
dmd abcexport swffile zlibx
dmd abcreplace swffile zlibx
dmd swfdecompress swffile zlibx
dmd swf7zcompress swffile zlibx
dmd -O -inline rabcdasm abcfile asprogram disassembler autodata murmurhash2a
dmd -O -inline rabcasm abcfile asprogram assembler autodata murmurhash2a
dmd -O -inline abcexport swffile zlibx
dmd -O -inline abcreplace swffile zlibx
dmd -O -inline swfdecompress swffile zlibx
dmd -O -inline swf7zcompress swffile zlibx
[d1]: http://www.digitalmars.com/d/1.0/
[std2]: http://dsource.org/projects/std2
[d2]: http://www.digitalmars.com/d/2.0/
[dmd]: http://www.digitalmars.com/d/download.html
[git]: http://git-scm.com/
[svn]: http://subversion.apache.org/
Pre-compiled binaries
---------------------
+4 -4
View File
@@ -20,7 +20,7 @@ module abcexport;
import std.file;
import std.path;
import std.string;
import std.conv;
import std.stdio;
import swffile;
@@ -45,11 +45,11 @@ void main(string[] args)
while (*p++) {} // skip name
abc = tag.data[p-tag.data.ptr..$];
}
write(getName(arg) ~ .toString(count++) ~ ".abc", abc);
std.file.write(getName(arg) ~ to!string(count++) ~ ".abc", abc);
}
if (count == 0)
throw new Exception("No DoABC tags found");
}
catch (Object o)
writefln("Error while processing %s: %s", arg, o);
catch (Exception e)
writefln("Error while processing %s: %s", arg, e);
}
+27 -24
View File
@@ -19,6 +19,7 @@
module abcfile;
import std.string : format; // exception formatting
import std.exception;
/**
* Implements a shallow representation of an .abc file.
@@ -181,7 +182,7 @@ class ABCFile
// TraitAttributes bitmask
ubyte attr() { return cast(ubyte)(kindAttr >> 4); }
void attr(ubyte value) { kindAttr = (kindAttr&0xF) | (value<<4); }
void attr(ubyte value) { kindAttr = cast(ubyte)((kindAttr&0xF) | (value<<4)); }
}
struct Class
@@ -708,16 +709,16 @@ const OpcodeInfo[256] opcodeInfo = [
/* 0x32 */ {"hasnext2", [OpcodeArgumentType.UIntLiteral, OpcodeArgumentType.UIntLiteral]},
/* 0x33 */ {"pushdecimal", [OpcodeArgumentType.Unknown]},
/* 0x34 */ {"pushdnan", [OpcodeArgumentType.Unknown]},
/* 0x35 */ {"li8", [OpcodeArgumentType.Unknown]},
/* 0x36 */ {"li16", [OpcodeArgumentType.Unknown]},
/* 0x37 */ {"li32", [OpcodeArgumentType.Unknown]},
/* 0x38 */ {"lf32", [OpcodeArgumentType.Unknown]},
/* 0x39 */ {"lf64", [OpcodeArgumentType.Unknown]},
/* 0x3A */ {"si8", [OpcodeArgumentType.Unknown]},
/* 0x3B */ {"si16", [OpcodeArgumentType.Unknown]},
/* 0x3C */ {"si32", [OpcodeArgumentType.Unknown]},
/* 0x3D */ {"sf32", [OpcodeArgumentType.Unknown]},
/* 0x3E */ {"sf64", [OpcodeArgumentType.Unknown]},
/* 0x35 */ {"li8", []},
/* 0x36 */ {"li16", []},
/* 0x37 */ {"li32", []},
/* 0x38 */ {"lf32", []},
/* 0x39 */ {"lf64", []},
/* 0x3A */ {"si8", []},
/* 0x3B */ {"si16", []},
/* 0x3C */ {"si32", []},
/* 0x3D */ {"sf32", []},
/* 0x3E */ {"sf64", []},
/* 0x3F */ {"0x3F", [OpcodeArgumentType.Unknown]},
/* 0x40 */ {"newfunction", [OpcodeArgumentType.Method]},
/* 0x41 */ {"call", [OpcodeArgumentType.UIntLiteral]},
@@ -735,9 +736,9 @@ const OpcodeInfo[256] opcodeInfo = [
/* 0x4D */ {"callinterface", [OpcodeArgumentType.Unknown]},
/* 0x4E */ {"callsupervoid", [OpcodeArgumentType.Multiname, OpcodeArgumentType.UIntLiteral]},
/* 0x4F */ {"callpropvoid", [OpcodeArgumentType.Multiname, OpcodeArgumentType.UIntLiteral]},
/* 0x50 */ {"sxi1", [OpcodeArgumentType.Unknown]},
/* 0x51 */ {"sxi8", [OpcodeArgumentType.Unknown]},
/* 0x52 */ {"sxi16", [OpcodeArgumentType.Unknown]},
/* 0x50 */ {"sxi1", []},
/* 0x51 */ {"sxi8", []},
/* 0x52 */ {"sxi16", []},
/* 0x53 */ {"applytype", [OpcodeArgumentType.UIntLiteral]},
/* 0x54 */ {"0x54", [OpcodeArgumentType.Unknown]},
/* 0x55 */ {"newobject", [OpcodeArgumentType.UIntLiteral]},
@@ -992,13 +993,13 @@ private final class ABCReader
foreach (ref value; abc.bodies)
value = readMethodBody();
}
catch (Object o)
throw new Exception(format("Error at %d (0x%X): %s", pos, pos, o));
catch (Exception e)
throw new Exception(format("Error at %d (0x%X):", pos, pos), e);
}
ubyte readU8()
{
assert(pos < buf.length);
enforce(pos < buf.length, "End of file reached");
return buf[pos++];
}
@@ -1046,7 +1047,7 @@ private final class ABCReader
void readExact(void* ptr, size_t len)
{
assert(pos+len <= buf.length);
enforce(pos+len <= buf.length, "End of file reached");
(cast(ubyte*)ptr)[0..len] = buf[pos..pos+len];
pos += len;
}
@@ -1061,8 +1062,9 @@ private final class ABCReader
string readString()
{
string s = new char[readU30()];
readExact(s.ptr, s.length);
char[] buf = new char[readU30()];
readExact(buf.ptr, buf.length);
string s = assumeUnique(buf);
if (s.length == 0)
s = ""; // not null!
return s;
@@ -1471,7 +1473,7 @@ private final class ABCWriter
foreach (ref value; abc.instances)
writeInstance(value);
assert(abc.classes.length == abc.instances.length);
assert(abc.classes.length == abc.instances.length, "Number of classes and instances differs");
foreach (ref value; abc.classes)
writeClass(value);
@@ -1551,7 +1553,7 @@ private final class ABCWriter
writeU32(v);
}
void writeExact(void* ptr, size_t len)
void writeExact(const(void)* ptr, size_t len)
{
while (pos+len > buf.length)
buf.length = buf.length * 2;
@@ -1643,7 +1645,7 @@ private final class ABCWriter
}
if (v.flags & MethodFlags.HAS_PARAM_NAMES)
{
assert(v.paramNames.length == v.paramTypes.length);
assert(v.paramNames.length == v.paramTypes.length, "Mismatching number of parameter names and types");
foreach (value; v.paramNames)
writeU30(value);
}
@@ -1753,7 +1755,8 @@ private final class ABCWriter
// we don't know the length before writing all the instructions - swap buffer with a temporary one
auto globalBuf = buf;
auto globalPos = pos;
buf = new ubyte[1024];
static ubyte[1024*16] methodBuf;
buf = methodBuf[];
pos = 0;
struct Fixup { ABCFile.Label target; uint pos, base; }
+1 -1
View File
@@ -27,7 +27,7 @@ void main(string[] args)
if (args.length != 4)
throw new Exception("Bad arguments. Usage: abcreplace file.swf index code.abc");
auto swf = SWFFile.read(cast(ubyte[])read(args[1]));
auto index = toUint(args[2]);
auto index = to!uint(args[2]);
uint count;
foreach (ref tag; swf.tags)
if ((tag.type == TagType.DoABC || tag.type == TagType.DoABC2) && count++ == index)
+55 -77
View File
@@ -18,6 +18,8 @@
module asprogram;
import std.algorithm;
import core.stdc.string;
import abcfile;
import autodata;
@@ -41,16 +43,7 @@ final class ASProgram
uint privateIndex; // unique index for private namespaces
mixin AutoCompare;
//mixin ProcessAllData;
R processData(R, string prolog, string epilog, H)(ref H handler)
{
mixin(prolog);
mixin(addAutoField("kind"));
mixin(addAutoField("name"));
mixin(addAutoField("privateIndex"));
mixin(epilog);
}
mixin ProcessAllData;
}
static class Multiname
@@ -89,7 +82,7 @@ final class ASProgram
mixin AutoCompare;
mixin AutoToString;
R processData(R, string prolog, string epilog, H)(ref H handler)
R processData(R, string prolog, string epilog, H)(ref H handler) const
{
mixin(prolog);
mixin(addAutoField("kind"));
@@ -244,7 +237,7 @@ final class ASProgram
Instance instance;
string toString()
override string toString()
{
return instance.name.toString();
}
@@ -732,9 +725,24 @@ private final class AStoABC
return value == T.init;
}
static void move(T)(T[] array, size_t from, size_t to)
{
assert(from<array.length && to<array.length);
if (from == to)
return;
T t = array[from];
if (from < to)
memmove(array.ptr+from, array.ptr+from+1, (to-from)*T.sizeof);
else
memmove(array.ptr+to+1, array.ptr+to, (from-to)*T.sizeof);
array[to] = t;
}
/// Maintain an unordered set of values; sort/index by usage count
struct ConstantPool(T, bool haveNull = true)
{
alias immutable(T) I;
struct Entry
{
uint hits;
@@ -743,7 +751,7 @@ private final class AStoABC
mixin AutoCompare;
R processData(R, string prolog, string epilog, H)(ref H handler)
R processData(R, string prolog, string epilog, H)(ref H handler) const
{
mixin(prolog);
mixin(addAutoField("hits", true));
@@ -752,17 +760,18 @@ private final class AStoABC
}
}
Entry[T] pool;
Entry[immutable(T)] pool;
T[] values;
bool add(T value) // return true if added
{
enum ivalue = cast(I)value;
if (haveNull && isNull(value))
return false;
auto cp = value in pool;
auto cp = ivalue in pool;
if (cp is null)
{
pool[value] = Entry(1, value);
pool[ivalue] = Entry(1, value);
return true;
}
else
@@ -774,7 +783,8 @@ private final class AStoABC
bool notAdded(T value)
{
auto ep = value in pool;
enum ivalue = cast(I)value;
auto ep = ivalue in pool;
if (ep)
ep.hits++;
return !((haveNull && isNull(value)) || ep);
@@ -788,16 +798,17 @@ private final class AStoABC
values.length = all.length + NullOffset;
foreach (i, ref c; all)
{
pool[c.value].index = i + NullOffset;
pool[cast(I)c.value].index = i + NullOffset;
values[i + NullOffset] = c.value;
}
}
uint get(T value)
{
enum ivalue = cast(I)value;
if (haveNull && isNull(value))
return 0;
return pool[value].index;
return pool[ivalue].index;
}
}
@@ -811,17 +822,8 @@ private final class AStoABC
uint addIndex, index;
void*[] parents;
int opCmp(Entry* o)
{
if (this.parents.contains(o.object))
return 1;
if (o.parents.contains(this.object))
return -1;
if (o.hits==hits)
return addIndex-o.addIndex;
else
return o.hits-hits;
}
mixin AutoToString;
mixin ProcessAllData;
}
Entry[void*] pool;
@@ -871,61 +873,37 @@ private final class AStoABC
void finalize()
{
// assign unique index
// create array
auto all = new Entry*[pool.length];
int i=0;
foreach (ref e; pool)
e.index = i++;
// topographical sort
bool done;
while (!done)
{
done = true;
foreach (ref a; pool)
foreach (parent; a.parents)
{
auto pb = parent in pool;
assert(pb !is null, "Can't find referenced object");
if (pb.index > a.index)
{
auto t = pb.index;
pb.index = a.index;
a.index = t;
done = false;
break;
}
}
}
// copy to array
auto all = new Entry[i];
foreach (ref e; pool)
all[e.index] = e;
all[i++] = &e;
// sort
//all.sort; // sort preserving topological integrity demands compared items to always be adjacent
done = false;
while (!done)
{
done = true;
sort!q{a.hits > b.hits || (a.hits == b.hits && a.addIndex < b.addIndex)}(all);
for (int j=0; j<all.length-1; j++)
if (all[j] > &all[j+1])
// topographical sort
topSort:
// update indices
foreach (j, e; all)
e.index = j;
foreach (ref a; pool)
foreach (parent; a.parents)
{
auto pb = parent in pool;
assert(pb !is null, "Can't find referenced object");
if (pb.index > a.index)
{
auto t = all[j];
all[j] = all[j+1];
all[j+1] = t;
done = false;
move(all, pb.index, a.index);
goto topSort;
}
}
}
objects.length = i;
foreach (j, ref e; all)
{
pool[e.object].index = j;
foreach (j, e; all)
objects[j] = cast(T)e.object;
}
}
uint get(T obj)
@@ -996,7 +974,7 @@ private final class AStoABC
throw new .Exception("Unknown Multiname kind");
}
bool r = multinames.add(multiname);
assert(r);
assert(r, "Recursive multiname reference");
}
}
@@ -1095,7 +1073,7 @@ private final class AStoABC
visitInstance(vclass.instance);
bool r = classes.add(vclass);
assert(r);
assert(r, "Recursive class reference");
}
}
+26 -40
View File
@@ -22,6 +22,7 @@ import std.file;
import std.string;
import std.conv;
import std.path;
import std.exception;
import abcfile;
import asprogram;
@@ -44,8 +45,8 @@ final class Assembler
{
string filename;
string buf;
char* pos;
char* end;
immutable(char)* pos;
immutable(char)* end;
string[] arguments;
string basePath;
@@ -61,7 +62,7 @@ final class Assembler
static File fromData(string name, string data, string[] arguments = null, string basePath = null)
{
data ~= \0; data = data[0..$-1]; // hack to prevent readWord etc. from checking for end-of-file on every character
data ~= "\0"; data = data[0..$-1]; // hack to prevent readWord etc. from checking for end-of-file on every character
return File(name, data, data.ptr, data.ptr + data.length, arguments, basePath);
}
@@ -98,11 +99,11 @@ final class Assembler
{
if (filename.length == 0)
throw new Exception("Empty filename");
filename = filename.dup;
foreach (ref c; filename)
auto buf = filename.dup;
foreach (ref c; buf)
if (c == '\\')
c = '/';
return std.path.join(getBasePath, filename);
return std.path.join(getBasePath, assumeUnique(buf));
}
void skipWhitespace()
@@ -190,7 +191,7 @@ final class Assembler
foreach (ref file; files[0..fileCount])
if (file.arguments.length)
{
uint index = .toUint(name)-1;
uint index = .to!uint(name)-1;
if (index >= file.arguments.length)
throw new Exception("Argument index out-of-bounds");
string value = file.arguments[index];
@@ -211,7 +212,7 @@ final class Assembler
static bool isWordChar(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.'; // TODO: use lookup table?
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.';
}
string readWord()
@@ -254,7 +255,7 @@ final class Assembler
}
}
void pushFile(ref File file)
void pushFile(File file)
{
if (fileCount == files.length)
throw new Exception("Recursion limit exceeded");
@@ -264,7 +265,7 @@ final class Assembler
}
/// For restoring the position of an error
void setFile(ref File file)
void setFile(File file)
{
files[0] = file;
fileCount = -1;
@@ -357,7 +358,7 @@ final class Assembler
static const char[16] hexDigits = "0123456789ABCDEF";
// TODO: optimize
string s = \";
string s = "\"";
foreach (c; str)
if (c == 0x0A)
s ~= `\n`;
@@ -422,7 +423,7 @@ final class Assembler
return v;
}
ubyte readFlag(string[] names)
ubyte readFlag(const string[] names)
{
auto word = readWord();
ubyte f = 1;
@@ -490,7 +491,7 @@ final class Assembler
string w = readWord();
if (w == "null")
return ABCFile.NULL_INT;
return toInt(w);
return to!int(w);
}
ulong readUInt()
@@ -498,7 +499,7 @@ final class Assembler
string w = readWord();
if (w == "null")
return ABCFile.NULL_UINT;
return toUint(w);
return to!uint(w);
}
double readDouble()
@@ -506,7 +507,7 @@ final class Assembler
string w = readWord();
if (w == "null")
return ABCFile.NULL_DOUBLE;
return toDouble(w);
return to!double(w);
}
string readString()
@@ -967,7 +968,7 @@ final class Assembler
if (c=='-' || c=='+')
{
name = label[0..i];
offset = .toInt(label[i..$]);
offset = to!int(label[i..$]);
break;
}
auto lp = name in labels;
@@ -1073,24 +1074,14 @@ final class Assembler
foreach (ref f; jumpFixups)
{
try
instructions[f.ii].arguments[f.ai].jumpTarget = parseLabel(f.name, labels);
catch (Object o)
{
setFile(f.where.load);
throw o;
}
scope(failure) setFile(f.where.load);
instructions[f.ii].arguments[f.ai].jumpTarget = parseLabel(f.name, labels);
}
foreach (ref f; switchFixups)
{
try
instructions[f.ii].arguments[f.ai].switchTargets[f.si] = parseLabel(f.name, labels);
catch (Object o)
{
setFile(f.where.load);
throw o;
}
scope(failure) setFile(f.where.load);
instructions[f.ii].arguments[f.ai].switchTargets[f.si] = parseLabel(f.name, labels);
}
foreach (ref f; localClassFixups)
@@ -1107,13 +1098,8 @@ final class Assembler
ABCFile.Label readLabel()
{
auto word = readWord();
try
return parseLabel(word, labels);
catch (Object o)
{
backpedal(word.length);
throw o;
}
scope(failure) backpedal(word.length);
return parseLabel(word, labels);
}
ASProgram.Exception e;
@@ -1213,15 +1199,15 @@ final class Assembler
*f.ptr = *mp;
}
}
catch (Object o)
catch (Exception e)
{
string s = files[0].positionStr ~ ": " ~ o.toString();
string s = files[0].positionStr ~ ": ";
if (fileCount == -1)
s ~= "\n\t(inclusion context unavailable)";
else
foreach (ref f; files[1..fileCount])
s ~= "\n\t(included from " ~ f.positionStr ~ ")";
throw new Exception(s);
throw new Exception(s, e);
}
classFixups = null;
+84 -79
View File
@@ -19,61 +19,67 @@
module autodata;
import murmurhash2a;
import std2.traits;
import std.traits;
string addAutoField(string name, bool reverseSort = false)
{
//return `mixin(handler.process!(typeof(` ~ name ~ `), "` ~ name ~ `")());`; // doesn't work due to DMD bug 3959
return `{ static const _AutoDataStr = handler.process!(typeof(this.` ~ name ~ `), "` ~ name ~ `", ` ~ (reverseSort ? "true" : "false") ~`)(); mixin(_AutoDataStr); }`;
return `mixin(typeof(handler).getMixin!(typeof(` ~ name ~ `), "` ~ name ~ `", ` ~ (reverseSort ? "true" : "false") ~`));`;
}
template AutoCompare()
{
hash_t toHash()
static if (is(typeof(this)==class))
{
alias typeof(this) _AutoDataTypeReference;
alias Object _AutoDataOtherTypeReference;
override hash_t toHash() const { return _AutoDataHash(); }
override bool opEquals(Object o) const { return _AutoDataEquals(o); }
override int opCmp(Object o) const { return _AutoDataCmp(o); }
}
else // struct
{
alias const(typeof(this)*) _AutoDataTypeReference;
alias const(typeof(this)*) _AutoDataOtherTypeReference;
hash_t toHash() const { return _AutoDataHash(); }
bool opEquals(ref const typeof(this) s) const { return _AutoDataEquals(&s); }
int opCmp(ref const typeof(this) s) const { return _AutoDataCmp(&s); }
}
private hash_t _AutoDataHash() const
{
HashDataHandler handler;
handler.hasher.Begin();
processData!(void, "", "")(handler);
processData!(void, q{}, q{})(handler);
return handler.hasher.End();
}
static if (is(typeof(this)==class))
alias Object _AutoDataOtherType;
else
alias typeof(this) _AutoDataOtherType;
int opEquals(_AutoDataOtherType other)
private bool _AutoDataEquals(_AutoDataOtherTypeReference other) const
{
EqualsDataHandler!(typeof(this)) handler;
static if (is(typeof(this)==class))
{
handler.other = cast(typeof(this)) other;
if (handler.other is null)
return false;
}
else
handler.other = other;
return processData!(bool, "auto _AutoDataOther = handler.other;", "return true;")(handler);
auto handler = EqualsDataHandler!_AutoDataTypeReference(cast(_AutoDataTypeReference) other);
if (handler.other is null)
return false;
return processData!(bool, q{auto _AutoDataOther = handler.other;}, q{return true;})(handler);
}
int opCmp(_AutoDataOtherType other)
private int _AutoDataCmp(_AutoDataOtherTypeReference other) const
{
CmpDataHandler!(typeof(this)) handler;
static if (is(typeof(this)==class))
{
handler.other = cast(typeof(this)) other;
if (handler.other is null)
return -1;
}
else
handler.other = other;
return processData!(int, "auto _AutoDataOther = handler.other;", "return 0;")(handler);
auto handler = CmpDataHandler!_AutoDataTypeReference(cast(_AutoDataTypeReference) other);
if (handler.other is null)
return false;
return processData!(int, q{auto _AutoDataOther = handler.other;}, "return 0;")(handler);
}
}
template AutoToString()
{
string toString()
static if (is(typeof(this)==class))
override string toString() { return _AutoDataToString(); }
else // struct
string toString() const { return _AutoDataToString(); }
string _AutoDataToString() const
{
ToStringDataHandler handler;
return processData!(string, "string _AutoDataResult;", "return _AutoDataResult;")(handler);
@@ -82,20 +88,11 @@ template AutoToString()
template ProcessAllData()
{
R processData(R, string prolog, string epilog, H)(ref H handler)
R processData(R, string prolog, string epilog, H)(ref H handler) const
{
mixin(prolog);
foreach (i, T; this.tupleof)
{
//mixin(addAutoField(T.stringof)); // doesn't work
static if (this.tupleof[i].stringof == typeof(this.tupleof[i]).stringof)
static assert(0, "DMD bug 2881 detected - can't use enums with ProcessAllData");
else
static if (is (typeof(this) == class))
mixin(addAutoField(this.tupleof[i].stringof[5..$])); // remove "this."
else
mixin(addAutoField(this.tupleof[i].stringof[8..$])); // remove "(*this)."
}
mixin(addAutoField(this.tupleof[i].stringof[5..$])); // remove "this."
mixin(epilog);
}
}
@@ -103,29 +100,27 @@ template ProcessAllData()
/// For data handlers that only need to look at the raw data (currently only HashDataHandler)
template RawDataHandlerWrapper()
{
static string process(T, string name, bool reverseSort)()
template getMixin(T, string name, bool reverseSort)
{
return processRecursive!(T, "this." ~ name, "");
enum getMixin = getMixinRecursive!(T, "this." ~ name, "");
}
static string processRecursive(T, string name, string loopDepth)()
template getMixinRecursive(T, string name, string loopDepth)
{
static if (!hasAliasing!(T))
return processRaw("&" ~ name, name ~ ".sizeof");
else
static if (is(T U : U[]))
{
string s = "{ bool _AutoDataNullTest = " ~ name ~ " is null; " ~ processRaw("&_AutoDataNullTest", "bool.sizeof") ~ "}";
static if (!hasAliasing!(U))
s ~= processRaw(name ~ ".ptr", name ~ ".length");
else
s ~= "foreach (ref _AutoDataArrayItem" ~ loopDepth ~ "; " ~ name ~ ") {" ~ processRecursive!(U, "_AutoDataArrayItem" ~ loopDepth, loopDepth~"Item")() ~ "}";
return s;
}
enum getMixinRecursive =
"{ bool _AutoDataNullTest = " ~ name ~ " is null; " ~ getRawMixin!("&_AutoDataNullTest", "bool.sizeof") ~ "}" ~
(!hasAliasing!(U) ?
getRawMixin!(name ~ ".ptr", name ~ ".length")
:
"foreach (ref _AutoDataArrayItem" ~ loopDepth ~ "; " ~ name ~ ") {" ~ getMixinRecursive!(U, "_AutoDataArrayItem" ~ loopDepth, loopDepth~"Item") ~ "}"
);
else
static if (!hasAliasing!(T))
enum getMixinRecursive = getRawMixin!("&" ~ name, name ~ ".sizeof");
else
static if (is(typeof((new T).toHash())))
//static assert(0, "aoeu: " ~ T.stringof);
return name ~ ".processData!(void, ``, ``)(handler);";
enum getMixinRecursive = name ~ ".processData!(void, ``, ``)(handler);";
else
static assert(0, "Don't know how to process type: " ~ T.stringof);
}
@@ -137,9 +132,9 @@ struct HashDataHandler
MurmurHash2A hasher;
static string processRaw(string ptr, string len)
template getRawMixin(string ptr, string len)
{
return "handler.hasher.Add(" ~ ptr ~ ", " ~ len ~ ");";
enum getRawMixin = "handler.hasher.Add(" ~ ptr ~ ", " ~ len ~ ");";
}
}
@@ -147,13 +142,17 @@ struct EqualsDataHandler(O)
{
O other;
static string process(T, string name, bool reverseSort)()
template nullCheck(T, string name)
{
string s;
static if (is(T U : U[]))
s ~= " if ((this." ~ name ~ " is null) != (_AutoDataOther." ~ name ~ " is null)) return false;";
s ~= "if (this." ~ name ~ " != _AutoDataOther." ~ name ~ ") return false;";
return s;
enum nullCheck = "if ((this." ~ name ~ " is null) != (_AutoDataOther." ~ name ~ " is null)) return false;";
else
enum nullCheck = "";
}
template getMixin(T, string name, bool reverseSort)
{
enum getMixin = nullCheck!(T, name) ~ "if (this." ~ name ~ " != _AutoDataOther." ~ name ~ ") return false;";
}
}
@@ -161,32 +160,38 @@ struct CmpDataHandler(O)
{
O other;
static string process(T, string name, bool reverseSort)()
template getMixin(T, string name, bool reverseSort)
{
string reverseStr = reverseSort ? "-" : "";
string s;
enum getMixin = getMixinComposite!(T, name, reverseSort).code;
}
template getMixinComposite(T, string name, bool reverseSort)
{
enum reverseStr = reverseSort ? "-" : "";
static if (is(T U : U[]))
s ~= "{ int _AutoDataCmp = cast(int)(this." ~ name ~ " !is null) - cast(int)(_AutoDataOther." ~ name ~ " !is null); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
enum arrCode = "{ int _AutoDataCmp = cast(int)(this." ~ name ~ " !is null) - cast(int)(_AutoDataOther." ~ name ~ " !is null); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
else
enum arrCode = "";
static if (is(T == string) && is(std.string.cmp))
s ~= "{ int _AutoDataCmp = std.string.cmp(this." ~ name ~ ", _AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
enum dataCode = "{ int _AutoDataCmp = std.string.cmp(this." ~ name ~ ", _AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
else
static if (is(T == int))
s ~= "{ int _AutoDataCmp = this." ~ name ~ " - _AutoDataOther." ~ name ~ "; if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }"; // TODO: use long?
enum dataCode = "{ int _AutoDataCmp = this." ~ name ~ " - _AutoDataOther." ~ name ~ "; if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }"; // TODO: use long?
else
static if (is(typeof(T.opCmp)))
s ~= "{ int _AutoDataCmp = this." ~ name ~ ".opCmp(_AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
enum dataCode = "{ int _AutoDataCmp = this." ~ name ~ ".opCmp(_AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
else
s ~= "if (this." ~ name ~ " < _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "(-1);" ~
"if (this." ~ name ~ " > _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "( 1);";
return s;
enum dataCode = "if (this." ~ name ~ " < _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "(-1);" ~
"if (this." ~ name ~ " > _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "( 1);";
enum code = arrCode ~ dataCode;
}
}
struct ToStringDataHandler
{
static string process(T, string name, bool reverseSort)()
template getMixin(T, string name, bool reverseSort)
{
return "_AutoDataResult ~= format(`%s = %s `, `" ~ name ~ "`, this." ~ name ~ ");";
enum getMixin = "_AutoDataResult ~= format(`%s = %s `, `" ~ name ~ "`, this." ~ name ~ ");";
}
}
+25 -22
View File
@@ -20,12 +20,14 @@ module disassembler;
import std.file;
import std.string;
import std.conv;
import std.exception;
import abcfile;
import asprogram;
final class StringBuilder
{
string buf;
char[] buf;
size_t pos;
string filename;
@@ -108,7 +110,7 @@ final class RefBuilder : ASTraitsVisitor
override void run()
{
foreach (i, ref v; as.scripts)
addMethod(v.sinit, "script" ~ .toString(i) ~ "_sinit");
addMethod(v.sinit, "script" ~ to!string(i) ~ "_sinit");
foreach (vclass; as.orphanClasses)
addClass(vclass, "orphan");
foreach (method; as.orphanMethods)
@@ -157,7 +159,7 @@ final class RefBuilder : ASTraitsVisitor
int n = 0;
uint* pindex;
while ((pindex = name in privateNamespaceByName) !is null && *pindex != index)
name = bname ~ .toString(++n);
name = bname ~ to!string(++n);
}
auto pname = index in privateNamespaceNames;
if (pname)
@@ -242,11 +244,11 @@ final class RefBuilder : ASTraitsVisitor
strings[i] = qNameToString(m);
if (field)
strings[$-1] = field;
string s = join(strings, "/");
char[] s = join(strings, "/").dup;
foreach (ref c; s)
if (c < 0x20 || c == '"')
c = '_';
return s;
return assumeUnique(s);
}
string addObject(T)(T obj, ref T[string] objByName, string field)
@@ -255,7 +257,7 @@ final class RefBuilder : ASTraitsVisitor
auto uniqueName = name;
int i = 1;
while (uniqueName in objByName)
uniqueName = name ~ "_" ~ .toString(++i);
uniqueName = name ~ "_" ~ to!string(++i);
objByName[uniqueName] = obj;
objName[cast(void*)obj] = uniqueName;
return uniqueName;
@@ -300,7 +302,7 @@ final class RefBuilder : ASTraitsVisitor
if (pname)
return *pname;
else
//throw new Exception("Nameless private namespace: " ~ .toString(index));
//throw new Exception("Nameless private namespace: " ~ to!string(index));
return addPrivateNamespace(index, "OrphanPrivateNamespace");
}
}
@@ -335,10 +337,10 @@ final class Disassembler
sb.indent++; sb.newLine();
sb ~= "minorversion ";
sb ~= .toString(as.minorVersion);
sb ~= to!string(as.minorVersion);
sb.newLine();
sb ~= "majorversion ";
sb ~= .toString(as.majorVersion);
sb ~= to!string(as.majorVersion);
sb.newLine();
sb.newLine();
@@ -388,7 +390,7 @@ final class Disassembler
uint[] indices = refs.privateNamespaceNames.keys.sort;
foreach (index; indices)
{
sb ~= "#privatens " ~ .toString(index) ~ " ";
sb ~= "#privatens " ~ to!string(index) ~ " ";
dumpString(sb, refs.privateNamespaceNames[index]);
sb.newLine();
}
@@ -400,7 +402,7 @@ final class Disassembler
if (v == ABCFile.NULL_INT)
sb ~= "null";
else
sb ~= .toString(v);
sb ~= to!string(v);
}
void dumpUInt(StringBuilder sb, ulong v)
@@ -408,7 +410,7 @@ final class Disassembler
if (v == ABCFile.NULL_UINT)
sb ~= "null";
else
sb ~= .toString(v);
sb ~= to!string(v);
}
void dumpDouble(StringBuilder sb, double v)
@@ -642,7 +644,7 @@ final class Disassembler
sb.indent--; sb ~= "end ; metadata"; sb.newLine();
}
void dumpFlags(bool oneLine = false)(StringBuilder sb, ubyte flags, string[] names)
void dumpFlags(bool oneLine = false)(StringBuilder sb, ubyte flags, const string[] names)
{
for (int i=0; flags; i++, flags>>=1)
if (flags & 1)
@@ -747,13 +749,14 @@ final class Disassembler
string toFileName(string refid)
{
string filename = refid.dup;
foreach (ref c; filename)
char[] buf = refid.dup;
foreach (ref c; buf)
if (c == '.' || c == ':')
c = '/';
else
if (c == '\\' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' || c == '|')
c = '_';
string filename = assumeUnique(buf);
version (Windows)
{
@@ -835,7 +838,7 @@ final class Disassembler
void dumpScript(StringBuilder sb, ASProgram.Script script, uint index)
{
sb ~= "script ; ";
sb ~= .toString(index);
sb ~= to!string(index);
sb.indent++; sb.newLine();
sb ~= "sinit"; dumpMethod(sb, script.sinit);
dumpTraits(sb, script.traits);
@@ -853,12 +856,12 @@ final class Disassembler
void dumpLabel(StringBuilder sb, ref ABCFile.Label label)
{
sb ~= 'L';
sb ~= .toString(label.index);
sb ~= to!string(label.index);
if (label.offset != 0)
{
if (label.offset > 0)
sb ~= '+';
sb ~= .toString(label.offset);
sb ~= to!string(label.offset);
}
}
@@ -925,7 +928,7 @@ final class Disassembler
{
sb.noIndent();
sb ~= 'L';
sb ~= .toString(ii);
sb ~= to!string(ii);
sb ~= ':';
sb.newLine();
}
@@ -953,13 +956,13 @@ final class Disassembler
throw new Exception("Don't know how to disassemble OP_" ~ opcodeInfo[instruction.opcode].name);
case OpcodeArgumentType.UByteLiteral:
sb ~= .toString(instruction.arguments[i].ubytev);
sb ~= to!string(instruction.arguments[i].ubytev);
break;
case OpcodeArgumentType.IntLiteral:
sb ~= .toString(instruction.arguments[i].intv);
sb ~= to!string(instruction.arguments[i].intv);
break;
case OpcodeArgumentType.UIntLiteral:
sb ~= .toString(instruction.arguments[i].uintv);
sb ~= to!string(instruction.arguments[i].uintv);
break;
case OpcodeArgumentType.Int:
+1 -1
View File
@@ -31,7 +31,7 @@ public:
m_size = 0;
}
void Add ( void * vdata, int len )
void Add ( const(void) * vdata, int len )
{
ubyte * data = cast(ubyte*)vdata;
m_size += len;