Index: libcfa/src/Makefile.am
===================================================================
--- libcfa/src/Makefile.am	(revision 218096fb228f5c7862385d7645097bffddd90c17)
+++ libcfa/src/Makefile.am	(revision 0f781fb89ac90634a87242ab226c285456c417bf)
@@ -63,4 +63,5 @@
 	containers/queueLockFree.hfa \
 	containers/stackLockFree.hfa \
+	containers/string_sharectx.hfa \
 	containers/vector2.hfa \
 	vec/vec.hfa \
Index: libcfa/src/containers/string_res.cfa
===================================================================
--- libcfa/src/containers/string_res.cfa	(revision 218096fb228f5c7862385d7645097bffddd90c17)
+++ libcfa/src/containers/string_res.cfa	(revision 0f781fb89ac90634a87242ab226c285456c417bf)
@@ -15,4 +15,6 @@
 
 #include "string_res.hfa"
+#include "string_sharectx.hfa"
+
 #include <stdlib.hfa>  // e.g. malloc
 #include <string.h>    // e.g. strlen
@@ -20,18 +22,4 @@
 
 //######################### VbyteHeap "header" #########################
-
-
-
-
-
-
-
-
-// DON'T COMMIT:
-// #define VbyteDebug
-
-
-
-
 
 #ifdef VbyteDebug
@@ -62,6 +50,6 @@
 static inline void ?{}( VbyteHeap &, int = 1000 );
 static inline void ^?{}( VbyteHeap & );
-static inline void ByteCopy( VbyteHeap &, char *, int, int, char *, int, int ); // copy a block of bytes from one location in the heap to another
-static inline int ByteCmp( VbyteHeap &, char *, int, int, char *, int, int );	// compare 2 blocks of bytes
+static inline void ByteCopy( char *, int, int, char *, int, int ); // copy a block of bytes from one location in the heap to another
+static inline int ByteCmp( char *, int, int, char *, int, int );	// compare 2 blocks of bytes
 static inline char *VbyteAlloc( VbyteHeap &, int );			// allocate a block bytes in the heap
 
@@ -83,4 +71,5 @@
     ExtVbyte = (void *)( StartVbyte + CurrSize );
     Header.flink = Header.blink = &Header;
+    Header.ulink = & this;
 #ifdef VbyteDebug
     HeaderPtr = &Header;
@@ -124,4 +113,5 @@
     s = 0;
     lnth = 0;
+    ulink = &vh;
     AddThisAfter( this, *vh.Header.blink );
 #ifdef VbyteDebug
@@ -150,10 +140,38 @@
 } // ~HandleNode
 
+
+//######################### String Sharing Context #########################
+
+static string_sharectx * ambient_string_sharectx;               // fickle top of stack
+static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack
+
+void ?{}( string_sharectx & this, StringSharectx_Mode mode ) with( this ) {
+    (older){ ambient_string_sharectx };
+    if ( mode == NEW_SHARING ) {
+        (activeHeap){ new( 1000 ) };
+    } else {
+        verify( mode == NO_SHARING );
+        (activeHeap){ 0p };
+    }
+    ambient_string_sharectx = & this;
+}
+
+void ^?{}( string_sharectx & this ) with( this ) {
+    if ( activeHeap ) delete( activeHeap );
+
+    // unlink this from older-list starting from ambient_string_sharectx
+    // usually, this==ambient_string_sharectx and the loop runs zero times
+    string_sharectx *& c = ambient_string_sharectx;
+    while ( c != &this ) &c = &c->older;              // find this
+    c = this.older;                                   // unlink
+}
+
 //######################### String Resource #########################
 
 
