Commits

Dean Hall  committed 50b6b60

#180 mainlined directly

  • Participants
  • Parent commits 6f122ac

Comments (0)

Files changed (14)

 	$(TAGS) -R *
 	$(CSCOPE) -b -c -R
 	cd src/tools && $(PYCSCOPE) *.py
-	cd src/lib && $(PYCSCOPE) *.py
+#	cd src/lib && $(PYCSCOPE) *.py
 
 dist :
 ifndef PM_RELEASE

File src/lib/__bi.py

 
     /* Raise ValueError if arg is not a string */
     pimg = NATIVE_GET_LOCAL(0);
-    if (OBJ_GET_TYPE(pimg) != OBJ_TYPE_STR)
+    if (OBJ_GET_TYPE(pimg) != OBJ_TYPE_CIO)
     {
         PM_RAISE(retval, PM_RET_EX_VAL);
         return retval;
 
     /* Create a code object from the image */
     imgaddr = (uint8_t *)&((pPmString_t)pimg)->val;
-    retval = obj_loadFromImg(MEMSPACE_RAM, &imgaddr, &pco);
+    retval = obj_loadFromImgObj(pimg, &pco);
     PM_RETURN_IF_ERROR(retval);
 
     /* Return the code object */

File src/lib/ipm.py

     uint8_t imgType;
     uint16_t imgSize;
     uint8_t *pchunk;
-    pPmString_t pimg;
+    pPmCodeImgObj_t pimg;
     uint16_t i;
     uint8_t b;
 
     PM_RETURN_IF_ERROR(retval);
     imgSize |= (b << 8);
 
-    /* Get space for String obj */
-    retval = heap_getChunk(sizeof(PmString_t) + imgSize, &pchunk);
+    /* Get space for CodeImgObj */
+    retval = heap_getChunk(sizeof(PmCodeImgObj_t) + imgSize, &pchunk);
     PM_RETURN_IF_ERROR(retval);
-    pimg = (pPmString_t)pchunk;
-
-    /* Set the string object's fields */
-    OBJ_SET_TYPE(pimg, OBJ_TYPE_STR);
-    pimg->length = imgSize;
+    pimg = (pPmCodeImgObj_t)pchunk;
+    OBJ_SET_TYPE(pimg, OBJ_TYPE_CIO);
 
     /* Start the image with the bytes that have already been received */
     i = 0;
     while 1:
         # Wait for a code image, make a code object from it
         # and evaluate the code object.
-        rv = eval(Co(_getImg()), g)
+        # #180: One-liner turned into 3 so that objects get bound to roots
+        s = _getImg()
+        co = Co(s)
+        rv = eval(co, g)
 
         # Send a byte to indicate completion of evaluation
         print '\x04',
 
-#:mode=c:
+# :mode=c:

File src/tests/system/t071.c

-/*
- * PyMite - A flyweight Python interpreter for 8-bit and larger microcontrollers.
- * Copyright 2002 Dean Hall.  All rights reserved.
- * PyMite is offered through one of two licenses: commercial or open-source.
- * See the LICENSE file at the root of this package for licensing details.
- */
-
-/**
- * System Test 071
- * Tests implementation of builtin function eval()
- */
-
-#include "pm.h"
-
-
-extern unsigned char usrlib_img[];
-
-
-int main(void)
-{
-    PmReturn_t retval;
-
-    retval = pm_init(MEMSPACE_PROG, usrlib_img);
-    PM_RETURN_IF_ERROR(retval);
-
-    retval = pm_run((uint8_t *)"t071");
-    return (int)retval;
-}

File src/tests/system/t071.c.deprecated_by_#180

+/*
+ * PyMite - A flyweight Python interpreter for 8-bit and larger microcontrollers.
+ * Copyright 2002 Dean Hall.  All rights reserved.
+ * PyMite is offered through one of two licenses: commercial or open-source.
+ * See the LICENSE file at the root of this package for licensing details.
+ */
+
+/**
+ * System Test 071
+ * Tests implementation of builtin function eval()
+ */
+
+#include "pm.h"
+
+
+extern unsigned char usrlib_img[];
+
+
+int main(void)
+{
+    PmReturn_t retval;
+
+    retval = pm_init(MEMSPACE_PROG, usrlib_img);
+    PM_RETURN_IF_ERROR(retval);
+
+    retval = pm_run((uint8_t *)"t071");
+    return (int)retval;
+}

File src/tools/pmHeapDump.py

+#!/usr/bin/env python
+
+#
+# PyMite - A flyweight Python interpreter for 8-bit and larger microcontrollers.
+# Copyright 2002 Dean Hall.  All rights reserved.
+# PyMite is offered through one of two licenses: commercial or open-source.
+# See the LICENSE file at the root of this package for licensing details.
+#
+
+"""
+PyMite Heap Dump
+================
+
+Parses a heap dump into human-readable format.
+
+The heap dump file is created by inserting a calls to heap_dump()
+inside heap_gcRun().  Using two calls, a before and after, is ideal.
+
+The dump format is:
+
+=========== ==========================================
+NumBytes    Contents
+=========== ==========================================
+4           int: HEAP_SIZE
+4           Pointer to heap_base
+HEAP_SIZE   contents of heap (byte array)
+4           int: NUM_ROOTS
+NUM_ROOTS*4 Pointers to roots
+=========== ==========================================
+
+The heap_dump() function names files incrementally starting from:
+
+    pmheapdump00.bin
+    pmheapdump01.bin
+    ...
+    pmheapdumpNN.bin
+"""
+
+
+__usage__ = """USAGE:
+    pmHeapDiff.py filename
+    """
+
+
+import struct, sys, types, UserDict
+
+
+class PmObject(UserDict.UserDict):
+    """A model of an object.
+    """
+
+    PM_TYPES = ("NON", "INT", "FLT", "STR", "TUP", "COB", "MOD", "CLO", "FXN",
+        "CLI", "CIM", "NIM", "NOB", "THR", "EXN", "BOL", "CIO", "LST", "DIC",
+        "x", "x", "x", "x", "x", "x",
+        "FRM", "BLK", "SEG", "SGL", "SQI", "NFM", )
+
+
+    def _parse_int(self,):
+        addr = self.addr + 4
+        self.data['val'] = struct.unpack("i", self.heap[addr : addr + 4])[0]
+
+
+    def _parse_str(self,):
+        d = self.data
+        addr = self.addr + 2
+        d['len'] = strlen = struct.unpack("H", self.heap[addr : addr + 2])[0]
+        d['cache_next'] = struct.unpack("P", self.heap[addr + 2 : addr + 6])[0]
+        d['val'] = self.heap[addr + 6: addr + 6 + strlen]
+
+
+    def _parse_lst(self,):
+        addr = self.addr + 2
+        self.data['len'] = struct.unpack("H", self.heap[addr : addr + 2])[0]
+        self.data['sgl'] = struct.unpack("P", self.heap[addr + 2 : addr + 6])[0]
+
+
+    def _parse_free(self,):
+        addr = self.addr + 2
+        self.data['prev'] = struct.unpack("P", self.heap[addr : addr + 4])[0]
+        self.data['next'] = struct.unpack("P", self.heap[addr + 4 : addr + 8])[0]
+
+
+    _parse_nul = lambda x: x
+    parse = (_parse_nul, _parse_int, _parse_nul, _parse_str,
+             _parse_nul, _parse_nul, _parse_nul, _parse_nul,
+             _parse_nul, _parse_nul, _parse_nul, _parse_nul,
+             _parse_nul, _parse_nul, _parse_nul, _parse_nul,
+             _parse_lst, _parse_nul, _parse_nul, _parse_nul,
+             _parse_nul, _parse_nul, _parse_nul, _parse_nul,
+             _parse_nul, _parse_nul, _parse_nul, _parse_nul,
+             _parse_nul, _parse_nul, _parse_nul, _parse_nul, )
+
+
+    def __init__(self, heap, addr):
+        """Initialize the object based on the given string from the dump file.
+        """
+        UserDict.UserDict.__init__(self)
+
+        d = self.data
+
+        self.heap = heap
+        self.addr = addr
+
+        od = struct.unpack("H", heap[addr : addr + 2])[0]
+        d['mark'] = (' ','M')[(od & 0x4000) == 0x4000]
+        d['free'] = (' ','F')[(od & 0x8000) == 0x8000]
+        d['val'] = None
+
+        if d['free'] == 'F':
+            d['size'] = (od & 0x3FFF) << 2
+            d['type'] = "fre"
+            PmObject._parse_free(self)
+
+        else:
+            size = (od & 0x01FF) << 2
+            assert size > 0
+            typeindex = (od >> 9) & 0x1f
+            objtype = PmObject.PM_TYPES[typeindex]
+            d['size'] = size
+            d['type'] = objtype
+            PmObject.parse[typeindex](self)
+
+
+    def __str__(self,):
+        """The printable representation of the object.
+        """
+        d = self.data
+        result = []
+        result.append("%s %s %d %s%s: " % (
+            hex(self.addr),
+            d['type'],
+            d['size'],
+            d['mark'],
+            d['free'],))
+
+        if d['type'] == "fre":
+            result.append("next=%s, prev=%s" % (hex(d['next']), hex(d['prev'])))
+
+        elif d['type'] == "INT":
+            result.append("%d" % d['val'])
+
+        elif d['type'] == "STR":
+            result.append("cache_next=%s : %s" % (hex(d['cache_next']), str(d['val'])))
+
+        return "".join(result)
+
+
+class PmHeap(UserDict.UserDict):
+    """A model of the heap.
+    """
+
+    def __init__(self, fn):
+        """Initialize the heap based on the given dump file.
+        """
+        UserDict.UserDict.__init__(self)
+
+        self.is_parsed = False
+
+        fp = open(fn, "rb")
+        s = fp.read()
+        fp.close()
+
+        self.size = size = struct.unpack("i", s[:4])[0]
+        self.base = struct.unpack("P", s[4 : 8])[0]
+        self.rawheap = s[8 : size + 8]
+
+        num_roots = struct.unpack("i", s[size + 8 : size + 12])[0]
+        roots = {}
+        (roots['None'],
+         roots['False'],
+         roots['True'],
+         roots['Zero'],
+         roots['One'],
+         roots['NegOne'],
+         roots['CodeStr'],
+         roots['Builtins'],
+         roots['NativeFrame'],
+         roots['ThreadList']) = struct.unpack("%dP" % num_roots, s[size + 12:])
+        self.roots = roots
+
+
+    def __getitem__(self, indx):
+        """Returns the object at the given address
+        or the string of bytes defined by the slice.
+        """
+        # Return the object at the given address
+        if type(indx) == types.IntType:
+            if is_parsed:
+                return self.data[indx]
+            else:
+                return PmObject(self, indx)
+
+        # Return the string of bytes defined by the slice
+        elif type(indx) == types.SliceType:
+            return self.rawheap[indx.start - self.base : indx.stop - self.base]
+
+        else:
+            assert False, "Bad type to heap[%s]" % type(indx)
+
+
+    def parse_heap(self,):
+        """Parse the heap into a dict of key=address, value=object items
+        """
+        d = self.data
+
+        addr = self.base
+        end = addr + self.size
+        while addr < end:
+            d[addr] = obj = PmObject(self, addr)
+            d[addr] = obj
+            addr += obj['size']
+            print obj
+        self.is_parsed = True
+
+
+def main():
+    if len(sys.argv) < 2:
+        fn = os.path.join(os.path.curdir, "pmheapdump00.bin")
+    elif len(sys.argv) == 2:
+        fn = sys.argv[1]
+    else:
+        print __usage__
+        sys.exit()
+
+    heap0 = PmHeap(fn)
+    heap0.parse_heap()
+
+if __name__ == "__main__":
+    main()

File src/vm/codeobj.h

     PmObjDesc_t od;
     /** memory space selector */
     PmMemSpace_t co_memspace:8;
-    /** address in memspace of code image */
+    /** address in progmem of the code image, or of code img obj in heap */
     uint8_t const *co_codeimgaddr;
     /** address in RAM of names tuple */
     pPmTuple_t co_names;

File src/vm/frame.c

     }
 
     /* Get sizes needed to calc frame size */
