Fixed Closure Compiler build (the compiler gets easily confused when objects in different class hierarchies have identical method names)

This commit is contained in:
Jeff Parsons 2015-11-08 21:38:15 -08:00
commit 39af7dbe32
6 changed files with 145 additions and 65 deletions

View file

@ -61,9 +61,10 @@ if (NODE) {
* addMemory(). If the component needs something more than simple read/write storage,
* it must provide a controller with getMemoryBuffer() and getMemoryAccess() methods.
*
* By contrast, all port (I/O) operations are defined by external handlers; they register
* with us, and we manage those registrations, as well as support for I/O breakpoints,
* but unlike memory accesses, we're not involved with port data accesses.
* All port (I/O) operations are defined by external handlers; they register with us,
* and we manage those registrations and provide support for I/O breakpoints, but the
* only default I/O behavior we provide is ignoring writes to any unregistered output
* ports and returning 0xff from any unregistered input ports.
*
* @constructor
* @extends Component
@ -1266,7 +1267,7 @@ Bus.prototype.getSymbol = function(addr, fNearest)
};
/**
* saveMemory()
* saveMemory(fAll)
*
* The only memory blocks we save are those marked as dirty, but most likely all of RAM will have been marked dirty,
* and even if our dirty-memory flags were as smart as our dirty-sector flags (ie, were set only when a write changed
@ -1291,17 +1292,17 @@ Bus.prototype.getSymbol = function(addr, fNearest)
* helper methods compress() and decompress() to create and expand the compressed data arrays.
*
* @this {Bus}
* @param {boolean} [fAll] (true to save all non-ROM memory blocks, regardless of their dirty flags)
* @return {Array} a
*/
Bus.prototype.saveMemory = function()
Bus.prototype.saveMemory = function(fAll)
{
var i = 0;
var a = [];
/*
* A quick-and-dirty work-around for 32-bit bus machines, to ensure that all blocks in the 2nd Mb are
* mapped in before we save. We do this by forcing A20 on, and then turning it back off again before we
* leave.
* mapped in before we save. We do this by forcing A20 on, and then turning it off again before we leave.
*/
var fA20 = this.getA20();
if (!fA20) this.setA20(true);
@ -1313,7 +1314,7 @@ Bus.prototype.saveMemory = function()
* the memory blocks (eg, video memory), and while cleanMemory() will clear a dirty block's fDirty flag,
* it also sets the dirty block's fDirtyEver flag, which is left set for the lifetime of the machine.
*/
if (block.fDirty || block.fDirtyEver) {
if (fAll && block.type != Memory.TYPE.ROM || block.fDirty || block.fDirtyEver) {
a[i++] = iBlock;
a[i++] = State.compress(block.save());
}
@ -1336,7 +1337,7 @@ Bus.prototype.saveMemory = function()
* it was using when it's restored. And since the CPU is guaranteed to be the last
* component to be restored, all those blocks (and their attributes) should be in place now.
*
* See saveMemory() for a description of how the memory block contents are saved.
* See saveMemory() for more information on how the memory block contents are saved.
*
* @this {Bus}
* @param {Array} a
@ -1466,12 +1467,11 @@ Bus.prototype.checkPortInputNotify = function(port, size, addrLIP)
var dataPort = maskPort;
/*
* TODO: We need to decide what to do about 8-bit I/O to a 16-bit port
* (ditto for 16-bit I/O to a 32-bit port). We probably should pass the
* size through to the aNotify[0] handler, and let it decide what to do,
* but I don't feel like changing all the I/O handlers right now. The
* good news, at least, is that the 8-bit handlers would not have to do
* anything special. This assert will warn us if this is a pressing need.
* TODO: We need to decide what to do about 8-bit I/O to a 16-bit port (ditto for 16-bit I/O
* to a 32-bit port). We probably should pass the size through to the aNotify[0] handler,
* and let it decide what to do, but I don't feel like changing all the I/O handlers right now.
* The good news, at least, is that the 8-bit handlers would not have to do anything special.
* This assert will warn us if this is a pressing need.
*/
this.assert(size >= sizePort);
@ -1625,12 +1625,11 @@ Bus.prototype.checkPortOutputNotify = function(port, size, data, addrLIP)
var dataPort = (data >>>= shift) & maskPort;
/*
* TODO: We need to decide what to do about 8-bit I/O to a 16-bit port
* (ditto for 16-bit I/O to a 32-bit port). We probably should pass the
* size through to the aNotify[0] handler, and let it decide what to do,
* but I don't feel like changing all the I/O handlers right now. The
* good news, at least, is that the 8-bit handlers would not have to do
* anything special. This assert will warn us if this is a pressing need.
* TODO: We need to decide what to do about 8-bit I/O to a 16-bit port (ditto for 16-bit I/O
* to a 32-bit port). We probably should pass the size through to the aNotify[0] handler,
* and let it decide what to do, but I don't feel like changing all the I/O handlers right now.
* The good news, at least, is that the 8-bit handlers would not have to do anything special.
* This assert will warn us if this is a pressing need.
*/
this.assert(size >= sizePort);

View file

@ -256,6 +256,17 @@ Memory.adjustEndian = function(dw) {
Memory.prototype = {
constructor: Memory,
parent: null,
/**
* init(addr)
*
* Quick reinitializer when reusing a Memory block.
*
* @this {Memory}
* @param {number} addr
*/
init: function(addr) {
this.addr = addr;
},
/**
* clone(mem, type)
*
@ -501,6 +512,7 @@ Memory.prototype = {
* @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;
@ -516,9 +528,9 @@ Memory.prototype = {
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;
this.setAccess(Memory.afnPaged);
}
},
/**
@ -1231,7 +1243,14 @@ Memory.prototype = {
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;
/*
* NOTE: Technically, we should be setting the fDirty flag on blockPDE and blockPTE as well, but let's
* consider the two sole uses of fDirty. First, we have cleanMemory(), which is currently used only by
* the Video component, and video memory should never contain page directories or page tables, so no
* worries there. Second, we have saveMemory(), but the CPU now asks that function to save all physical
* memory blocks whenever paging is enabled, so no worries there either.
*/
this.blockPhys.fDirty = true;
},
/**
* writeShortBE(off, w, addr)
@ -1287,7 +1306,14 @@ Memory.prototype = {
}
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED | X86.PTE.DIRTY;
this.fDirty = true;
/*
* NOTE: Technically, we should be setting the fDirty flag on blockPDE and blockPTE as well, but let's
* consider the two sole uses of fDirty. First, we have cleanMemory(), which is currently used only by
* the Video component, and video memory should never contain page directories or page tables, so no
* worries there. Second, we have saveMemory(), but the CPU now asks that function to save all physical
* memory blocks whenever paging is enabled, so no worries there either.
*/
this.blockPhys.fDirty = true;
},
/**
* writeLongBE(off, l, addr)
@ -1347,7 +1373,14 @@ Memory.prototype = {
}
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED | X86.PTE.DIRTY;
this.fDirty = true;
/*
* NOTE: Technically, we should be setting the fDirty flag on blockPDE and blockPTE as well, but let's
* consider the two sole uses of fDirty. First, we have cleanMemory(), which is currently used only by
* the Video component, and video memory should never contain page directories or page tables, so no
* worries there. Second, we have saveMemory(), but the CPU now asks that function to save all physical
* memory blocks whenever paging is enabled, so no worries there either.
*/
this.blockPhys.fDirty = true;
},
/**
* readBackTrackNone(off)

View file

@ -278,9 +278,7 @@ State.prototype = {
if (s) {
this[this.id] = s;
this.fLoaded = true;
if (DEBUG && this.messageEnabled()) {
this.printMessage("localStorage(" + this.key + "): " + s.length + " bytes loaded");
}
if (DEBUG) this.printString("localStorage(" + this.key + "): " + s.length + " bytes loaded");
return true;
}
}
@ -317,9 +315,7 @@ State.prototype = {
if (web.hasLocalStorage()) {
var s = JSON.stringify(this[this.id]);
if (web.setLocalStorageItem(this.key, s)) {
if (DEBUG && this.messageEnabled()) {
this.printMessage("localStorage(" + this.key + "): " + s.length + " bytes stored");
}
if (DEBUG) this.printString("localStorage(" + this.key + "): " + s.length + " bytes stored");
} else {
/*
* WARNING: Because browsers tend to disable all alerts() during an "unload" operation,
@ -377,40 +373,24 @@ State.prototype = {
var sKey = aKeys[i];
if (sKey && (fAll || sKey.substr(0, this.key.length) == this.key)) {
web.removeLocalStorageItem(sKey);
if (DEBUG && this.messageEnabled()) {
this.printMessage("localStorage(" + sKey + ") removed");
}
if (DEBUG) this.printString("localStorage(" + sKey + ") removed");
aKeys.splice(i, 1);
i = 0;
}
}
},
/**
* messageEnabled(bitsMessage)
* printString(s)
*
* @this {State}
* @param {number} [bitsMessage] is one or more Messages category flag(s)
* @return {boolean}
* @param {string} s is any caller-defined string
*/
messageEnabled: function(bitsMessage) {
if (DEBUGGER && this.dbg) {
if (bitsMessage == null) {
bitsMessage = Messages.STATE;
} else {
bitsMessage |= Messages.STATE;
printString: function(s) {
if (DEBUG && DEBUGGER && this.dbg) {
if (this.dbg.messageEnabled(Messages.STATE)) {
this.dbg.message(s);
}
return this.dbg.messageEnabled(bitsMessage);
}
return false;
},
/**
* printMessage(sMessage)
*
* @this {State}
* @param {string} sMessage is any caller-defined message string
*/
printMessage: function(sMessage) {
if (DEBUGGER && this.dbg) this.dbg.message(sMessage);
}
};

View file

@ -218,6 +218,8 @@ if (PREFETCH) {
X86CPU.PFINFO.IP_MASK = ((X86CPU.PFINFO.LENGTH - 1) & ~0x3);
}
X86CPU.PAGEBLOCKS_CACHE = 512; // TODO: This seems adequate for 4Mb of RAM, but it should be dynamically reconfigured
/**
* initMemory(aMemBlocks, nBlockShift)
*
@ -432,6 +434,12 @@ X86CPU.prototype.enablePageBlocks = function()
* if the Debugger is suppressing faults or calling probeAddr(), returning memEmpty is helpful.
*/
this.memEmpty = new Memory();
/*
* Initialize our PAGEBLOCKS cache (see acquirePageBlock() and releasePageBlock()).
*/
this.aCacheBlocks = new Array(X86CPU.PAGEBLOCKS_CACHE);
this.iCacheBlocks = 0;
} else {
/*
* Our equivalent of a TLB flush. NOTE: We do not attempt to simulate an actual TLB; our
@ -440,12 +448,62 @@ X86CPU.prototype.enablePageBlocks = function()
* a constrained TLB -- at least not from the 80386 era, which is all we're emulating.
*/
for (var i = 0; i < this.aBlocksPaged.length; i++) {
this.aMemBlocks[this.aBlocksPaged[i]] = this.blockUnpaged;
var iBlock = this.aBlocksPaged[i];
this.releasePageBlock(this.aMemBlocks[iBlock]);
this.aMemBlocks[iBlock] = this.blockUnpaged;
}
}
this.aBlocksPaged = [];
};
/**
* acquirePageBlock(addr)
*
* This implements a simple paged memory block cache. Candidates for caching must be released via
* releasePageBlock().
*
* After acquiring a block from this cache, the caller MUST use setPhysBlock() to properly reinitialize
* it for the new given linear address.
*
* @this {X86CPU}
* @param {number} addr
* @return {Memory}
*/
X86CPU.prototype.acquirePageBlock = function(addr)
{
var block;
if (this.iCacheBlocks > 0) {
block = this.aCacheBlocks[--this.iCacheBlocks];
/*
* Paged memory blocks are all very generic and contain no memory of their own, so the fact
* that we're not calling the Memory constructor to reinitialize it is OK. setPhysBlock() is
* what's critical, and the caller will take care of that. However, to avoid any confusion,
* especially when debugging, there are a few properties we should reinitialize, hence init().
*/
block.init(addr);
} else {
block = new Memory(addr, 0, 0, Memory.TYPE.PAGED);
}
return block;
};
/**
* releasePageBlock(block)
*
* Instead of simply tossing Memory blocks onto the garbage collector's heap, we'll retain a maximum
* number (X86CPU.PAGEBLOCKS_CACHE) in aCacheBlocks, with iCacheBlocks pointing to the next free element.
*
* @this {X86CPU}
* @param {Memory} block
*/
X86CPU.prototype.releasePageBlock = function(block)
{
this.assert(block && block.type === Memory.TYPE.PAGED);
if (this.iCacheBlocks < X86CPU.PAGEBLOCKS_CACHE) {
this.aCacheBlocks[this.iCacheBlocks++] = block;
}
};
/**
* mapPageBlock(addr, fWrite, fSuppress)
*
@ -535,14 +593,13 @@ X86CPU.prototype.mapPageBlock = function(addr, fWrite, fSuppress)
*
* Now we can create a new PAGED Memory block and record the physical block info using setPhysBlock().
*/
var addrPage = addr & ~X86.LADDR.OFFSET;
var blockPage = new Memory(addrPage, 0, 0, Memory.TYPE.PAGED);
var blockPage = this.acquirePageBlock(addr & ~X86.LADDR.OFFSET);
blockPage.setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE);
blockPage.copyBreakpoints(this.dbg, block);
this.aMemBlocks[iBlock] = blockPage;
this.aBlocksPaged.push(iBlock);
return blockPage;
};
@ -563,6 +620,19 @@ X86CPU.prototype.disablePageBlocks = function()
}
};
/**
* isPagingEnabled()
*
* @this {X86CPU}
* @return {boolean}
*/
X86CPU.prototype.isPagingEnabled = function()
{
var fPaging = !!(this.regCR0 & X86.CR0.PG);
this.assert((this.aMemBlocks !== this.aBusBlocks) === fPaging);
return fPaging;
};
/**
* initProcessor()
*
@ -1717,7 +1787,7 @@ X86CPU.prototype.save = function()
state.set(1, a);
state.set(2, [this.segData.sName, this.segStack.sName, this.opFlags, this.opPrefixes, this.intFlags, this.regEA, this.regEAWrite]);
state.set(3, [0, this.nTotalCycles, this.getSpeed()]);
state.set(4, this.bus.saveMemory());
state.set(4, this.bus.saveMemory(this.isPagingEnabled()));
return state.data();
};

View file

@ -4116,7 +4116,8 @@ X86.fnFaultMessage = function(nFault, nError, fHalt)
var sMessage = "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode " + str.toHexByte(bOpcode);
if (fHalt && fRunning) sMessage += " (blocked by PCjs Debugger)";
if (this.printMessage(sMessage, fHalt || bitsMessage, true)) {
if (DEBUGGER && this.dbg) {
this.printMessage(sMessage, fHalt || bitsMessage, true);
if (fHalt) {
/*
* By setting fHalt to fRunning (which is true while running but false while single-stepping),
@ -4131,8 +4132,8 @@ X86.fnFaultMessage = function(nFault, nError, fHalt)
}
} else {
/*
* If printMessage() returned false, then there's no Debugger, which means that messageEnabled() must have
* returned false as well, which means that fHalt must be true. Which means we should shut the machine down.
* If there's no Debugger, then messageEnabled() must have returned false, which means that fHalt must
* be true. Which means we should shut the machine down.
*/
this.assert(fHalt);
this.notice(sMessage);

View file

@ -960,16 +960,13 @@ Component.prototype = {
* @param {string} sMessage is any caller-defined message string
* @param {number|boolean} [bitsMessage] is zero or more MESSAGE_* category flag(s)
* @param {boolean} [fAddress] is true to display the current address
* @return {boolean} true if Debugger available, false if not
*/
printMessage: function(sMessage, bitsMessage, fAddress) {
if (DEBUGGER && this.dbg) {
if (bitsMessage === true || this.messageEnabled(bitsMessage | 0)) {
this.dbg.message(sMessage, fAddress);
}
return true;
}
return false;
},
/**
* printMessageIO(port, bOut, addrFrom, name, bIn, bitsMessage)