Added optimized memory handlers for paged memory

This commit is contained in:
Jeff Parsons 2015-11-07 18:35:32 -08:00
commit d3a8160ad8
3 changed files with 182 additions and 82 deletions

View file

@ -7670,7 +7670,7 @@ if (DEBUGGER) {
}
break;
}
this.println((APPNAME || "PCjs") + " version " + (XMLVERSION || APPVERSION) + " (" + this.cpu.model + (COMPILED? ",RELEASE" : (DEBUG? ",DEBUG" : ",NODEBUG")) + (PREFETCH? ",PREFETCH" : ",NOPREFETCH") + (TYPEDARRAYS? ",TYPEDARRAYS" : (FATARRAYS? ",FATARRAYS" : ",LONGARRAYS")) + (BACKTRACK? ",BACKTRACK" : ",NOBACKTRACK") + ')');
this.println((APPNAME || "PCjs") + " version " + (XMLVERSION || APPVERSION) + " (" + this.cpu.model + (COMPILED? ",RELEASE" : (DEBUG? ",DEBUG" : ",NODEBUG")) + (PREFETCH? ",PREFETCH" : ",NOPREFETCH") + (TYPEDARRAYS? ",TYPEDARRAYS" : (BYTEARRAYS? ",BYTEARRAYS" : ",LONGARRAYS")) + (BACKTRACK? ",BACKTRACK" : ",NOBACKTRACK") + ')');
break;
case 'x':
this.doExecOptions(asArgs);

View file

