Simplify recursive state handling (don't require get_state for set_state)

This commit is contained in:
Fabian 2020-12-31 19:14:32 -06:00
parent faadca9f35
commit cd3f48c0a3
7 changed files with 57 additions and 87 deletions

View file

@ -190,7 +190,7 @@ Virtio9p.prototype.set_state = function(state)
{ {
this.configspace_tagname = state[0]; this.configspace_tagname = state[0];
this.configspace_taglen = state[1]; this.configspace_taglen = state[1];
this.virtio = state[2]; this.virtio.set_state(state[2]);
this.virtqueue = this.virtio.queues[0]; this.virtqueue = this.virtio.queues[0];
this.VERSION = state[3]; this.VERSION = state[3];
this.BLOCKSIZE = state[4]; this.BLOCKSIZE = state[4];
@ -201,7 +201,7 @@ Virtio9p.prototype.set_state = function(state)
{ {
return { inodeid: f[0], type: f[1], uid: f[2], dbg_name: f[3] }; return { inodeid: f[0], type: f[1], uid: f[2], dbg_name: f[3] };
}); });
this.fs = state[9]; this.fs.set_state(state[9]);
}; };
// Note: dbg_name is only used for debugging messages and may not be the same as the filename, // Note: dbg_name is only used for debugging messages and may not be the same as the filename,

View file