-VbyteHeap HeapArea;
-
-VbyteHeap * DEBUG_string_heap = & HeapArea;
+VbyteHeap * DEBUG_string_heap() {
+    assert( ambient_string_sharectx->activeHeap && "No sharing context is active" );
+    return ambient_string_sharectx->activeHeap;
+}
 
 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) {
@@ -199,5 +217,6 @@
 // Empty constructor
 void ?{}(string_res &s) with(s) {
-    (Handle){ HeapArea };
+    assert( ambient_string_sharectx->activeHeap && "Need to implement private contexts" );
+    (Handle){ * ambient_string_sharectx->activeHeap };
     s.shareEditSet_prev = &s;
     s.shareEditSet_next = &s;
@@ -206,6 +225,7 @@
 // Constructor from a raw buffer and size
 void ?{}(string_res &s, const char* rhs, size_t rhslnth) with(s) {
-    (Handle){ HeapArea };
-    Handle.s = VbyteAlloc(HeapArea, rhslnth);
+    assert( ambient_string_sharectx->activeHeap && "Need to implement private contexts" );
+    (Handle){ * ambient_string_sharectx->activeHeap };
+    Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
     Handle.lnth = rhslnth;
     for ( int i = 0; i < rhslnth; i += 1 ) {		// copy characters
@@ -224,4 +244,7 @@
 void ?{}(string_res &s, const string_res & s2, StrResInitMode mode, size_t start, size_t end ) {
 
+    assert( ambient_string_sharectx->activeHeap && "Need to implement private contexts" );
+    assert( s2.Handle.ulink == ambient_string_sharectx->activeHeap && "need to implement context crossing");
+
     verify( start <= end && end <= s2.Handle.lnth );
 
@@ -229,4 +252,5 @@
     s.Handle.s = s2.Handle.s + start;
     s.Handle.lnth = end - start;
+    s.Handle.ulink = ambient_string_sharectx->activeHeap;
     AddThisAfter(s.Handle, s2.Handle );			// insert this handle after rhs handle
     // ^ bug?  skip others at early point in string
@@ -404,12 +428,12 @@
         // no-op
     } else {						// must copy some text
-        if ( str1.Handle.s + size(str1) == VbyteAlloc(HeapArea, 0) ) { // str1 at end of string area ?
-            VbyteAlloc(HeapArea, bsize); // create room for 2nd part at the end of string area
+        if ( str1.Handle.s + size(str1) == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ?
+            VbyteAlloc( *str1.Handle.ulink, bsize ); // create room for 2nd part at the end of string area
         } else {					// copy the two parts
             char * str1oldBuf = str1.Handle.s;
-            str1.Handle.s = VbyteAlloc( HeapArea, clnth );
-            ByteCopy( HeapArea, str1.Handle.s, 0, str1.Handle.lnth, str1oldBuf, 0, str1.Handle.lnth);
+            str1.Handle.s = VbyteAlloc( *str1.Handle.ulink, clnth );
+            ByteCopy( str1.Handle.s, 0, str1.Handle.lnth, str1oldBuf, 0, str1.Handle.lnth);
         } // if
-        ByteCopy( HeapArea, str1.Handle.s, str1.Handle.lnth, bsize, (char*)buffer, 0, (int)bsize);
+        ByteCopy( str1.Handle.s, str1.Handle.lnth, bsize, (char*)buffer, 0, (int)bsize);
         //       VbyteHeap & this, char *Dst, int DstStart, int DstLnth, char *Src, int SrcStart, int SrcLnth 
     } // if
@@ -437,5 +461,5 @@
 
 bool ?==?(const string_res &s1, const string_res &s2) {
-    return ByteCmp( HeapArea, s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0;
+    return ByteCmp( s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0;
 }
 
@@ -608,4 +632,6 @@
     serr | "enter:AddThisAfter, this:" | &this | " n:" | &n;
 #endif // VbyteDebug
+    verify( n.ulink != 0p );
+    verify( this.ulink == n.ulink );
     flink = n.flink;
     blink = &n;
@@ -682,4 +708,6 @@
     serr | "enter:MoveThisAfter, this:" | & this | " h:" | & h;
 #endif // VbyteDebug
+    verify( h.ulink != 0p );
+    verify( this.ulink == h.ulink );
     if ( s < h.s ) {					// check argument values
 		// serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:"
@@ -723,5 +751,5 @@
 // if the |Dst| > |Src| => pad Dst with blanks
 
-void ByteCopy( VbyteHeap & this, char *Dst, int DstStart, int DstLnth, char *Src, int SrcStart, int SrcLnth ) {
+void ByteCopy( char *Dst, int DstStart, int DstLnth, char *Src, int SrcStart, int SrcLnth ) {
     for ( int i = 0; i < DstLnth; i += 1 ) {
       if ( i == SrcLnth ) {				// |Dst| > |Src|
@@ -741,5 +769,5 @@
 // -1 => Src1-byte-string < Src2-byte-string
 
-int ByteCmp( VbyteHeap & this, char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth )  with(this) {
+int ByteCmp( char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth )  {
 #ifdef VbyteDebug
     serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth;
@@ -798,5 +826,5 @@
     h = Header.flink;					// ignore header node
     for (;;) {
-		ByteCopy( this, EndVbyte, 0, h->lnth, h->s, 0, h->lnth );
+		ByteCopy( EndVbyte, 0, h->lnth, h->s, 0, h->lnth );
 		obase = h->s;
 		h->s = EndVbyte;
Index: libcfa/src/containers/string_res.hfa
===================================================================
--- libcfa/src/containers/string_res.hfa	(revision 218096fb228f5c7862385d7645097bffddd90c17)
+++ libcfa/src/containers/string_res.hfa	(revision 0f781fb89ac90634a87242ab226c285456c417bf)
@@ -27,4 +27,5 @@
     HandleNode *flink;					// forward link
     HandleNode *blink;					// backward link
+    VbyteHeap *ulink;                   // upward link
 
     char *s;						// pointer to byte string
@@ -32,5 +33,5 @@
 }; // HandleNode
 
-extern VbyteHeap * DEBUG_string_heap;
+VbyteHeap * DEBUG_string_heap();
 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap );
 const char * DEBUG_string_heap_start( VbyteHeap * heap );
Index: libcfa/src/containers/string_sharectx.hfa
===================================================================
--- libcfa/src/containers/string_sharectx.hfa	(revision 0f781fb89ac90634a87242ab226c285456c417bf)
+++ libcfa/src/containers/string_sharectx.hfa	(revision 0f781fb89ac90634a87242ab226c285456c417bf)
@@ -0,0 +1,58 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// string_sharectx -- utility for controlling string sharing / isolation
+//
+// Author           : Michael L. Brooks
+// Created On       : Fri Sep 03 11:00:00 2021
+// Last Modified By : Michael L. Brooks
+// Last Modified On : Fri Sep 03 11:00:00 2021
+// Update Count     : 1
+//
+
+#pragma once
+
+//######################### String Sharing Context #########################
+
+struct VbyteHeap;
+
+// A string_sharectx 
+//
+// Usage:
+// void bar() {
+//    c();
+//    string_sharectx c = {NEW_SHARING};
+//    d();
+// }
+// void foo() {
+//    a();
+//    string_sharectx c = {NO_SHARING};
+//    b();
+//    bar();
+//    e();
+// }
+// int main() {
+//    foo();
+// }
+//
+// a, d: share string character ranges within themselves, not with each other
+// b, c, e: never share anything
+//
+struct string_sharectx {
+    // private
+    VbyteHeap * activeHeap;
+    string_sharectx * older;
+};
+
+enum StringSharectx_Mode { NEW_SHARING, NO_SHARING };
+
+void ?{}( string_sharectx &, StringSharectx_Mode );
+void ^?{}( string_sharectx & );
+
+void ?{}( string_sharectx & ) = void;
+void ?{}( string_sharectx &, string_sharectx ) = void;
+void ?=?( string_sharectx &, string_sharectx ) = void;
+
