mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 12:34:35 +03:00
Changed asmjit namespaces, each architecture has now only one namespace for registers / memory operands.
Changed instruction table schema to minimize its size and added use of EFLAGS register (for scheduler). Changed the rest of intrinsics accepting `void*` to accept `Ptr` instead. Changed clear()/reset() concept - only `reset()` now exists and accepts a `releaseMemory` argument. Changed unit tests to use bundled `Broken` framework. Moved podvector and podlist to base/containers. Added CMPS, LODS, MOVS, SCAS, STOS instructions. Added Label::isInitialized() and Var::isInitialized(). Added X86Scheduler stub - preparing for instruction reordering. Added support for tracing (see ASMJIT_TRACE) to allow consumers to find bugs in AsmJit quicker. Fixed possible Zone memory leak. Fixed and improved alloc/spill (added support for home register which asmjit honors from now). Fixed Assembler `LEA REG, [LABEL]` bug. Fixed [Mem, Imm] instructions with zero-sized operand to return error instead of emitting garbage. Fixed minor bug in VMemMgr - always point to a correct hProcess so it can be used properly (#41).
This commit is contained in:
@@ -1,33 +1,31 @@
|
||||
// [GenDefs]
|
||||
//
|
||||
// The purpose of this script is to fetch all instructions' names into a single
|
||||
// string. It prevents relocation that has to be done by linked to make all
|
||||
// pointers the binary application/library uses valid. This approach decreases
|
||||
// the final size of AsmJit binary.
|
||||
// string and to optimize common patterns that appear in instruction data. It
|
||||
// prevents relocation of small strings (instruction names) that has to be done
|
||||
// by a linker to make all pointers the binary application/library uses valid.
|
||||
// This approach decreases the final size of AsmJit binary and relocation data.
|
||||
|
||||
var fs = require("fs");
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// [Configuration]
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
var injectStartMarker = "// ${kInstData:Begin}\n";
|
||||
var injectEndMarker = "// ${kInstData:End}\n";
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// [Utilities]
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
var uppercaseFirst = function(s) {
|
||||
var upFirst = function(s) {
|
||||
if (!s)
|
||||
return s;
|
||||
return s[0].toUpperCase() + s.substr(1);
|
||||
};
|
||||
|
||||
var trimLeft = function(s) {
|
||||
return s.replace(/^\s+/, "");
|
||||
}
|
||||
|
||||
var inject = function(s, start, end, code) {
|
||||
var iStart = s.indexOf(start);
|
||||
var iEnd = s.indexOf(end);
|
||||
|
||||
|
||||
if (iStart === -1)
|
||||
throw new Error("Couldn't locate start mark.");
|
||||
|
||||
@@ -41,9 +39,8 @@ var inject = function(s, start, end, code) {
|
||||
// [Database]
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// FullIndex - Index of the name of the instruction in one big string.
|
||||
|
||||
var Database = (function() {
|
||||
// `IndexedString` class.
|
||||
var IndexedString = function() {
|
||||
this.array = [];
|
||||
this.index = 0;
|
||||
@@ -52,6 +49,7 @@ var Database = (function() {
|
||||
|
||||
IndexedString.prototype.add = function(s) {
|
||||
var index = this.map[s];
|
||||
|
||||
if (typeof index === "number")
|
||||
return index;
|
||||
|
||||
@@ -84,38 +82,58 @@ var Database = (function() {
|
||||
return this.index;
|
||||
};
|
||||
|
||||
// `Database` class.
|
||||
var Database = function() {
|
||||
this.map = {};
|
||||
this.alphabetical = new Array(26);
|
||||
this.fullString = new IndexedString();
|
||||
this.instMap = {};
|
||||
this.instNames = new IndexedString();
|
||||
this.instAlpha = new Array(26);
|
||||
|
||||
this.extendedData = [];
|
||||
this.extendedMap = {};
|
||||
};
|
||||
|
||||
Database.prototype.add = function(name, id) {
|
||||
this.map[name] = {
|
||||
id: id,
|
||||
fullIndex: 0,
|
||||
hasV: 0
|
||||
Database.prototype.add = function(name, id, extendedData) {
|
||||
this.instMap[name] = {
|
||||
id : id, // Instruction ID.
|
||||
nameIndex : 0, // Instruction name-index, used directly by AsmJit.
|
||||
vPrefix : 0, // Instruction starts with 'v', not used at this point.
|
||||
extendedData : extendedData,
|
||||
extendedIndex : ""
|
||||
};
|
||||
};
|
||||
|
||||
Database.prototype.index = function() {
|
||||
var map = this.map;
|
||||
var alphabetical = this.alphabetical;
|
||||
var instMap = this.instMap;
|
||||
var instNames = this.instNames;
|
||||
var instAlpha = this.instAlpha;
|
||||
|
||||
for (var name in map) {
|
||||
var inst = map[name];
|
||||
inst.fullIndex = this.fullString.add(name);
|
||||
var extendedData = this.extendedData;
|
||||
var extendedMap = this.extendedMap;
|
||||
|
||||
for (var name in instMap) {
|
||||
var inst = instMap[name];
|
||||
|
||||
var nameIndex = instNames.add(name);
|
||||
var extendedIndex = extendedMap[inst.extendedData];
|
||||
|
||||
if (typeof extendedIndex !== "number") {
|
||||
extendedIndex = extendedData.length;
|
||||
extendedMap[inst.extendedData] = extendedIndex;
|
||||
extendedData.push(inst.extendedData);
|
||||
}
|
||||
|
||||
inst.nameIndex = nameIndex;
|
||||
inst.extendedIndex = extendedIndex;
|
||||
|
||||
var aIndex = name.charCodeAt(0) - 'a'.charCodeAt(0);
|
||||
if (aIndex < 0 || aIndex >= 26)
|
||||
throw new Error("Alphabetical index error");
|
||||
|
||||
if (alphabetical[aIndex] === undefined)
|
||||
alphabetical[aIndex] = inst.id;
|
||||
if (instAlpha[aIndex] === undefined)
|
||||
instAlpha[aIndex] = inst.id;
|
||||
|
||||
if (name.indexOf("v") === 0) {
|
||||
inst.hasV = 1;
|
||||
name = name.substr(1);
|
||||
inst.vPrefix = 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -127,64 +145,154 @@ var Database = (function() {
|
||||
// [Generate]
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
var decToHex = function(n, nPad) {
|
||||
var hex = Number(n < 0 ? 0x100000000 + n : n).toString(16);
|
||||
while (nPad > hex.length)
|
||||
hex = "0" + hex;
|
||||
return "0x" + hex.toUpperCase();
|
||||
};
|
||||
|
||||
var getEFlagsMask = function(eflags, passing) {
|
||||
var msk = 0x0;
|
||||
var bit = 0x1;
|
||||
|
||||
for (var i = 0; i < 8; i++, bit <<= 1) {
|
||||
if (passing.indexOf(eflags[i]) !== -1)
|
||||
msk |= bit;
|
||||
}
|
||||
|
||||
return msk;
|
||||
};
|
||||
|
||||
var generate = function(fileName, arch) {
|
||||
var Arch = upFirst(arch);
|
||||
var oldData = fs.readFileSync(fileName, "utf8").replace(/\r\n/g, "\n");
|
||||
|
||||
var data = oldData;
|
||||
var code = "";
|
||||
|
||||
var Arch = uppercaseFirst(arch);
|
||||
|
||||
var disclaimer = "// Automatically generated, do not edit.\n";
|
||||
|
||||
// Create database.
|
||||
var db = new Database();
|
||||
var re = new RegExp("INST\\(([A-Za-z0-9_]+)\\s*,\\s*\\\"([A-Za-z0-9_ ]*)\\\"", "g");
|
||||
var re = new RegExp(
|
||||
"INST\\(([A-Za-z0-9_]+)\\s*," + // [01] Inst-Code.
|
||||
"\\s*\\\"([A-Za-z0-9_ ]*)\\\"\\s*," + // [02] Inst-Name.
|
||||
"([^,]+)," + // [03] Inst-Group.
|
||||
"([^,]+)," + // [04] Inst-Flags.
|
||||
"([^,]+)," + // [05] Move-Size.
|
||||
"([^,]+)," + // [06] Operand-Flags[0].
|
||||
"([^,]+)," + // [07] Operand-Flags[1].
|
||||
"([^,]+)," + // [08] Operand-Flags[2].
|
||||
"([^,]+)," + // [09] Operand-Flags[3].
|
||||
"\\s*E\\(([A-Z_]+)\\)\\s*," + // [10] EFLAGS.
|
||||
"(.{17}[^,]*)," + // [11] OpCode[0].
|
||||
"(.{17}[^\\)]*)\\)", // [12] OpCode[1].
|
||||
"g");
|
||||
|
||||
while (m = re.exec(data)) {
|
||||
// Extract instruction ID and Name.
|
||||
var id = m[1];
|
||||
var name = m[2];
|
||||
|
||||
db.add(name, id);
|
||||
// Extract data that goes to the secondary table (ExtendedInfo).
|
||||
var instGroup = trimLeft(m[3]);
|
||||
var instFlags = trimLeft(m[4]);
|
||||
var moveSize = trimLeft(m[5]);
|
||||
|
||||
var opFlags0 = trimLeft(m[6]);
|
||||
var opFlags1 = trimLeft(m[7]);
|
||||
var opFlags2 = trimLeft(m[8]);
|
||||
var opFlags3 = trimLeft(m[9]);
|
||||
var eflags = m[10];
|
||||
var opCode1 = trimLeft(m[12]);
|
||||
|
||||
// Generate EFlags-In and EFlags-Out.
|
||||
var eflagsIn = decToHex(getEFlagsMask(eflags, "RX"), 2);
|
||||
var eflagsOut = decToHex(getEFlagsMask(eflags, "WXU"), 2);
|
||||
|
||||
var extData = "" +
|
||||
instGroup + ", " +
|
||||
moveSize + ", " +
|
||||
eflagsIn + ", " +
|
||||
eflagsOut + ", " +
|
||||
instFlags + ", " +
|
||||
"{ " + opFlags0 + ", " + opFlags1 + ", " + opFlags2 + ", " + opFlags3 + ", U }, " +
|
||||
opCode1;
|
||||
|
||||
db.add(name, id, extData);
|
||||
}
|
||||
db.index();
|
||||
|
||||
console.log("Full size: " + db.fullString.getSize());
|
||||
console.log("Number of instructions: " + db.instNames.array.length);
|
||||
console.log("Instruction names size: " + db.instNames.getSize());
|
||||
console.log("Extended-info length : " + db.extendedData.length);
|
||||
|
||||
// Generate InstName[] string.
|
||||
code += "const char _instName[] =\n";
|
||||
for (var k in db.map) {
|
||||
var inst = db.map[k];
|
||||
code += disclaimer;
|
||||
code += "#if !defined(ASMJIT_DISABLE_INST_NAMES)\n";
|
||||
code += "const char _" + arch + "InstName[] =\n";
|
||||
for (var k in db.instMap) {
|
||||
var inst = db.instMap[k];
|
||||
code += " \"" + k + "\\0\"\n";
|
||||
}
|
||||
code = code.substr(code, code.length - 1) + ";\n\n";
|
||||
|
||||
// Generate AlphaIndex.
|
||||
code += "enum kInstAlphaIndex {\n";
|
||||
code += " kInstAlphaIndexFirst = 'a',\n";
|
||||
code += " kInstAlphaIndexLast = 'z',\n";
|
||||
code += " kInstAlphaIndexInvalid = 0xFFFF\n";
|
||||
code += disclaimer;
|
||||
code += "enum k" + Arch + "InstAlphaIndex {\n";
|
||||
code += " k" + Arch + "InstAlphaIndexFirst = 'a',\n";
|
||||
code += " k" + Arch + "InstAlphaIndexLast = 'z',\n";
|
||||
code += " k" + Arch + "InstAlphaIndexInvalid = 0xFFFF\n";
|
||||
code += "};\n";
|
||||
code += "\n";
|
||||
|
||||
// Generate NameIndex.
|
||||
code += "static const uint16_t _instAlphaIndex[26] = {\n";
|
||||
for (var i = 0; i < db.alphabetical.length; i++) {
|
||||
var id = db.alphabetical[i];
|
||||
code += disclaimer;
|
||||
code += "static const uint16_t _" + arch + "InstAlphaIndex[26] = {\n";
|
||||
for (var i = 0; i < db.instAlpha.length; i++) {
|
||||
var id = db.instAlpha[i];
|
||||
code += " " + (id === undefined ? "0xFFFF" : id);
|
||||
if (i !== db.alphabetical.length - 1)
|
||||
if (i !== db.instAlpha.length - 1)
|
||||
code += ",";
|
||||
code += "\n";
|
||||
}
|
||||
code += "};\n\n";
|
||||
|
||||
code += "enum kInstData_NameIndex {\n";
|
||||
for (var k in db.map) {
|
||||
var inst = db.map[k];
|
||||
code += " " + inst.id + "_NameIndex = " + inst.fullIndex + ",\n";
|
||||
// Generate NameIndex.
|
||||
code += disclaimer;
|
||||
code += "enum k" + Arch + "InstData_NameIndex {\n";
|
||||
for (var k in db.instMap) {
|
||||
var inst = db.instMap[k];
|
||||
code += " " + inst.id + "_NameIndex = " + inst.nameIndex + ",\n";
|
||||
}
|
||||
code = code.substr(code, code.length - 2) + "\n};\n";
|
||||
code = code.substr(0, code.length - 2) + "\n};\n";
|
||||
code += "#endif // !ASMJIT_DISABLE_INST_NAMES\n"
|
||||
code += "\n";
|
||||
|
||||
// Generate ExtendedInfo.
|
||||
code += disclaimer;
|
||||
code += "const " + Arch + "InstExtendedInfo _" + arch + "InstExtendedInfo[] = {\n";
|
||||
for (var i = 0; i < db.extendedData.length; i++) {
|
||||
code += " { " + db.extendedData[i] + " }";
|
||||
if (i !== db.extendedData.length - 1)
|
||||
code += ",";
|
||||
code += "\n";
|
||||
}
|
||||
code += "};\n";
|
||||
code += "\n";
|
||||
|
||||
code += disclaimer;
|
||||
code += "enum k" + Arch + "InstData_ExtendedIndex {\n";
|
||||
for (var k in db.instMap) {
|
||||
var inst = db.instMap[k];
|
||||
code += " " + inst.id + "_ExtendedIndex = " + inst.extendedIndex + ",\n";
|
||||
}
|
||||
code = code.substr(0, code.length - 2) + "\n};\n";
|
||||
|
||||
// Inject.
|
||||
data = inject(data, injectStartMarker, injectEndMarker, code);
|
||||
data = inject(data,
|
||||
"// ${" + Arch + "InstData:Begin}\n",
|
||||
"// ${" + Arch + "InstData:End}\n",
|
||||
code);
|
||||
|
||||
// Save only if modified.
|
||||
if (data !== oldData)
|
||||
|
||||
Reference in New Issue
Block a user