@ -424,7 +424,11 @@ Inode.prototype.get_state = function()
Inode.prototype.set_state = function(state) Inode.prototype.set_state = function(state)
{ {
this.updatedir = state[0]; this.updatedir = state[0];
this.direntries = new Map(state[1]); this.direntries = new Map();
for(const [name, entry] of state[1])
{
this.direntries.set(name, entry);
}
this.locks = []; this.locks = [];
for(const lock_state of state[2]) for(const lock_state of state[2])
{ {

View file

@ -450,26 +450,26 @@ CPU.prototype.set_state = function(state)
this.set_tsc(state[43][0], state[43][1]); this.set_tsc(state[43][0], state[43][1]);
this.devices.virtio_9p = state[45]; this.devices.virtio_9p && this.devices.virtio_9p.set_state(state[45]);
this.devices.apic = state[46]; this.devices.apic && this.devices.apic.set_state(state[46]);
this.devices.rtc = state[47]; this.devices.rtc && this.devices.rtc.set_state(state[47]);
this.devices.pci = state[48]; this.devices.pci && this.devices.pci.set_state(state[48]);
this.devices.dma = state[49]; this.devices.dma && this.devices.dma.set_state(state[49]);
this.devices.acpi = state[50]; this.devices.acpi && this.devices.acpi.set_state(state[50]);
this.devices.hpet = state[51]; this.devices.hpet && this.devices.hpet.set_state(state[51]);
this.devices.vga = state[52]; this.devices.vga && this.devices.vga.set_state(state[52]);
this.devices.ps2 = state[53]; this.devices.ps2 && this.devices.ps2.set_state(state[53]);
this.devices.uart = state[54]; this.devices.uart && this.devices.uart.set_state(state[54]);
this.devices.fdc = state[55]; this.devices.fdc && this.devices.fdc.set_state(state[55]);
this.devices.cdrom = state[56]; this.devices.cdrom && this.devices.cdrom.set_state(state[56]);
this.devices.hda = state[57]; this.devices.hda && this.devices.hda.set_state(state[57]);
this.devices.pit = state[58]; this.devices.pit && this.devices.pit.set_state(state[58]);
this.devices.net = state[59]; this.devices.net && this.devices.net.set_state(state[59]);
this.devices.pic = state[60]; this.devices.pic && this.devices.pic.set_state(state[60]);
this.fw_value = state[62]; this.fw_value = state[62];
this.devices.ioapic = state[63]; this.devices.ioapic && this.devices.ioapic.set_state(state[63]);
this.tss_size_32[0] = state[64]; this.tss_size_32[0] = state[64];

View file

@ -433,8 +433,8 @@ IDEDevice.prototype.get_state = function()
IDEDevice.prototype.set_state = function(state) IDEDevice.prototype.set_state = function(state)
{ {
this.master = state[0]; this.master.set_state(state[0]);
this.slave = state[1]; this.slave.set_state(state[1]);
this.ata_port = state[2]; this.ata_port = state[2];
this.irq = state[3]; this.irq = state[3];
this.pci_id = state[4]; this.pci_id = state[4];
@ -2079,5 +2079,5 @@ IDEInterface.prototype.set_state = function(state)
this.data16 = new Uint16Array(this.data.buffer); this.data16 = new Uint16Array(this.data.buffer);
this.data32 = new Int32Array(this.data.buffer); this.data32 = new Int32Array(this.data.buffer);
this.buffer = state[28]; this.buffer && this.buffer.set_state(state[28]);
}; };

View file

@ -413,7 +413,7 @@ PIC.prototype.set_state = function(state)
this.isr = state[2]; this.isr = state[2];
this.irr = state[3]; this.irr = state[3];
this.is_master = state[4]; this.is_master = state[4];
this.slave = state[5]; this.slave && this.slave.set_state(state[5]);
this.expect_icw4 = state[6]; this.expect_icw4 = state[6];
this.state = state[7]; this.state = state[7];
this.read_isr = state[8]; this.read_isr = state[8];

View file

@ -90,82 +90,42 @@ function save_object(obj, saved_buffers)
return result; return result;
} }
const NO_BASE = Object.freeze({}); function restore_buffers(obj, buffers)
function restore_object(base, obj, buffers)
{ {
// recursively restore obj into base
if(typeof obj !== "object" || obj === null) if(typeof obj !== "object" || obj === null)
{ {
dbg_assert(typeof obj !== "function"); dbg_assert(typeof obj !== "function");
return obj; return obj;
} }
if((base instanceof Array || base === NO_BASE) && obj instanceof Array) if(obj instanceof Array)
{ {
return obj.map(x => restore_object(NO_BASE, x, buffers)); for(let i = 0; i < obj.length; i++)
{
obj[i] = restore_buffers(obj[i], buffers);
}
return obj;
} }
var type = obj["__state_type__"]; const type = obj["__state_type__"];
dbg_assert(type !== undefined);
if(type === undefined) const constructor = CONSTRUCTOR_TABLE[type];
dbg_assert(constructor, "Unkown type: " + type);
const info = buffers.infos[obj["buffer_id"]];
// restore large buffers by just returning a view on the state blob
// get_state is responsible for copying the data
if(info.length >= 1024 * 1024 && constructor === Uint8Array)
{ {
if(DEBUG && base === undefined) return new Uint8Array(buffers.full, info.offset, info.length);
{
console.log("Cannot restore (base doesn't exist)", obj);
dbg_assert(false);
}
if(DEBUG && !base.get_state)
{
console.log("No get_state:", base);
}
var current = base.get_state();
dbg_assert(current.length === obj.length, "Cannot restore: Different number of properties");
for(var i = 0; i < obj.length; i++)
{
obj[i] = restore_object(current[i], obj[i], buffers);
}
base.set_state(obj);
return base;
} }
else else
{ {
var constructor = CONSTRUCTOR_TABLE[type]; var buf = buffers.full.slice(info.offset, info.offset + info.length);
dbg_assert(constructor, "Unkown type: " + type); return new constructor(buf);
var info = buffers.infos[obj["buffer_id"]];
// restore large buffers by just returning a view on the state blob
if(info.length >= 1024 * 1024 && constructor === Uint8Array)
{
return new Uint8Array(buffers.full, info.offset, info.length);
}
// XXX: Disabled, unpredictable since it updates in-place, breaks pci
// and possibly also breaks restore -> save -> restore again
// avoid a new allocation if possible
//else if(base &&
// base.constructor === constructor &&
// base.byteOffset === 0 &&
// base.byteLength === info.length)
//{
// new Uint8Array(base.buffer).set(
// new Uint8Array(buffers.full, info.offset, info.length),
// base.byteOffset
// );
// return base;
//}
else
{
var buf = buffers.full.slice(info.offset, info.offset + info.length);
return new constructor(buf);
}
} }
} }
@ -315,5 +275,6 @@ CPU.prototype.restore_state = function(state)
infos: buffer_infos, infos: buffer_infos,
}; };
restore_object(this, state_object, buffers); state_object = restore_buffers(state_object, buffers);
this.set_state(state_object);
}; };

View file

@ -923,7 +923,12 @@ VirtIO.prototype.set_state = function(state)
this.config_generation = state[7]; this.config_generation = state[7];
this.isr_status = state[8]; this.isr_status = state[8];
this.queue_select = state[9]; this.queue_select = state[9];
this.queues = state.slice(10); let i = 0;
for(let queue of state.slice(10))
{
this.queues[i].set_state(queue);
i++;
}
this.queue_selected = this.queues[this.queue_select] || null; this.queue_selected = this.queues[this.queue_select] || null;
}; };