-    paddr = pco->co_codeimgaddr + CI_STACKSIZE_FIELD;
+    if (pco->co_memspace == MEMSPACE_RAM)
+    {
+        paddr = (uint8_t *)((pPmCodeImgObj_t)pco->co_codeimgaddr)->val + CI_STACKSIZE_FIELD;
+    }
+    else
+    {
+        paddr = pco->co_codeimgaddr + CI_STACKSIZE_FIELD;
+    }
     stacksz = mem_getByte(pco->co_memspace, &paddr);
 
     /* Now paddr points to CI_NLOCALS_FIELD */

File src/vm/heap.c

 #endif
 
 
+#if 0
+/** DEBUG: dumps the heap and roots list to a file */
+static void
+heap_dump(void)
+{
+    static int n = 0;
+    int i;
+    char filename[32];
+    FILE *fp;
+
+    snprintf(filename, 32, "pmheapdump%02d.bin", n++);
+    fp = fopen(filename, "wb");
+
+    /* Write size of heap */
+    i = HEAP_SIZE;
+    fwrite(&i, sizeof(int), 1, fp);
+
+    /* Write base address of heap */
+    i = (int)&pmHeap.base;
+    fwrite(&i, sizeof(int *), 1, fp);
+
+    /* Write contents of heap */
+    fwrite(&pmHeap.base, 1, HEAP_SIZE, fp);
+
+    /* Write num roots*/
+    i = 10;
+    fwrite(&i, sizeof(int), 1, fp);
+
+    /* Write heap root ptrs */
+    fwrite((void *)&gVmGlobal.pnone, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pfalse, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.ptrue, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pzero, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pone, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pnegone, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.pcodeStr, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.builtins, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.nativeframe, sizeof(intptr_t), 1, fp);
+    fwrite((void *)&gVmGlobal.threadList, sizeof(intptr_t), 1, fp);
+    fclose(fp);
+}
+#endif
+
+
 /* Removes the given chunk from the free list; leaves list in sorted order */
 static PmReturn_t
 heap_unlinkFromFreelist(pPmHeapDesc_t pchunk)
         case OBJ_TYPE_STR:
         case OBJ_TYPE_NOB:
         case OBJ_TYPE_BOOL:
