Browse Source

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

Fabian 3 years ago
parent
commit
cd3f48c0a3
7 changed files with 54 additions and 84 deletions
  1. 2 2
      lib/9p.js
  2. 5 1
      lib/filesystem.js
  3. 17 17
      src/cpu.js
  4. 3 3
      src/ide.js
  5. 1 1
      src/pic.js
  6. 20 59
      src/state.js
  7. 6 1
      src/virtio.js

+ 2 - 2
lib/9p.js

@@ -190,7 +190,7 @@ Virtio9p.prototype.set_state = function(state)
 {
     this.configspace_tagname = state[0];
     this.configspace_taglen = state[1];
-    this.virtio = state[2];
+    this.virtio.set_state(state[2]);
     this.virtqueue = this.virtio.queues[0];
     this.VERSION = state[3];
     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] };
     });
-    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,

+ 5 - 1
lib/filesystem.js

@@ -424,7 +424,11 @@ Inode.prototype.get_state = function()
 Inode.prototype.set_state = function(state)
 {
     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 = [];
     for(const lock_state of state[2])
     {

+ 17 - 17
src/cpu.js

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

+ 3 - 3
src/ide.js

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

+ 1 - 1
src/pic.js

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

+ 20 - 59
src/state.js

@@ -90,82 +90,42 @@ function save_object(obj, saved_buffers)
     return result;
 }
 
-const NO_BASE = Object.freeze({});
-
-function restore_object(base, obj, buffers)
+function restore_buffers(obj, buffers)
 {
-    // recursively restore obj into base
-
     if(typeof obj !== "object" || obj === null)
     {
         dbg_assert(typeof obj !== "function");
         return obj;
     }
 
-    if((base instanceof Array || base === NO_BASE) && obj instanceof Array)
-    {
-        return obj.map(x => restore_object(NO_BASE, x, buffers));
-    }
-
-    var type = obj["__state_type__"];
-
-    if(type === undefined)
+    if(obj instanceof Array)
     {
-        if(DEBUG && base === undefined)
+        for(let i = 0; i < obj.length; i++)
         {
-            console.log("Cannot restore (base doesn't exist)", obj);
-            dbg_assert(false);
+            obj[i] = restore_buffers(obj[i], buffers);
         }
 
-        if(DEBUG && !base.get_state)
-        {
-            console.log("No get_state:", base);
-        }
-
-        var current = base.get_state();
+        return obj;
+    }
 
-        dbg_assert(current.length === obj.length, "Cannot restore: Different number of properties");
+    const type = obj["__state_type__"];
+    dbg_assert(type !== undefined);
 
-        for(var i = 0; i < obj.length; i++)
-        {
-            obj[i] = restore_object(current[i], obj[i], buffers);
-        }
+    const constructor = CONSTRUCTOR_TABLE[type];
+    dbg_assert(constructor, "Unkown type: " + type);
 
-        base.set_state(obj);
+    const info = buffers.infos[obj["buffer_id"]];
 
-        return base;
+    // 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)
+    {
+        return new Uint8Array(buffers.full, info.offset, info.length);
     }
     else
     {
-        var constructor = CONSTRUCTOR_TABLE[type];
-        dbg_assert(constructor, "Unkown type: " + type);
-
-        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);
-        }
+        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,
     };
 
-    restore_object(this, state_object, buffers);
+    state_object = restore_buffers(state_object, buffers);
+    this.set_state(state_object);
 };

+ 6 - 1
src/virtio.js

@@ -923,7 +923,12 @@ VirtIO.prototype.set_state = function(state)
     this.config_generation = state[7];
     this.isr_status = state[8];
     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;
 };