Commits

Anonymous committed 0279163

46: Mainlining directly

Comments (0)

Files changed (36)

docs/src/StringObjects.txt

+.. Copyright 2007 Dean Hall
+   Permission is granted to copy, distribute and/or modify this document
+   under the terms of the GNU Free Documentation License, Version 1.2
+   or any later version published by the Free Software Foundation;
+   with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+   Texts.  A copy of the license is in the file docs/LICENSE.
+
+=====================
+PyMite String Objects
+=====================
+
+:Author:    Dean Hall
+:Id:        $Id$
+
+Purpose
+-------
+
+This document describes the String object as used in the PyMite virtual machine
+(VM).  In doing so, it serves as a design document for the PyMite developer
+and a reference for the PyMite user.
+
+Overview
+--------
+
+PyMite shall define the C data type ``PmString_t`` as the general type for
+the String object used by the VM.  String objects are used routinely throughout
+the VM and character strings are often passed between the VM and native code in
+both directions.  The design of the String object is important both inside and
+outside the VM.
+
+Background
+----------
+
+The author has a history with the J2ME_ VM, inside which strings did not have
+null terminators.  The author ported J2ME to a number of platforms whose string
+routines required null terminators.  For these platforms, the solution was to
+copy the contents of the VM string to a buffer and append a null character.
+This solution slowed the resulting system and added to its memory requirements.
+
+.. _J2ME: http://en.wikipedia.org/wiki/J2ME
+
+Object Details
+--------------
+
+The ``PmString_t`` data type shall represent a PyMite String object and shall
+contain an object descriptor, an unsigned  16-bit integer to represent the
+string's length and a variable number of bytes to contain the contents of the
+string itself.  The bytes that make up the string shall have at least one null
+character '\\0' (0x00) following the last intended character.  Python String
+objects may intentionally contain any number of null characters, so in the
+byte representation of the String object, a null character does not always
+imply the end of the character array.
+
+String objects are of dynamic length.  A string's maximum length is limited by
+the heap implementation.  As of this writing (2007/04), the maximum heap chunk
+size is 1020 bytes.  Up to eight bytes are used by the ``PmString_t`` on 32-bit
+systems.  Subtract a null terminator and PyMite strings can be a maximum of 1011
+characters.  However, when using Interactive PyMite (ipm), a string is packaged
+inside a code object and that code object must fit within the maximum chunk
+size.  So the effective string length in ipm is smaller than 1011.
+
+In the ``PmString_t`` data type, a character array field is declared.  Since
+C type declarations must be of constant size and an array of zero characters is
+not allowed by some compilers, this field is declared as an array of one
+character.  This has a nice side effect that when creating a String object,
+the length of the string is added to the size of the ``PmString_t`` struct.
+The "extra" byte in the resulting size holds the null terminator.
+
+In Python, String objects are used to represent names.  Object linking is not
+necessary in Python because name lookup is used to access external modules,
+global variables and other objects.  This means that there are often two
+instances of every String object: one in the provider object and one in
+the user object.  A String object caching mechanism is implemented as a compile
+time option.  The String object cache shall conserve heap memory by having all
+instances of an identical String object refer to one common String object.
+
+PyMite used to declare support for international character sets using UTF-8
+character strings.  This is no longer true.  PyMite only supports 8-bit ASCII
+characters.
+
+Design Decisions
+----------------
+
+Inside the VM, string objects are used very often as are the numerical length
+of those strings.  I chose to use a field to store the string's length as an
+optimization so that the string's length does not need to be measured every time
+the length is needed.  However, I do not intend for the string's length to be
+used to determine where the character array ends.
+
+The String object shall have a null character at the end of the array
+of characters.  This is done so that PyMite string objects are compatible with
+general C string libraries and can avoid the troubles explained above in
+Background_.  Note that Python String objects can contain null characters
+anywhere within the string and this may cause C string libraries to not work
+properly on those String objects.
+
+The choice to add a String object cache was easy.  Without it, PyMite exhausts
+a 4 KiB heap during system start-up before any user code is executed.
+
+PyMite dropped the goal of supporting UTF-8 characters because there was never
+a demand for UTF-8 support from a user and the complication of UTF-8 support
+does not justify its exestince.
+
+.. :mode=rest:
     }
 
     /* Create char string from  integer value */