+        case OBJ_TYPE_CIO:
             OBJ_SET_GCVAL(pobj, pmHeap.gcval);
             break;
 
             /* #122: Mark the code image if it is in RAM */
             if (((pPmCo_t)pobj)->co_memspace == MEMSPACE_RAM)
             {
-                /* Special case: The image is contained in a string object */
                 retval = heap_gcMarkObj((pPmObj_t)
-                                        (((pPmCo_t)pobj)->co_codeimgaddr
-                                         - sizeof(PmObjDesc_t)));
+                                        (((pPmCo_t)pobj)->co_codeimgaddr));
             }
             break;
 
     PmReturn_t retval;
 
     C_DEBUG_PRINT(VERBOSITY_LOW, "heap_gcRun()\n");
+    /*heap_dump();*/
 
     retval = heap_gcMarkRoots();
     PM_RETURN_IF_ERROR(retval);
 
     retval = heap_gcSweep();
+    /*heap_dump();*/
     return retval;
 }
 

File src/vm/heap.h

  * The threshold of heap.avail under which the interpreter will run the GC
  * just before starting a native session.
  */
-#define HEAP_GC_NF_THRESHOLD (1024)
+#define HEAP_GC_NF_THRESHOLD (512)
 
 
 #ifdef __DEBUG__