@ -64,12 +64,12 @@ var PREFETCH = false;
/**
* @define {boolean}
*
* FATARRAYS is a Closure Compiler compile-time option that allocates an Array of numbers for every Memory block,
* BYTEARRAYS is a Closure Compiler compile-time option that allocates an Array of numbers for every Memory block,
* where each a number represents ONE byte; very wasteful, but potentially slightly faster.
*
* See the Memory component for details.
*/
var FATARRAYS = false;
var BYTEARRAYS = false;
/**
* TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time-only option, but I've
@ -147,7 +147,7 @@ if (NODE) {
global.PCJSCLASS = PCJSCLASS;
global.DEBUGGER = DEBUGGER;
global.PREFETCH = PREFETCH;
global.FATARRAYS = FATARRAYS;
global.BYTEARRAYS = BYTEARRAYS;
global.TYPEDARRAYS = TYPEDARRAYS;
global.BACKTRACK = BACKTRACK;
global.SYMBOLS = SYMBOLS;

View file

@ -75,7 +75,7 @@ var littleEndian = (TYPEDARRAYS? (function() {
* (LONGARRAYS) and shifting/masking bytes/words to/from dwords; in theory, byte accesses would
* be faster and word accesses somewhat less faster.
*
* However, preliminary testing of that feature (FATARRAYS) did not yield significantly faster
* However, preliminary testing of that feature (BYTEARRAYS) did not yield significantly faster
* performance, so it is OFF by default to minimize our memory consumption. Using TYPEDARRAYS
* would seem best, but as discussed in defines.js, it's off by default, because it doesn't perform
* as well as LONGARRAYS; the other advantage of TYPEDARRAYS is that it should theoretically use
@ -110,7 +110,6 @@ function Memory(addr, used, size, type, controller, cpu)
this.controller = null;
this.cpu = cpu; // if a CPU reference is provided, then this must be an UNPAGED Memory block allocation
this.fDirty = this.fDirtyEver = false;
this.setPhysBlock();
this.copyBreakpoints(); // initialize the block's Debugger info (eg, breakpoint totals); the caller will reinitialize
if (BACKTRACK) {
@ -170,13 +169,13 @@ function Memory(addr, used, size, type, controller, cpu)
this.ab = new Uint8Array(this.buffer, 0, size);
this.aw = new Uint16Array(this.buffer, 0, size >> 1);
this.adw = new Int32Array(this.buffer, 0, size >> 2);
this.setAccess(littleEndian? Memory.afnLittleEndian : Memory.afnBigEndian);
this.setAccess(littleEndian? Memory.afnArrayLE : Memory.afnArrayBE);
} else {
if (FATARRAYS) {
if (BYTEARRAYS) {
this.ab = new Array(size);
} else {
/*
* NOTE: This is the default mode of operation (!TYPEDARRAYS && !FATARRAYS), because it
* NOTE: This is the default mode of operation (!TYPEDARRAYS && !BYTEARRAYS), because it
* seems to provide the best performance; and although in theory, that performance might
* come at twice the overhead of TYPEDARRAYS, it's increasingly likely that the JavaScript
* runtime will notice that all we ever store are 32-bit values, and optimize accordingly.
@ -287,9 +286,9 @@ Memory.prototype = {
this.ab = mem.ab;
this.aw = mem.aw;
this.adw = mem.adw;
this.setAccess(littleEndian? Memory.afnLittleEndian : Memory.afnBigEndian);
this.setAccess(littleEndian? Memory.afnArrayLE : Memory.afnArrayBE);
} else {
if (FATARRAYS) {
if (BYTEARRAYS) {
this.ab = mem.ab;
} else {
this.adw = mem.adw;
@ -315,7 +314,7 @@ Memory.prototype = {
if (this.controller) {
adw = null;
}
else if (FATARRAYS) {
else if (BYTEARRAYS) {
adw = new Array(this.size >> 2);
var off = 0;
for (i = 0; i < adw.length; i++) {
@ -367,11 +366,11 @@ Memory.prototype = {
* memory blocks installed at the programmed address, and so we arrived here at a block with
* no controller AND no data.
*/
// DEBUG: Component.assert(adw != null);
Component.assert(adw != null);
if (adw && this.size == adw.length << 2) {
var i;
if (FATARRAYS) {
if (BYTEARRAYS) {
var off = 0;
for (i = 0; i < adw.length; i++) {
this.ab[off] = adw[i] & 0xff;
@ -399,7 +398,7 @@ Memory.prototype = {
*
* @this {Memory}
* @param {Array.<function()>} [afn] function table
* @param {boolean} [fDirect]
* @param {boolean} [fDirect] (true to update direct access functions as well; default is true)
*/
setAccess: function(afn, fDirect) {
if (!afn) {
@ -495,20 +494,32 @@ Memory.prototype = {
* setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE)
*
* @this {Memory}
* @param {Memory|null} [blockPhys]
* @param {Memory|null} [blockPDE]
* @param {number} [offPDE]
* @param {Memory|null} [blockPTE]
* @param {number} [offPTE]
* @param {Memory} blockPhys
* @param {Memory} blockPDE
* @param {number} offPDE
* @param {Memory} blockPTE
* @param {number} offPTE
*/
setPhysBlock: function(blockPhys, blockPDE, offPDE, blockPTE, offPTE) {
this.blockPhys = blockPhys;
this.blockPDE = blockPDE;
this.iPDE = offPDE >> 2; // convert offPDE into iPDE (an adw index)
this.blockPTE = blockPTE;
this.iPTE = offPTE >> 2; // convert offPTE into iPTE (an adw index)
this.bitPTEDirty = blockPhys? Memory.adjustEndian(X86.PTE.ACCESSED | X86.PTE.DIRTY) : 0;
this.bitPTEAccessed = blockPhys? Memory.adjustEndian(X86.PTE.ACCESSED) : 0;
/*
* This is an optimization for "normal" pages, installing paged memory handlers that mimic
* normal memory but also know how to update page tables. If any of the criteria are not met
* for these special handlers, we fall back to the slower default "paged" memory handlers.
*/
if (TYPEDARRAYS && littleEndian && blockPhys.adw && !blockPhys.controller) {
this.ab = blockPhys.ab;
this.aw = blockPhys.aw;
this.adw = blockPhys.adw;
this.setAccess(Memory.afnPagedLE);
} else {
this.blockPhys = blockPhys;
this.bitPTEAccessed = blockPhys? Memory.adjustEndian(X86.PTE.ACCESSED) : 0;
this.bitPTEDirty = blockPhys? Memory.adjustEndian(X86.PTE.ACCESSED | X86.PTE.DIRTY) : 0;
}
},
/**
* printAddr(sMessage)
@ -671,7 +682,6 @@ Memory.prototype = {
* @param {number} addr
*/
writeShortDefault: function writeShortDefault(off, w, addr) {
// DEBUG: Component.assert(!(w & ~0xffff));
this.writeByte(off++, w & 0xff, addr++);
this.writeByte(off, w >> 8, addr);
},
@ -698,8 +708,7 @@ Memory.prototype = {
* @return {number}
*/
readByteMemory: function readByteMemory(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
if (FATARRAYS) {
if (BYTEARRAYS) {
return this.ab[off];
}
return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff);
@ -713,8 +722,7 @@ Memory.prototype = {
* @return {number}
*/
readShortMemory: function readShortMemory(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1);
if (FATARRAYS) {
if (BYTEARRAYS) {
return this.ab[off] | (this.ab[off + 1] << 8);
}
var w;
@ -737,8 +745,7 @@ Memory.prototype = {
* @return {number}
*/
readLongMemory: function readLongMemory(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3);
if (FATARRAYS) {
if (BYTEARRAYS) {
return this.ab[off] | (this.ab[off + 1] << 8) | (this.ab[off + 2] << 16) | (this.ab[off + 3] << 24);
}
var idw = off >> 2;
@ -759,8 +766,7 @@ Memory.prototype = {
* @param {number} addr
*/
writeByteMemory: function writeByteMemory(off, b, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size && (b & 0xff) == b);
if (FATARRAYS) {
if (BYTEARRAYS) {
this.ab[off] = b;
} else {
var idw = off >> 2;
@ -778,8 +784,7 @@ Memory.prototype = {
* @param {number} addr
*/
writeShortMemory: function writeShortMemory(off, w, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1 && (w & 0xffff) == w);
if (FATARRAYS) {
if (BYTEARRAYS) {
this.ab[off] = (w & 0xff);
this.ab[off + 1] = (w >> 8);
} else {
@ -804,8 +809,7 @@ Memory.prototype = {
* @param {number} addr
*/
writeLongMemory: function writeLongMemory(off, l, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3);
if (FATARRAYS) {
if (BYTEARRAYS) {
this.ab[off] = (l & 0xff);
this.ab[off + 1] = (l >> 8) & 0xff;
this.ab[off + 2] = (l >> 16) & 0xff;
@ -1071,51 +1075,60 @@ Memory.prototype = {
this.getPageBlock(addr, true).writeLong(off, l, addr);
},
/**
* readByteBigEndian(off, addr)
* readByteBE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readByteBigEndian: function readByteBigEndian(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
readByteBE: function readByteBE(off, addr) {
return this.ab[off];
},
/**
* readByteLittleEndian(off, addr)
* readByteLE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readByteLittleEndian: function readByteLittleEndian(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
readByteLE: function readByteLE(off, addr) {
return this.ab[off];
},
/**
* readShortBigEndian(off, addr)
* readBytePLE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readShortBigEndian: function readShortBigEndian(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1);
readBytePLE: function readBytePLE(off, addr) {
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED;
return this.ab[off];
},
/**
* readShortBE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readShortBE: function readShortBE(off, addr) {
return this.dv.getUint16(off, true);
},
/**
* readShortLittleEndian(off, addr)
* readShortLE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readShortLittleEndian: function readShortLittleEndian(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1);
readShortLE: function readShortLE(off, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read
* vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
@ -1123,27 +1136,42 @@ Memory.prototype = {
return (off & 0x1)? (this.ab[off] | (this.ab[off+1] << 8)) : this.aw[off >> 1];
},
/**
* readLongBigEndian(off, addr)
* readShortPLE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readLongBigEndian: function readLongBigEndian(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3);
readShortPLE: function readShortPLE(off, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read
* vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
*/
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED;
return (off & 0x1)? (this.ab[off] | (this.ab[off+1] << 8)) : this.aw[off >> 1];
},
/**
* readLongBE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readLongBE: function readLongBE(off, addr) {
return this.dv.getInt32(off, true);
},
/**
* readLongLittleEndian(off, addr)
* readLongLE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readLongLittleEndian: function readLongLittleEndian(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3);
readLongLE: function readLongLE(off, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read
* vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
@ -1151,54 +1179,81 @@ Memory.prototype = {
return (off & 0x3)? (this.ab[off] | (this.ab[off+1] << 8) | (this.ab[off+2] << 16) | (this.ab[off+3] << 24)) : this.adw[off >> 2];
},
/**
* writeByteBigEndian(off, b, addr)
* readLongPLE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readLongPLE: function readLongPLE(off, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read
* vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
*/
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED;
return (off & 0x3)? (this.ab[off] | (this.ab[off+1] << 8) | (this.ab[off+2] << 16) | (this.ab[off+3] << 24)) : this.adw[off >> 2];
},
/**
* writeByteBE(off, b, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} b
* @param {number} addr
*/
writeByteBigEndian: function writeByteBigEndian(off, b, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
writeByteBE: function writeByteBE(off, b, addr) {
this.ab[off] = b;
this.fDirty = true;
},
/**
* writeByteLittleEndian(off, b, addr)
* writeByteLE(off, b, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @param {number} b
*/
writeByteLittleEndian: function writeByteLittleEndian(off, b, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
writeByteLE: function writeByteLE(off, b, addr) {
this.ab[off] = b;
this.fDirty = true;
},
/**
* writeShortBigEndian(off, w, addr)
* writeBytePLE(off, b, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @param {number} b
*/
writeBytePLE: function writeBytePLE(off, b, addr) {
this.ab[off] = b;
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED | X86.PTE.DIRTY;
this.fDirty = true;
},
/**
* writeShortBE(off, w, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @param {number} w
*/
writeShortBigEndian: function writeShortBigEndian(off, w, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1);
writeShortBE: function writeShortBE(off, w, addr) {
this.dv.setUint16(off, w, true);
this.fDirty = true;
},
/**
* writeShortLittleEndian(off, w, addr)
* writeShortLE(off, w, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @param {number} w
*/
writeShortLittleEndian: function writeShortLittleEndian(off, w, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1);
writeShortLE: function writeShortLE(off, w, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write
* vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
@ -1212,28 +1267,49 @@ Memory.prototype = {
this.fDirty = true;
},
/**
* writeLongBigEndian(off, l, addr)
* writeShortPLE(off, w, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @param {number} w
*/
writeShortPLE: function writeShortPLE(off, w, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write
* vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
*/
if (off & 0x1) {
this.ab[off] = w;
this.ab[off+1] = w >> 8;
} else {
this.aw[off >> 1] = w;
}
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED | X86.PTE.DIRTY;
this.fDirty = true;
},
/**
* writeLongBE(off, l, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} l
* @param {number} addr
*/
writeLongBigEndian: function writeLongBigEndian(off, l, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3);
writeLongBE: function writeLongBE(off, l, addr) {
this.dv.setInt32(off, l, true);
this.fDirty = true;
},
/**
* writeLongLittleEndian(off, l, addr)
* writeLongLE(off, l, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} l
* @param {number} addr
*/
writeLongLittleEndian: function writeLongLittleEndian(off, l, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3);
writeLongLE: function writeLongLE(off, l, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write
* vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
@ -1248,6 +1324,31 @@ Memory.prototype = {
}
this.fDirty = true;
},
/**
* writeLongPLE(off, l, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} l
* @param {number} addr
*/
writeLongPLE: function writeLongPLE(off, l, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write
* vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
*/
if (off & 0x3) {
this.ab[off] = l;
this.ab[off+1] = (l >> 8);
this.ab[off+2] = (l >> 16);
this.ab[off+3] = (l >> 24);
} else {
this.adw[off >> 2] = l;
}
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED | X86.PTE.DIRTY;
this.fDirty = true;
},
/**
* readBackTrackNone(off)
*
@ -1284,7 +1385,6 @@ Memory.prototype = {
* @return {number}
*/
readBackTrackIndex: function readBackTrackIndex(off) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
return this.abtIndexes[off];
},
/**
@ -1297,7 +1397,6 @@ Memory.prototype = {
*/
writeBackTrackIndex: function writeBackTrackIndex(off, bti) {
var btiPrev;
// DEBUG: Component.assert(off >= 0 && off < this.size);
btiPrev = this.abtIndexes[off];
this.abtIndexes[off] = bti;
return btiPrev;
@ -1320,21 +1419,22 @@ Memory.prototype = {
* This is the effective definition of afnNone, but we need not fully define it, because setAccess()
* uses these defaults when any of the 6 handlers (ie, 3 read handlers and 3 write handlers) are undefined.
*
Memory.afnNone = [Memory.prototype.readNone, Memory.prototype.readShortDefault, Memory.prototype.readLongDefault, Memory.prototype.writeNone, Memory.prototype.writeShortDefault, Memory.prototype.writeLongDefault];
Memory.afnNone = [Memory.prototype.readNone, Memory.prototype.readShortDefault, Memory.prototype.readLongDefault, Memory.prototype.writeNone, Memory.prototype.writeShortDefault, Memory.prototype.writeLongDefault];
*/
Memory.afnNone = [];
Memory.afnMemory = [Memory.prototype.readByteMemory, Memory.prototype.readShortMemory, Memory.prototype.readLongMemory, Memory.prototype.writeByteMemory, Memory.prototype.writeShortMemory, Memory.prototype.writeLongMemory];
Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.readLongChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked, Memory.prototype.writeLongChecked];
Memory.afnNone = [];
Memory.afnMemory = [Memory.prototype.readByteMemory, Memory.prototype.readShortMemory, Memory.prototype.readLongMemory, Memory.prototype.writeByteMemory, Memory.prototype.writeShortMemory, Memory.prototype.writeLongMemory];
Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.readLongChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked, Memory.prototype.writeLongChecked];
if (PAGEBLOCKS) {
Memory.afnPaged = [Memory.prototype.readBytePaged, Memory.prototype.readShortPaged, Memory.prototype.readLongPaged, Memory.prototype.writeBytePaged, Memory.prototype.writeShortPaged, Memory.prototype.writeLongPaged];
Memory.afnUnpaged = [Memory.prototype.readByteUnpaged, Memory.prototype.readShortUnpaged, Memory.prototype.readLongUnpaged, Memory.prototype.writeByteUnpaged, Memory.prototype.writeShortUnpaged, Memory.prototype.writeLongUnpaged];
Memory.afnPaged = [Memory.prototype.readBytePaged, Memory.prototype.readShortPaged, Memory.prototype.readLongPaged, Memory.prototype.writeBytePaged, Memory.prototype.writeShortPaged, Memory.prototype.writeLongPaged];
Memory.afnUnpaged = [Memory.prototype.readByteUnpaged, Memory.prototype.readShortUnpaged, Memory.prototype.readLongUnpaged, Memory.prototype.writeByteUnpaged, Memory.prototype.writeShortUnpaged, Memory.prototype.writeLongUnpaged];
}
if (TYPEDARRAYS) {
Memory.afnBigEndian = [Memory.prototype.readByteBigEndian, Memory.prototype.readShortBigEndian, Memory.prototype.readLongBigEndian, Memory.prototype.writeByteBigEndian, Memory.prototype.writeShortBigEndian, Memory.prototype.writeLongBigEndian];
Memory.afnLittleEndian = [Memory.prototype.readByteLittleEndian, Memory.prototype.readShortLittleEndian, Memory.prototype.readLongLittleEndian, Memory.prototype.writeByteLittleEndian, Memory.prototype.writeShortLittleEndian, Memory.prototype.writeLongLittleEndian];
Memory.afnArrayBE = [Memory.prototype.readByteBE, Memory.prototype.readShortBE, Memory.prototype.readLongBE, Memory.prototype.writeByteBE, Memory.prototype.writeShortBE, Memory.prototype.writeLongBE];
Memory.afnArrayLE = [Memory.prototype.readByteLE, Memory.prototype.readShortLE, Memory.prototype.readLongLE, Memory.prototype.writeByteLE, Memory.prototype.writeShortLE, Memory.prototype.writeLongLE];
Memory.afnPagedLE = [Memory.prototype.readBytePLE, Memory.prototype.readShortPLE, Memory.prototype.readLongPLE, Memory.prototype.writeBytePLE, Memory.prototype.writeShortPLE, Memory.prototype.writeLongPLE];
}
if (NODE) module.exports = Memory;