-    retval = string_newFromChar((uint8_t)n, &ps);
+    retval = string_newFromChar((uint8_t const)n, &ps);
     NATIVE_SET_TOS(ps);
     return retval;
     """
     PmReturn_t retval;
     pPmObj_t pimg;
     pPmObj_t pco;
-    uint8_t *imgaddr;
+    uint8_t const *imgaddr;
 
     /* If wrong number of args, raise TypeError */
     if (NATIVE_GET_NUM_ARGS() != 1)

src/tests/system/t006.c

 
 int main(void)
 {
-    uint8_t *pimg;
+    uint8_t const *pimg;
     PmReturn_t retval = PM_RET_OK;
 
     heap_init();

src/tests/system/t026.py

 #
 
 #
+# Test len()
+#
+assert len("") == 0
+assert len("\x00") == 1
+assert len("\x00\x00\x00\x00") == 4
+
+#
 # Test ord()
 #
 c = ord("t")
 c = ord("\xff")
 assert c == 0xff
 
-c = ord("\0")
+c = ord("\x00")
 assert c == 0
 
 
 # Test chr()
 #
 n = chr(0)
-assert n == "\0"
+assert n == "\x00"
 
 n = chr(255)
 assert n == "\xff"

src/tests/system/t075.c

     pPmObj_t pmodA;
     pPmObj_t pmodB;
     pPmObj_t pstring;
-    uint8_t *pmodstrA = (uint8_t*)"t075a";
-    uint8_t *pmodstrB = (uint8_t*)"t075b";
+    uint8_t const *pmodstrA = (uint8_t const *)"t075a";
+    uint8_t const *pmodstrB = (uint8_t const *)"t075b";
 
     retval = pm_init(MEMSPACE_PROG, usrlib_img);
     PM_RETURN_IF_ERROR(retval);

src/tests/unit/ut_codeobj.c

 main()
 
  */
-uint8_t test_code_image0[] =
+uint8_t const test_code_image0[] =
 {
     0x0A, 0xFB, 0x00, 0x00, 0x01, 0x00, 0x04, 0x02, 
     0x03, 0x04, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x03, 
 ut_co_loadFromImg_000(CuTest *tc)
 {
     PmReturn_t retval;
-    uint8_t *paddr = test_code_image0;
-    uint8_t *pimg = test_code_image0;
+    uint8_t const *paddr = test_code_image0;
+    uint8_t const *pimg = test_code_image0;
     pPmObj_t pcodeobject;
     uint16_t size;
     

src/tests/unit/ut_dict.c

     
     retval = pm_init(MEMSPACE_RAM, C_NULL);
     
-    retval = string_new((uint8_t **)&test_str1, &p_firstval);
-    retval = string_new((uint8_t **)&test_str2, &p_secondval);
-    retval = string_new((uint8_t **)&test_str3, &p_thirdval);
-    retval = string_new((uint8_t **)&test_strnew, &p_newval);
+    retval = string_new((uint8_t const **)&test_str1, &p_firstval);
+    retval = string_new((uint8_t const **)&test_str2, &p_secondval);
+    retval = string_new((uint8_t const **)&test_str3, &p_thirdval);
+    retval = string_new((uint8_t const **)&test_strnew, &p_newval);
     
     retval = int_new(1, (pPmObj_t *)&p_firstkey);
     retval = int_new(2, (pPmObj_t *)&p_secondkey);

src/tests/unit/ut_func.c

 ut_func_new_000(CuTest *tc)
 {
     PmReturn_t retval;
-    uint8_t *pimg = test_code_image0;
+    uint8_t const *pimg = test_code_image0;
     pPmObj_t pcodeobject;
     pPmObj_t pfuncobject;
     pPmObj_t pglobals;

src/tests/unit/ut_interp.c

 ut_interp_interpret_000(CuTest *tc)
 {
     PmReturn_t retval;
-    uint8_t *pimg = test_code_image0;
+    uint8_t const *pimg = test_code_image0;
     pPmObj_t pcodeobject;
     pPmObj_t pmodule;
     uint16_t size;

src/tests/unit/ut_string.c

     pPmObj_t pstring;
     uint16_t length;
     uint8_t cstring[] = "forty-two";
-    uint8_t *pcstring = cstring;
+    uint8_t const *pcstring = cstring;
     PmReturn_t retval;
 
     pm_init(MEMSPACE_RAM, C_NULL);
 }
 
 
-/**
- * Tests string_copy():
- *      retval is OK
- *      string and its copy are the same
- */
-void
-ut_string_copy_000(CuTest *tc)
-{
-    pPmObj_t pstring;
-    pPmObj_t pstringcopy;
-    uint8_t cchar = 'Z';
-    PmReturn_t retval;
-
-    pm_init(MEMSPACE_RAM, C_NULL);
-
-    /* Check the return value is Ok */
-    retval = string_newFromChar(cchar, &pstring);
-    retval = string_copy(pstring, &pstringcopy);
-    CuAssertTrue(tc, retval == PM_RET_OK);
-    CuAssertTrue(tc, obj_compare(pstring, pstringcopy) == C_SAME);
-}
-
-
 /** Make a suite from all tests in this file */
 CuSuite *getSuite_testStringObj(void)
 {
 
     SUITE_ADD_TEST(suite, ut_string_new_000);
     SUITE_ADD_TEST(suite, ut_string_newFromChar_000);
-    SUITE_ADD_TEST(suite, ut_string_copy_000);
 
     return suite;
 }
  **************************************************************/
 
 PmReturn_t
-co_loadFromImg(PmMemSpace_t memspace, uint8_t **paddr, pPmObj_t *r_pco)
+co_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pco)
 {
     PmReturn_t retval = PM_RET_OK;
     pPmObj_t pobj;
     uint8_t *pchunk;
 
     /* store ptr to top of code img (less type byte) */
-    uint8_t *pci = *paddr - 1;
+    uint8_t const *pci = *paddr - 1;
 
     /* get size of code img */
     uint16_t size = mem_getWord(memspace, paddr);
 
 
 PmReturn_t
-no_loadFromImg(PmMemSpace_t memspace, uint8_t **paddr, pPmObj_t *r_pno)
+no_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pno)
 {
     PmReturn_t retval = PM_RET_OK;
     pPmNo_t pno = C_NULL;
     /** memory space selector */
     PmMemSpace_t co_memspace:8;
     /** address in memspace of code image */
-    uint8_t *co_codeimgaddr;
+    uint8_t const *co_codeimgaddr;
     /** address in RAM of names tuple */
     pPmTuple_t co_names;
     /** address in RAM of constants tuple */
     pPmTuple_t co_consts;
     /** address in memspace of bytecode (or native function) */
-    uint8_t *co_codeaddr;
+    uint8_t const *co_codeaddr;
 } PmCo_t,
  *pPmCo_t;
 
  * @return  Return status
  */
 PmReturn_t
-co_loadFromImg(PmMemSpace_t memspace, uint8_t **paddr, pPmObj_t *r_pco);
+co_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pco);
 
 /**
  * Create a Native code object by loading a native image.
  *          past end of code img
  */
 PmReturn_t no_loadFromImg(PmMemSpace_t memspace,
-                          uint8_t **paddr, pPmObj_t *r_pno);
+                          uint8_t const **paddr, pPmObj_t *r_pno);
 
 
 #endif /* __CODEOBJ_H__ */
     int8_t nlocals = (int8_t)0;
     pPmCo_t pco = C_NULL;
     pPmFrame_t pframe = C_NULL;
-    uint8_t *paddr = C_NULL;
+    uint8_t const *paddr = C_NULL;
     uint8_t *pchunk;
 
     /* get fxn's code obj */
  * Constants
  **************************************************************/
 
-/** 
- * the maximum number of local variables 
+/**
+ * the maximum number of local variables
  * a native function can have.
  * This defines the length of the locals array
  * in the native frame struct.
     /** ptr to backup stack ptr */
     pPmObj_t *b_sp;
     /** handler fxn obj */
-    uint8_t *b_handler;
+    uint8_t const *b_handler;
     /** block type */
     PmBlockType_t b_type:8;
     /** next block in stack */
     /** mem space where func's CO comes from */
     PmMemSpace_t fo_memspace:8;
     /** instrxn ptr (pts into memspace) */
-    uint8_t *fo_ip;
+    uint8_t const *fo_ip;
     /** current source line num */
     uint16_t fo_line;
     /** linked list of blocks */
 {
     PmReturn_t retval = PM_RET_OK;
     pPmObj_t pkey = C_NULL;
-    uint8_t *btstr = (uint8_t *)"__bt";
-    uint8_t *nmstr = (uint8_t *)"__nm";
+    uint8_t const *btstr = (uint8_t const *)"__bt";
+    uint8_t const *nmstr = (uint8_t const *)"__nm";
 
     /* ensure types */
     if ((OBJ_GET_TYPE(*pmeths) != OBJ_TYPE_DIC) ||
  * Constants
  **************************************************************/
 
-uint8_t *global_bistr = (uint8_t *)"__bi";
+uint8_t const *global_bistr = (uint8_t const *)"__bi";
 
 /***************************************************************
  * Macros
     OBJ_SET_SIZE(gVmGlobal.none, sizeof(PmObj_t));
 
     /* Init "code" string obj */
-    retval = string_new((uint8_t **)&codestr, &pobj);
+    retval = string_new((uint8_t const **)&codestr, &pobj);
     gVmGlobal.pcodeStr = (pPmString_t)pobj;
 
     /* init empty builtins */
 {
     PmReturn_t retval = PM_RET_OK;
     pPmObj_t pkey = C_NULL;
-    uint8_t *nonestr = (uint8_t *)"None";
+    uint8_t const *nonestr = (uint8_t const *)"None";
     pPmObj_t pstr = C_NULL;
     pPmObj_t pbimod;
 
  * without filling memory.
  */
 PmReturn_t
-img_findInMem(PmMemSpace_t memspace, uint8_t **paddr)
+img_findInMem(PmMemSpace_t memspace, uint8_t const **paddr)
 {
     PmReturn_t retval = PM_RET_ERR;
-    uint8_t *imgtop = 0;
+    uint8_t const *imgtop = (uint8_t const *)C_NULL;
     PmType_t type = 0;
     int16_t size = 0;
     uint8_t n = 0;
 
 PmReturn_t
 img_getName(PmMemSpace_t memspace,
-            uint8_t **paddr, uint8_t n, pPmObj_t *r_pname)
+            uint8_t const **paddr, uint8_t n, pPmObj_t *r_pname)
 {
     PmType_t type;
     uint16_t len;
     /** the memory space in which the image is located */
     PmMemSpace_t ii_memspace:8;
     /** the starting address of the image */
-    uint8_t *ii_addr;
+    uint8_t const *ii_addr;
     /** ptr to next image ID struct */
     struct PmImgInfo_s *next;
 } PmImgInfo_t,
  * @param   paddr ptr to address value to start search.
  * @return  Return status
  */
-PmReturn_t img_findInMem(PmMemSpace_t memspace, uint8_t **paddr);
+PmReturn_t img_findInMem(PmMemSpace_t memspace, uint8_t const **paddr);
 
 /**
  * Load a string obj from the names tuple at the given index.
  * @return  Return status
  */
 PmReturn_t img_getName(PmMemSpace_t memspace,
-                       uint8_t **paddr, uint8_t n, pPmObj_t *r_pname);
+                       uint8_t const **paddr, uint8_t n, pPmObj_t *r_pname);
 
 
 #endif /* __TEMPLATE_H__ */
                 /* get sequence */
                 pobj1 = PM_POP();
 
-                /* XXX if there's an seq_copy(), use here */
                 /* if it's a string */
                 if (OBJ_GET_TYPE(*pobj1) == OBJ_TYPE_STR)
                 {
-                    retval = string_copy(pobj1, &pobj2);
-                    PM_BREAK_IF_ERROR(retval);
+                    /* Just copy the pointer, since Strings are immutable */
+                    pobj2 = pobj1;
                 }
 
                 /* if it's a tuple */
 /**
  * Creates a thread object and adds it to the queue of threads to be
  * executed while interpret() is running.
- * 
+ *
  * The given obj may be a function, module, or class.
  * Creates a frame for the given function.
  *
  **************************************************************/
 
 uint16_t
-mem_getWord(PmMemSpace_t memspace, uint8_t **paddr)
+mem_getWord(PmMemSpace_t memspace, uint8_t const **paddr)
 {
     /* PyMite is little endian; get lo byte first */
     uint8_t blo = mem_getByte(memspace, paddr);
 
 
 uint32_t
-mem_getInt(PmMemSpace_t memspace, uint8_t **paddr)
+mem_getInt(PmMemSpace_t memspace, uint8_t const **paddr)
 {
     /* PyMite is little endian; get low word first */
     uint16_t wlo = mem_getWord(memspace, paddr);
 
 void
 mem_copy(PmMemSpace_t memspace,
-         uint8_t **pdest, uint8_t **psrc, uint16_t count)
+         uint8_t **pdest, uint8_t const **psrc, uint16_t count)
 {
 
     /* copy memory from RAM */
 
 
 uint16_t
-mem_getNumUtf8Bytes(PmMemSpace_t memspace, uint8_t **psrc)
+mem_getStringLength(PmMemSpace_t memspace, uint8_t const * const pstr)
 {
-    uint8_t *pbase = *psrc;
+    uint8_t const *psrc;
 
-    while (mem_getByte(memspace, psrc) != (uint8_t)0);
-    return *psrc - pbase - 1;
+    if (memspace == MEMSPACE_RAM)
+    {
+        return sli_strlen((char const *)pstr);
+    }
+
+    psrc = pstr;
+    while (mem_getByte(memspace, &psrc) != (uint8_t)0);
+    return psrc - pstr - 1;
 }
 
 
  * @return  word from memory.
  *          addr - points one byte past the word
  */
-INLINE uint16_t mem_getWord(PmMemSpace_t memspace, uint8_t **paddr);
+INLINE uint16_t mem_getWord(PmMemSpace_t memspace, uint8_t const **paddr);
 
 /**
  * Return the 4-byte int at the given address in memspace.
  * @return  int from memory.
  *          addr - points one byte past the word
  */
-INLINE uint32_t mem_getInt(PmMemSpace_t memspace, uint8_t **paddr);
+INLINE uint32_t mem_getInt(PmMemSpace_t memspace, uint8_t const **paddr);
 
 /**
  * Copy count number of bytes
  * @see     sli_memcpy
  */
 void mem_copy(PmMemSpace_t memspace,
-              uint8_t **pdest, uint8_t **psrc, uint16_t count);
+              uint8_t **pdest, uint8_t const **psrc, uint16_t count);
 
 /**
- * Return the number of bytes in the UTF-8 string
- * pointed to by the contents of psrc.
- * Afterward, the contents of psrc will point one byte past
- * the null terminator of the string.
+ * Returns the number of bytes in the C string pointed to by pstr.
+ * Does not modify pstr
  *
  * @param   memspace memory space/type of source
  * @param   psrc  ptr to source address
- * @return  Number of bytes in UTF-8 string.
+ * @return  Number of bytes in the string.
  */
-uint16_t mem_getNumUtf8Bytes(PmMemSpace_t memspace, uint8_t **psrc);
+uint16_t mem_getStringLength(PmMemSpace_t memspace,
+                             uint8_t const * const pstr);
 
 #endif /* __MEM_H__ */
 mod_import(pPmObj_t pstr, pPmObj_t *pmod)
 {
     pPmImgInfo_t pii = C_NULL;
-    uint8_t *imgaddr = C_NULL;
+    uint8_t const *imgaddr = C_NULL;
     pPmCo_t pco = C_NULL;
     PmReturn_t retval = PM_RET_OK;
     pPmObj_t pobj;
  **************************************************************/
 
 PmReturn_t
-obj_loadFromImg(PmMemSpace_t memspace, uint8_t **paddr, pPmObj_t *r_pobj)
+obj_loadFromImg(PmMemSpace_t memspace,
+                uint8_t const **paddr, pPmObj_t *r_pobj)
 {
     PmReturn_t retval = PM_RET_OK;
     PmObjDesc_t od;
 #define OBJ_SET_GCVAL(obj, gcval) (obj).od.od_gcval = (gcval)
 #define OBJ_GET_GCFREE(obj) ((obj).od.od_gcfree)
 #define OBJ_SET_GCFREE(obj, free) ((obj).od.od_gcfree = (uint8_t)free)
-/* 
- * od_size bits are shifted because size is a scaled value 
+/*
+ * od_size bits are shifted because size is a scaled value
  * True size is always a multiple of 4, so the lower two bits are ignored
  * and two more significant bits are gained.
  */
  * @return  Return status
  */
 PmReturn_t obj_loadFromImg(PmMemSpace_t memspace,
-                           uint8_t **paddr, pPmObj_t *r_pobj);
+                           uint8_t const **paddr, pPmObj_t *r_pobj);
 
 /**
  * Finds the boolean value of the given object.
 
 /**
  * Print an object, thereby using objects helpers.
- * 
+ *
  * @param   pobj Ptr to object for printing.
  * @param   marshallString Only has influence on the way strings are printed.
  *                         If 0, just output the string bytewise. Otherwise,

src/vm/plat/avr.c

  * Post-increments *paddr.
  */
 uint8_t
-plat_memGetByte(PmMemSpace_t memspace, uint8_t **paddr)
+plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr)
 {
     uint8_t b = 0;
 

src/vm/plat/desktop.c

  * Post-increments *paddr.
  */
 uint8_t
-plat_memGetByte(PmMemSpace_t memspace, uint8_t **paddr)
+plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr)
 {
     uint8_t b = 0;
 

src/vm/plat/plat.h

  * @return  byte from memory.
  *          paddr - points to the next byte
  */
-uint8_t plat_memGetByte(PmMemSpace_t memspace, uint8_t **paddr);
+uint8_t plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr);
 
 /**
  * Receives one byte from the default connection,
 pm_init(PmMemSpace_t memspace, uint8_t *pusrimg)
 {
     PmReturn_t retval;
-    uint8_t *pimg;
+    uint8_t const *pimg;
 
     /* Initialize the hardware platform */
     retval = plat_init();
 
 
 PmReturn_t
-pm_run(uint8_t *modstr)
+pm_run(uint8_t const *modstr)
 {
     PmReturn_t retval;
     pPmObj_t pmod;
     pPmObj_t pstring;
-    uint8_t *pmodstr = modstr;
+    uint8_t const *pmodstr = modstr;
 
     /* Import module from global struct */
     retval = string_new(&pmodstr, &pstring);
  * @param modstr        Name of module to run
  * @return Return status
  */
-PmReturn_t pm_run(uint8_t *modstr);
+PmReturn_t pm_run(uint8_t const *modstr);
 
 /**
  * Needs to be called periodically by a platform specific means.
  * For the desktop target, it is periodically called using a signal.
  * For embedded targets, it needs to be called periodically. It should
  * be called from a timer interrupt.
- * 
+ *
  * @param usecsSinceLastCall Microseconds (not less than those) that passed
  *                           since last call. This must be <64535.
  * @return Return status
 {
     char const *si = s;
 
-    while (*s++);
-    return (unsigned int)s - (unsigned int)si;
+    while (*si++);
+    return (unsigned int)si - (unsigned int)s - 1;
 }
 
 
  * Constants
  **************************************************************/
 
-/** 
+/**
  * If the compiler has string.h, set HAVE_STRING to 1;
  * otherwise, leave it 0 and the sli functions will be used.
  */
  * Log
  * ---
  *
+ * 2007/04/21   #46: Finalize design of string objects
  * 2007/01/17   #76: Print will differentiate on strings and print tuples
  * 2007/01/10   #75: Printing support (P.Adelt)
  * 2006/08/31   #9: Fix BINARY_SUBSCR for case stringobj[intobj]
  */
 PmReturn_t
 string_create(PmMemSpace_t memspace,
-              uint8_t **paddr, uint8_t isimg, pPmObj_t *r_pstring)
+              uint8_t const **paddr, uint8_t isimg, pPmObj_t *r_pstring)
 {
     PmReturn_t retval = PM_RET_OK;
     uint16_t len = 0;
     if (isimg == (uint8_t)0)
     {
         /* get length of string */
-        len = mem_getNumUtf8Bytes(memspace, paddr);
-        /* backup ptr to beginning of string */
-        *paddr -= len + 1;
+        len = mem_getStringLength(memspace, *paddr);
     }
 
     /* if loading from an img */
 
 
 PmReturn_t
-string_newFromChar(uint8_t c, pPmObj_t *r_pstring)
+string_newFromChar(uint8_t const c, pPmObj_t *r_pstring)
 {
     PmReturn_t retval;
-    pPmString_t pstr;
+    uint8_t cstr[2];
+    uint8_t const *pcstr;
 
-#if USE_STRING_CACHE
-    pPmString_t pcacheentry = C_NULL;
-#endif /* USE_STRING_CACHE */
-    uint8_t *pchunk;
+    cstr[0] = c;
+    cstr[1] = '\0';
+    pcstr = cstr;
 
-    /* Get space for String obj */
-    retval = heap_getChunk(sizeof(PmString_t) + 1, &pchunk);
-    PM_RETURN_IF_ERROR(retval);
-    pstr = (pPmString_t)pchunk;
+    retval = string_new(&pcstr, r_pstring);
 
-    /* Fill the string obj */
-    OBJ_SET_TYPE(*pstr, OBJ_TYPE_STR);
-    pstr->length = 1;
-    pstr->val[0] = c;
-    pstr->val[1] = '\0';
-
-#if USE_STRING_CACHE
-    /* XXX uses linear search... could improve */
-
-    /* check for twin string in cache */
-    for (pcacheentry = pstrcache;
-         pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
+    /* If c was a null character, force the length to 1 */
+    if (c == '\0')
     {
-        /* if string already exists */
-        if (string_compare(pcacheentry, pstr) == C_SAME)
-        {
-            /* free the string */
-            retval = heap_freeChunk((pPmObj_t)pstr);
-            /* return ptr to old */
-            *r_pstring = (pPmObj_t)pcacheentry;
-            return retval;
-        }
+        ((pPmString_t)*r_pstring)->length = 1;
     }
 
-    /* insert string obj into cache */
-    pstr->next = pstrcache;
-    pstrcache = pstr;
-
-#endif /* USE_STRING_CACHE */
-
-    *r_pstring = (pPmObj_t)pstr;
     return retval;
 }
 
 }
 
 
-PmReturn_t
-string_copy(pPmObj_t pstr, pPmObj_t *r_pstring)
-{
-    PmReturn_t retval = PM_RET_OK;
-    pPmString_t pnew = C_NULL;
-    uint8_t *pnewchars;
-    uint8_t *pstrchars;
-    uint8_t *pchunk;
-
-    /* ensure string obj */
-    if (OBJ_GET_TYPE(*pstr) != OBJ_TYPE_STR)
-    {
-        PM_RAISE(retval, PM_RET_EX_TYPE);
-        return retval;
-    }
-
-    /* allocate string obj */
-    retval = heap_getChunk(sizeof(PmString_t) + ((pPmString_t)pstr)->length,
-                           &pchunk);
-    PM_RETURN_IF_ERROR(retval);
-    pnew = (pPmString_t)pchunk;
-    OBJ_SET_TYPE(*pnew, OBJ_TYPE_STR);
-#if USE_STRING_CACHE
-    /* insert new string obj into cache */
-    pnew->next = pstrcache;
-    pstrcache = pnew;
-#endif
-    /* Copy the string's length field */
-    pnew->length = ((pPmString_t)pstr)->length;
-    /* copy string contents (and null term) */
-    pnewchars = pnew->val;
-    pstrchars = ((pPmString_t)pstr)->val;
-    mem_copy(MEMSPACE_RAM, &pnewchars, &pstrchars, pnew->length + 1);
-    *r_pstring = (pPmObj_t)pnew;
-    return retval;
-}
-
 #ifdef HAVE_PRINT
 PmReturn_t
 string_print(pPmObj_t pstr, uint8_t marshall)
             string_create((ms), (paddr), (uint8_t)1, (r_pstring))
 
 /**
- * create string from UTF-8 string in RAM
+ * Create String object from character array in RAM
  *
  * @param s address in RAM of source string
  * @param r_pstring Return arg; addr of ptr to string
  **************************************************************/
 
 /**
- * Create a new String obj.
+ * Creates a new String obj.
  * If n is zero, load from a String image.
  *      A string image has the following structure:
- *          -type:      S8 - OBJ_TYPE_STRING
- *          -length:    U16 - number of bytes in the string
- *          -string:    U8[] - array of chars with null term
+ *          -type:      int8 - OBJ_TYPE_STRING
+ *          -length:    uint16 - number of bytes in the string
+ *          -val:       uint8[] - array of chars with null term
  *
  * If n is not zero, create from a C string.
  * Return ptr to String obj.
  * or string_new().
  *
  * @param   memspace memory space where *paddr points
- * @param   paddr ptr to ptr to null term UTF-8 string or image.
+ * @param   paddr ptr to ptr to null term character array or image.
  * @param   isimg if 0, create from C string;
  *          else load from image.
  * @param   Return arg; ptr to String obj
  * @return  Return status
  */
-PmReturn_t string_create(PmMemSpace_t memspace,
-                         uint8_t **paddr, uint8_t isimg, pPmObj_t *r_pstring);
+PmReturn_t string_create(PmMemSpace_t memspace, uint8_t const **paddr,
+                         uint8_t isimg, pPmObj_t *r_pstring);
 
 /**
  * Create a new String object from a single character.
  * @param   r_psting Return arg; ptr to String obj
  * @return  Return status
  */
-PmReturn_t string_newFromChar(uint8_t c, pPmObj_t *r_pstring);
+PmReturn_t string_newFromChar(uint8_t const c, pPmObj_t *r_pstring);
 
 /**
  * Compare two String objects for equality.
  */
 int8_t string_compare(pPmString_t, pPmString_t);
 
-/**
- * Create a copy of the given string obj.
- *
- * @param   pstr Ptr to source string.
- * @param   Return arg; Ptr to the new string obj.
- * @return  Return status
- */
-PmReturn_t string_copy(pPmObj_t pstr, pPmObj_t *r_pstring);
-
 #ifdef HAVE_PRINT
 /**
  * Sends out a string object bytewise. Escaping and framing is configurable
  * via marshall.
- * 
+ *
  * @param pobj Ptr to string object
  * @param marshall If 0, print out string as is. Otherwise escape unprintable
  *                 characters and surround string with single quotes.
  **************************************************************/
 
 PmReturn_t
-tuple_loadFromImg(PmMemSpace_t memspace, uint8_t **paddr, pPmObj_t *r_ptuple)
+tuple_loadFromImg(PmMemSpace_t memspace,
+                  uint8_t const **paddr, pPmObj_t *r_ptuple)
 {
     PmReturn_t retval = PM_RET_OK;
     uint8_t i = (uint8_t)0;
     pPmTuple_t pnew = C_NULL;
     uint8_t *pchunk;
     uint8_t *pdest;
-    uint8_t *psrc;
+    uint8_t const *psrc;
 
     /* ensure type */
     if (OBJ_GET_TYPE(*ptup) != OBJ_TYPE_TUP)
     pnew = (pPmTuple_t)pchunk;
 
     pdest = (uint8_t *)pnew;
-    psrc = (uint8_t *)ptup;
+    psrc = (uint8_t const *)ptup;
     mem_copy(MEMSPACE_RAM, &pdest, &psrc, OBJ_GET_SIZE(*ptup));
     *r_ptuple = (pPmObj_t)pnew;
     return PM_RET_OK;
  *          past end of last obj in tuple.
  */
 PmReturn_t tuple_loadFromImg(PmMemSpace_t memspace,
-                             uint8_t **paddr, pPmObj_t *r_ptuple);
+                             uint8_t const **paddr, pPmObj_t *r_ptuple);
 
 /**
  * Allocate space for a new Tuple.
 #ifdef HAVE_PRINT
 /**
  * Print out a tuple. Uses obj_print() to print elements.
- * 
+ *
  * @param pobj Object to print.
  * @return Return status
  */