File src/vm/img.h

 
 
 /**
+ * Code image object
+ *
+ * A type to hold code images in the heap.
+ * A code image with an object descriptor at the front.
+ * Used for storing image objects during ipm;
+ * the code object keeps a reference to this object.
+ */
+typedef struct PmCodeImgObj_s
+{
+    /** Object descriptor */
+    PmObjDesc_t od;
+
+    /** Null-term? char array */
+    uint8_t val[1];
+} PmCodeImgObj_t,
+ *pPmCodeImgObj_t;
+
+
+/**
  * Iterates over all paths in the paths array until the named module is found.
  * Returns the memspace,address of the head of the module.
  *

File src/vm/obj.c

 }
 
 
+PmReturn_t
+obj_loadFromImgObj(pPmObj_t pimg, pPmObj_t *r_pobj)
+{
+    uint8_t const *imgaddr;
+    PmReturn_t retval;
+
+    C_ASSERT(OBJ_GET_TYPE(pimg) == OBJ_TYPE_CIO);
+    imgaddr = (uint8_t const *)&(((pPmCodeImgObj_t)pimg)->val);
+
+    retval = obj_loadFromImg(MEMSPACE_RAM, &imgaddr, r_pobj);
+    C_ASSERT(OBJ_GET_TYPE(*r_pobj) == OBJ_TYPE_COB);
+
+    /* The CO must reference the top of the code img obj */
+    ((pPmCo_t)*r_pobj)->co_codeimgaddr = (uint8_t const *)pimg;
+
+    return retval;
+}
+
+
 /* Returns true if the obj is false */
 int8_t
 obj_isFalse(pPmObj_t pobj)

File src/vm/obj.h

     /** Boolean object */
     OBJ_TYPE_BOOL = 0x0F,
 
+    /** Code image object */
+    OBJ_TYPE_CIO = 0x10,
+    
     /* All types after this are not hashable */
-    OBJ_TYPE_HASHABLE_MAX = 0x0F,
+    OBJ_TYPE_HASHABLE_MAX = 0x10,
 
     /** List (mutable sequence) */
-    OBJ_TYPE_LST = 0x10,
+    OBJ_TYPE_LST = 0x11,
 
     /** Dictionary (hash table) */
-    OBJ_TYPE_DIC = 0x11,
+    OBJ_TYPE_DIC = 0x12,
 
     /* All types after this are not accessible to the user */
     OBJ_TYPE_ACCESSIBLE_MAX = 0x19,
 PmReturn_t obj_loadFromImg(PmMemSpace_t memspace,
                            uint8_t const **paddr, pPmObj_t *r_pobj);
 
+/** 
+ * Loads a code object from a code image object
+ *
+ * @param pimg Ptr to a code image object
+ * @param r_pobj Return arg, the loaded object
+ * @return  Returns status
+ */
+PmReturn_t obj_loadFromImgObj(pPmObj_t pimg, pPmObj_t *r_pobj);
+
 /**
  * Finds the boolean value of the given object.
  *

File src/vm/tuple.c

         return retval;
     }
 
-    /* Calc size of struct to hold tuple */
-    size = sizeof(PmTuple_t) + (n * sizeof(pPmObj_t));
+    /* Calc size of struct to hold tuple; (n-1) because PmTuple_t has val[1] */
+    size = sizeof(PmTuple_t) + ((n - 1) * sizeof(pPmObj_t));
 
     /* Allocate a tuple */
     retval = heap_getChunk(size, (uint8_t **)r_ptuple);