From d810aacdcd3af286faa6cb92606f9f16798a9374 Mon Sep 17 00:00:00 2001
From: obligaron <obligaron@live.com>
Date: Sat, 19 Oct 2024 08:30:44 +0200
Subject: [PATCH 1/3] CSHARP-5348: Add PopContext to Bson*Context where missing

---
 src/MongoDB.Bson/IO/BsonBinaryWriter.cs          | 6 +++---
 src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs   | 5 +++++
 src/MongoDB.Bson/IO/BsonDocumentWriter.cs        | 8 ++++----
 src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs | 5 +++++
 src/MongoDB.Bson/IO/JsonWriter.cs                | 6 +++---
 src/MongoDB.Bson/IO/JsonWriterContext.cs         | 5 +++++
 6 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriter.cs b/src/MongoDB.Bson/IO/BsonBinaryWriter.cs
index 42430ef4eb4..7b9565592ba 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryWriter.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryWriter.cs
@@ -290,7 +290,7 @@ public override void WriteEndArray()
             _bsonStream.WriteByte(0);
             BackpatchSize(); // size of document
 
-            _context = _context.ParentContext;
+            _context = _context.PopContext();
             State = GetNextState();
         }
 
@@ -313,7 +313,7 @@ public override void WriteEndDocument()
             _bsonStream.WriteByte(0);
             BackpatchSize(); // size of document
 
-            _context = _context.ParentContext;
+            _context = _context.PopContext();
             if (_context == null)
             {
                 State = BsonWriterState.Done;
@@ -323,7 +323,7 @@ public override void WriteEndDocument()
                 if (_context.ContextType == ContextType.JavaScriptWithScope)
                 {
                     BackpatchSize(); // size of the JavaScript with scope value
-                    _context = _context.ParentContext;
+                    _context = _context.PopContext();
                 }
                 State = GetNextState();
             }
diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs b/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
index fb791ab4fc3..63bc6d79546 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
@@ -55,5 +55,10 @@ internal int Index
             get { return _index; }
             set { _index = value; }
         }
+
+        internal BsonBinaryWriterContext PopContext()
+        {
+            return _parentContext;
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonDocumentWriter.cs b/src/MongoDB.Bson/IO/BsonDocumentWriter.cs
index 3f77160f1c2..d0507a4b392 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentWriter.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentWriter.cs
@@ -195,7 +195,7 @@ public override void WriteEndArray()
 
             base.WriteEndArray();
             var array = _context.Array;
-            _context = _context.ParentContext;
+            _context = _context.PopContext();
             WriteValue(array);
             State = GetNextState();
         }
@@ -219,15 +219,15 @@ public override void WriteEndDocument()
             if (_context.ContextType == ContextType.ScopeDocument)
             {
                 var scope = _context.Document;
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
                 var code = _context.Code;
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
                 WriteValue(new BsonJavaScriptWithScope(code, scope));
             }
             else
             {
                 var document = _context.Document;
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
                 if (_context != null)
                 {
                     WriteValue(document);
diff --git a/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs b/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
index 4aa1f6ddd82..049ae09e7fd 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
@@ -87,5 +87,10 @@ internal string Code
         {
             get { return _code; }
         }
+
+        internal BsonDocumentWriterContext PopContext()
+        {
+            return _parentContext;
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/JsonWriter.cs b/src/MongoDB.Bson/IO/JsonWriter.cs
index 39b884c8618..e558e42eb12 100644
--- a/src/MongoDB.Bson/IO/JsonWriter.cs
+++ b/src/MongoDB.Bson/IO/JsonWriter.cs
@@ -312,7 +312,7 @@ public override void WriteEndArray()
             base.WriteEndArray();
             _textWriter.Write("]");
 
-            _context = _context.ParentContext;
+            _context = _context.PopContext();
             State = GetNextState();
         }
 
@@ -344,12 +344,12 @@ public override void WriteEndDocument()
 
             if (_context.ContextType == ContextType.ScopeDocument)
             {
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
                 WriteEndDocument();
             }
             else
             {
-                _context = _context.ParentContext;
+                _context = _context.PopContext();
             }
 
             if (_context == null)
diff --git a/src/MongoDB.Bson/IO/JsonWriterContext.cs b/src/MongoDB.Bson/IO/JsonWriterContext.cs
index c48dc7cef12..4fd7e5d00c1 100644
--- a/src/MongoDB.Bson/IO/JsonWriterContext.cs
+++ b/src/MongoDB.Bson/IO/JsonWriterContext.cs
@@ -52,5 +52,10 @@ internal bool HasElements
             get { return _hasElements; }
             set { _hasElements = value; }
         }
+
+        internal JsonWriterContext PopContext()
+        {
+            return _parentContext;
+        }
     }
 }

From e3923ca52b0581760dcb7ea828931132a22e0e87 Mon Sep 17 00:00:00 2001
From: obligaron <obligaron@live.com>
Date: Sat, 19 Oct 2024 08:25:34 +0200
Subject: [PATCH 2/3] CSHARP-5348: Introduce Bson*Context.PushContext

---
 .../MongoDB.Driver.Benchmarks/README.md       |  2 +-
 src/MongoDB.Bson/IO/BsonBinaryReader.cs       |  6 +++---
 .../IO/BsonBinaryReaderContext.cs             |  5 +++++
 src/MongoDB.Bson/IO/BsonBinaryWriter.cs       |  9 ++++++---
 .../IO/BsonBinaryWriterContext.cs             |  5 +++++
 src/MongoDB.Bson/IO/BsonDocumentReader.cs     |  4 ++--
 .../IO/BsonDocumentReaderContext.cs           | 10 ++++++++++
 src/MongoDB.Bson/IO/BsonDocumentWriter.cs     |  8 ++++----
 .../IO/BsonDocumentWriterContext.cs           | 19 +++++++++++++++++--
 src/MongoDB.Bson/IO/JsonReader.cs             |  6 +++---
 src/MongoDB.Bson/IO/JsonReaderContext.cs      |  5 +++++
 src/MongoDB.Bson/IO/JsonWriter.cs             |  4 ++--
 src/MongoDB.Bson/IO/JsonWriterContext.cs      |  5 +++++
 13 files changed, 68 insertions(+), 20 deletions(-)

diff --git a/benchmarks/MongoDB.Driver.Benchmarks/README.md b/benchmarks/MongoDB.Driver.Benchmarks/README.md
index fa07012c742..899a9df0ae6 100644
--- a/benchmarks/MongoDB.Driver.Benchmarks/README.md
+++ b/benchmarks/MongoDB.Driver.Benchmarks/README.md
@@ -13,7 +13,7 @@ This suite implements the benchmarks described in this [spec](https://github.com
    (e.g `dotnet run -c Release -- --driverBenchmarks --envVars MONGODB_URI:"ConnectionString"`)
 
 You can also select the benchmarks to run directly on the command for running the benchmarks as such
-`dotnet run -c Release -- --driverBenchmarks --fitler "*BenchmarkClassName*"`. The benchmarks are also grouped into categories namely: BSONBench, WriteBench
+`dotnet run -c Release -- --driverBenchmarks --filter "*BenchmarkClassName*"`. The benchmarks are also grouped into categories namely: BSONBench, WriteBench
 ReadBench, ParallelBench, SingleBench, MultiBench and DriverBench. So if you wanted to only run the WriteBench benchmarks, you can do so
 as follows: `dotnet run -c Release -- --driverBenchmarks --anyCategories "WriteBench"`.
 
diff --git a/src/MongoDB.Bson/IO/BsonBinaryReader.cs b/src/MongoDB.Bson/IO/BsonBinaryReader.cs
index 3bf194cd425..4993bffd764 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryReader.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryReader.cs
@@ -432,7 +432,7 @@ public override string ReadJavaScriptWithScope()
 
             var startPosition = _bsonStream.Position; // position of size field
             var size = ReadSize();
-            _context = new BsonBinaryReaderContext(_context, ContextType.JavaScriptWithScope, startPosition, size);
+            _context = _context.PushContext(ContextType.JavaScriptWithScope, startPosition, size);
             var code = _bsonStream.ReadString(Settings.Encoding);
 
             State = BsonReaderState.ScopeDocument;
@@ -590,7 +590,7 @@ public override void ReadStartArray()
 
             var startPosition = _bsonStream.Position; // position of size field
             var size = ReadSize();
-            _context = new BsonBinaryReaderContext(_context, ContextType.Array, startPosition, size);
+            _context = _context.PushContext(ContextType.Array, startPosition, size);
             State = BsonReaderState.Type;
         }
 
@@ -605,7 +605,7 @@ public override void ReadStartDocument()
             var contextType = (State == BsonReaderState.ScopeDocument) ? ContextType.ScopeDocument : ContextType.Document;
             var startPosition = _bsonStream.Position; // position of size field
             var size = ReadSize();
-            _context = new BsonBinaryReaderContext(_context, contextType, startPosition, size);
+            _context = _context.PushContext(contextType, startPosition, size);
             State = BsonReaderState.Type;
         }
 
diff --git a/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs b/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs
index c4e18381dda..9363d46bd61 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs
@@ -83,5 +83,10 @@ public BsonBinaryReaderContext PopContext(long position)
             }
             return _parentContext;
         }
+
+        internal BsonBinaryReaderContext PushContext(ContextType contextType, long startPosition, long size)
+        {
+            return new BsonBinaryReaderContext(this, contextType, startPosition, size);
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriter.cs b/src/MongoDB.Bson/IO/BsonBinaryWriter.cs
index 7b9565592ba..b1535347d79 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryWriter.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryWriter.cs
@@ -400,7 +400,7 @@ public override void WriteJavaScriptWithScope(string code)
 
             _bsonStream.WriteBsonType(BsonType.JavaScriptWithScope);
             WriteNameHelper();
-            _context = new BsonBinaryWriterContext(_context, ContextType.JavaScriptWithScope, _bsonStream.Position);
+            _context = _context.PushContext(ContextType.JavaScriptWithScope, _bsonStream.Position);
             _bsonStream.WriteInt32(0); // reserve space for size of JavaScript with scope value
             _bsonStream.WriteString(code, Settings.Encoding);
 
@@ -564,7 +564,7 @@ public override void WriteStartArray()
             base.WriteStartArray();
             _bsonStream.WriteBsonType(BsonType.Array);
             WriteNameHelper();
-            _context = new BsonBinaryWriterContext(_context, ContextType.Array, _bsonStream.Position);
+            _context = _context.PushContext(ContextType.Array, _bsonStream.Position);
             _bsonStream.WriteInt32(0); // reserve space for size
 
             State = BsonWriterState.Value;
@@ -588,7 +588,10 @@ public override void WriteStartDocument()
                 WriteNameHelper();
             }
             var contextType = (State == BsonWriterState.ScopeDocument) ? ContextType.ScopeDocument : ContextType.Document;
-            _context = new BsonBinaryWriterContext(_context, contextType, _bsonStream.Position);
+            if (_context == null)
+                _context = new BsonBinaryWriterContext(null, contextType, _bsonStream.Position);
+            else
+                _context = _context.PushContext(contextType, _bsonStream.Position);
             _bsonStream.WriteInt32(0); // reserve space for size
 
             State = BsonWriterState.Name;
diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs b/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
index 63bc6d79546..3f42c5faa2d 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
@@ -60,5 +60,10 @@ internal BsonBinaryWriterContext PopContext()
         {
             return _parentContext;
         }
+
+        internal BsonBinaryWriterContext PushContext(ContextType contextType, long startPosition)
+        {
+            return new BsonBinaryWriterContext(this, contextType, startPosition);
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonDocumentReader.cs b/src/MongoDB.Bson/IO/BsonDocumentReader.cs
index aa4a1e93252..2231bee8be0 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentReader.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentReader.cs
@@ -413,7 +413,7 @@ public override void ReadStartArray()
             VerifyBsonType("ReadStartArray", BsonType.Array);
 
             var array = _currentValue.AsBsonArray;
-            _context = new BsonDocumentReaderContext(_context, ContextType.Array, array);
+            _context = _context.PushContext(ContextType.Array, array);
             State = BsonReaderState.Type;
         }
 
@@ -435,7 +435,7 @@ public override void ReadStartDocument()
             {
                 document = _currentValue.AsBsonDocument;
             }
-            _context = new BsonDocumentReaderContext(_context, ContextType.Document, document);
+            _context = _context.PushContext(ContextType.Document, document);
             State = BsonReaderState.Type;
         }
 
diff --git a/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs b/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs
index 9208be4ae0f..60c2f6b0dd2 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs
@@ -124,5 +124,15 @@ public BsonDocumentReaderContext PopContext()
         {
             return _parentContext;
         }
+
+        internal BsonDocumentReaderContext PushContext(ContextType contextType, BsonArray array)
+        {
+            return new BsonDocumentReaderContext(this, contextType, array);
+        }
+
+        internal BsonDocumentReaderContext PushContext(ContextType contextType, BsonDocument document)
+        {
+            return new BsonDocumentReaderContext(this, contextType, document);
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonDocumentWriter.cs b/src/MongoDB.Bson/IO/BsonDocumentWriter.cs
index d0507a4b392..8e5e4ef0b27 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentWriter.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentWriter.cs
@@ -304,7 +304,7 @@ public override void WriteJavaScriptWithScope(string code)
                 ThrowInvalidState("WriteJavaScriptWithScope", BsonWriterState.Value);
             }
 
-            _context = new BsonDocumentWriterContext(_context, ContextType.JavaScriptWithScope, code);
+            _context = _context.PushContext(ContextType.JavaScriptWithScope, code);
             State = BsonWriterState.ScopeDocument;
         }
 
@@ -407,7 +407,7 @@ public override void WriteStartArray()
             }
 
             base.WriteStartArray();
-            _context = new BsonDocumentWriterContext(_context, ContextType.Array, new BsonArray());
+            _context = _context.PushContext(ContextType.Array, new BsonArray());
             State = BsonWriterState.Value;
         }
 
@@ -430,10 +430,10 @@ public override void WriteStartDocument()
                     _context = new BsonDocumentWriterContext(null, ContextType.Document, _document);
                     break;
                 case BsonWriterState.Value:
-                    _context = new BsonDocumentWriterContext(_context, ContextType.Document, new BsonDocument());
+                    _context = _context.PushContext(ContextType.Document, new BsonDocument());
                     break;
                 case BsonWriterState.ScopeDocument:
-                    _context = new BsonDocumentWriterContext(_context, ContextType.ScopeDocument, new BsonDocument());
+                    _context = _context.PushContext(ContextType.ScopeDocument, new BsonDocument());
                     break;
                 default:
                     throw new BsonInternalException("Unexpected state.");
diff --git a/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs b/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
index 049ae09e7fd..f82d3152d67 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
@@ -36,7 +36,7 @@ internal BsonDocumentWriterContext(
             _document = document;
         }
 
-        internal BsonDocumentWriterContext(
+        private BsonDocumentWriterContext(
             BsonDocumentWriterContext parentContext,
             ContextType contextType,
             BsonArray array)
@@ -46,7 +46,7 @@ internal BsonDocumentWriterContext(
             _array = array;
         }
 
-        internal BsonDocumentWriterContext(
+        private BsonDocumentWriterContext(
             BsonDocumentWriterContext parentContext,
             ContextType contextType,
             string code)
@@ -92,5 +92,20 @@ internal BsonDocumentWriterContext PopContext()
         {
             return _parentContext;
         }
+
+        internal BsonDocumentWriterContext PushContext(ContextType contextType, BsonDocument document)
+        {
+            return new BsonDocumentWriterContext(this, contextType, document);
+        }
+
+        internal BsonDocumentWriterContext PushContext(ContextType contextType, BsonArray array)
+        {
+            return new BsonDocumentWriterContext(this, contextType, array);
+        }
+
+        internal BsonDocumentWriterContext PushContext(ContextType contextType, string code)
+        {
+            return new BsonDocumentWriterContext(this, contextType, code);
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/JsonReader.cs b/src/MongoDB.Bson/IO/JsonReader.cs
index 0d5a483ff60..d26f7846b7c 100644
--- a/src/MongoDB.Bson/IO/JsonReader.cs
+++ b/src/MongoDB.Bson/IO/JsonReader.cs
@@ -627,7 +627,7 @@ public override string ReadJavaScriptWithScope()
         {
             if (Disposed) { ThrowObjectDisposedException(); }
             VerifyBsonType("ReadJavaScriptWithScope", BsonType.JavaScriptWithScope);
-            _context = new JsonReaderContext(_context, ContextType.JavaScriptWithScope);
+            _context = _context.PushContext(ContextType.JavaScriptWithScope);
             State = BsonReaderState.ScopeDocument;
             return _currentValue.AsString;
         }
@@ -723,7 +723,7 @@ public override void ReadStartArray()
             if (Disposed) { ThrowObjectDisposedException(); }
             VerifyBsonType("ReadStartArray", BsonType.Array);
 
-            _context = new JsonReaderContext(_context, ContextType.Array);
+            _context = _context.PushContext(ContextType.Array);
             State = BsonReaderState.Type;
         }
 
@@ -735,7 +735,7 @@ public override void ReadStartDocument()
             if (Disposed) { ThrowObjectDisposedException(); }
             VerifyBsonType("ReadStartDocument", BsonType.Document);
 
-            _context = new JsonReaderContext(_context, ContextType.Document);
+            _context = _context.PushContext(ContextType.Document);
             State = BsonReaderState.Type;
         }
 
diff --git a/src/MongoDB.Bson/IO/JsonReaderContext.cs b/src/MongoDB.Bson/IO/JsonReaderContext.cs
index 94dc554ec39..8f12af683a1 100644
--- a/src/MongoDB.Bson/IO/JsonReaderContext.cs
+++ b/src/MongoDB.Bson/IO/JsonReaderContext.cs
@@ -53,5 +53,10 @@ public JsonReaderContext PopContext()
         {
             return _parentContext;
         }
+
+        internal JsonReaderContext PushContext(ContextType contextType)
+        {
+            return new JsonReaderContext(this, contextType);
+        }
     }
 }
diff --git a/src/MongoDB.Bson/IO/JsonWriter.cs b/src/MongoDB.Bson/IO/JsonWriter.cs
index e558e42eb12..501cfc4ad01 100644
--- a/src/MongoDB.Bson/IO/JsonWriter.cs
+++ b/src/MongoDB.Bson/IO/JsonWriter.cs
@@ -641,7 +641,7 @@ public override void WriteStartArray()
             WriteNameHelper(Name);
             _textWriter.Write("[");
 
-            _context = new JsonWriterContext(_context, ContextType.Array, Settings.IndentChars);
+            _context = _context.PushContext(ContextType.Array, Settings.IndentChars);
             State = BsonWriterState.Value;
         }
 
@@ -664,7 +664,7 @@ public override void WriteStartDocument()
             _textWriter.Write("{");
 
             var contextType = (State == BsonWriterState.ScopeDocument) ? ContextType.ScopeDocument : ContextType.Document;
-            _context = new JsonWriterContext(_context, contextType, Settings.IndentChars);
+            _context = _context.PushContext(contextType, Settings.IndentChars);
             State = BsonWriterState.Name;
         }
 
diff --git a/src/MongoDB.Bson/IO/JsonWriterContext.cs b/src/MongoDB.Bson/IO/JsonWriterContext.cs
index 4fd7e5d00c1..609121ee129 100644
--- a/src/MongoDB.Bson/IO/JsonWriterContext.cs
+++ b/src/MongoDB.Bson/IO/JsonWriterContext.cs
@@ -57,5 +57,10 @@ internal JsonWriterContext PopContext()
         {
             return _parentContext;
         }
+
+        internal JsonWriterContext PushContext(ContextType contextType, string indentChars)
+        {
+            return new JsonWriterContext(this, contextType, indentChars);
+        }
     }
 }

From 4f91e8d0ce2097be27be0b46e4391fcd2d3b9df9 Mon Sep 17 00:00:00 2001
From: obligaron <obligaron@live.com>
Date: Sat, 19 Oct 2024 13:02:31 +0200
Subject: [PATCH 3/3] CSHARP-5348: Cache Bson*Context.PushContext

---
 .../MongoDB.Driver.Benchmarks/README.md       |  2 +-
 .../IO/BsonBinaryReaderContext.cs             | 19 ++++++++--
 .../IO/BsonBinaryWriterContext.cs             | 13 ++++++-
 .../IO/BsonDocumentReaderContext.cs           | 25 ++++++++++--
 .../IO/BsonDocumentWriterContext.cs           | 38 ++++++++++++-------
 src/MongoDB.Bson/IO/JsonReaderContext.cs      |  9 ++++-
 src/MongoDB.Bson/IO/JsonWriterContext.cs      | 12 +++++-
 7 files changed, 89 insertions(+), 29 deletions(-)

diff --git a/benchmarks/MongoDB.Driver.Benchmarks/README.md b/benchmarks/MongoDB.Driver.Benchmarks/README.md
index 899a9df0ae6..005c5bd5be6 100644
--- a/benchmarks/MongoDB.Driver.Benchmarks/README.md
+++ b/benchmarks/MongoDB.Driver.Benchmarks/README.md
@@ -1,6 +1,6 @@
 # C# Driver Benchmark Suite
 
-This suite implements the benchmarks described in this [spec](https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.rst).
+This suite implements the benchmarks described in this [spec](https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.md).
 
 ## Running the Driver Benchmarks
 
diff --git a/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs b/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs
index 9363d46bd61..589362a24de 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryReaderContext.cs
@@ -21,9 +21,10 @@ internal class BsonBinaryReaderContext
     {
         // private fields
         private readonly BsonBinaryReaderContext _parentContext;
-        private readonly ContextType _contextType;
-        private readonly long _startPosition;
-        private readonly long _size;
+        private BsonBinaryReaderContext _cachedPushContext;
+        private ContextType _contextType;
+        private long _startPosition;
+        private long _size;
         private string _currentElementName;
         private int _currentArrayIndex = -1;
 
@@ -86,7 +87,17 @@ public BsonBinaryReaderContext PopContext(long position)
 
         internal BsonBinaryReaderContext PushContext(ContextType contextType, long startPosition, long size)
         {
-            return new BsonBinaryReaderContext(this, contextType, startPosition, size);
+            if (_cachedPushContext == null)
+                _cachedPushContext = new BsonBinaryReaderContext(this, contextType, startPosition, size);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._startPosition = startPosition;
+                _cachedPushContext._size = size;
+                _cachedPushContext._currentArrayIndex = -1;
+                _cachedPushContext._currentElementName = null;
+            }
+            return _cachedPushContext;
         }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs b/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
index 3f42c5faa2d..8512e9d56de 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryWriterContext.cs
@@ -18,7 +18,8 @@ namespace MongoDB.Bson.IO
     internal class BsonBinaryWriterContext
     {
         // private fields
-        private BsonBinaryWriterContext _parentContext;
+        private readonly BsonBinaryWriterContext _parentContext;
+        private BsonBinaryWriterContext _cachedPushContext;
         private ContextType _contextType;
         private long _startPosition;
         private int _index; // used when contextType is Array
@@ -63,7 +64,15 @@ internal BsonBinaryWriterContext PopContext()
 
         internal BsonBinaryWriterContext PushContext(ContextType contextType, long startPosition)
         {
-            return new BsonBinaryWriterContext(this, contextType, startPosition);
+            if (_cachedPushContext == null)
+                _cachedPushContext = new BsonBinaryWriterContext(this, contextType, startPosition);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._startPosition = startPosition;
+                _cachedPushContext._index = 0;
+            }
+            return _cachedPushContext;
         }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs b/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs
index 60c2f6b0dd2..aa5013eb5ee 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentReaderContext.cs
@@ -18,20 +18,23 @@ namespace MongoDB.Bson.IO
     internal class BsonDocumentReaderContext
     {
         // private fields
-        private BsonDocumentReaderContext _parentContext;
+        private readonly BsonDocumentReaderContext _parentContext;
+        private BsonDocumentReaderContext _cachedPushContext;
         private ContextType _contextType;
         private BsonDocument _document;
         private BsonArray _array;
         private int _index;
 
         // constructors
-        internal BsonDocumentReaderContext(
+        private BsonDocumentReaderContext(
             BsonDocumentReaderContext parentContext,
             ContextType contextType,
+            BsonDocument document,
             BsonArray array)
         {
             _parentContext = parentContext;
             _contextType = contextType;
+            _document = document;
             _array = array;
         }
 
@@ -127,12 +130,26 @@ public BsonDocumentReaderContext PopContext()
 
         internal BsonDocumentReaderContext PushContext(ContextType contextType, BsonArray array)
         {
-            return new BsonDocumentReaderContext(this, contextType, array);
+            return PushContext(contextType, null, array);
         }
 
         internal BsonDocumentReaderContext PushContext(ContextType contextType, BsonDocument document)
         {
-            return new BsonDocumentReaderContext(this, contextType, document);
+            return PushContext(contextType, document, null);
+        }
+
+        private BsonDocumentReaderContext PushContext(ContextType contextType, BsonDocument document, BsonArray array)
+        {
+            if (_cachedPushContext == null)
+                _cachedPushContext = new BsonDocumentReaderContext(this, contextType, document, array);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._document = document;
+                _cachedPushContext._array = array;
+                _cachedPushContext._index = 0;
+            }
+            return _cachedPushContext;
         }
     }
 }
diff --git a/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs b/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
index f82d3152d67..00f25a8e790 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentWriterContext.cs
@@ -18,7 +18,8 @@ namespace MongoDB.Bson.IO
     internal class BsonDocumentWriterContext
     {
         // private fields
-        private BsonDocumentWriterContext _parentContext;
+        private readonly BsonDocumentWriterContext _parentContext;
+        private BsonDocumentWriterContext _cachedPushContext;
         private ContextType _contextType;
         private BsonDocument _document;
         private BsonArray _array;
@@ -39,20 +40,14 @@ internal BsonDocumentWriterContext(
         private BsonDocumentWriterContext(
             BsonDocumentWriterContext parentContext,
             ContextType contextType,
-            BsonArray array)
-        {
-            _parentContext = parentContext;
-            _contextType = contextType;
-            _array = array;
-        }
-
-        private BsonDocumentWriterContext(
-            BsonDocumentWriterContext parentContext,
-            ContextType contextType,
+            BsonDocument document,
+            BsonArray array,
             string code)
         {
             _parentContext = parentContext;
             _contextType = contextType;
+            _document = document;
+            _array = array;
             _code = code;
         }
 
@@ -95,17 +90,32 @@ internal BsonDocumentWriterContext PopContext()
 
         internal BsonDocumentWriterContext PushContext(ContextType contextType, BsonDocument document)
         {
-            return new BsonDocumentWriterContext(this, contextType, document);
+            return PushContext(contextType, document, null, null);
         }
 
         internal BsonDocumentWriterContext PushContext(ContextType contextType, BsonArray array)
         {
-            return new BsonDocumentWriterContext(this, contextType, array);
+            return PushContext(contextType, null, array, null);
         }
 
         internal BsonDocumentWriterContext PushContext(ContextType contextType, string code)
         {
-            return new BsonDocumentWriterContext(this, contextType, code);
+            return PushContext(contextType, null, null, code);
+        }
+
+        private BsonDocumentWriterContext PushContext(ContextType contextType, BsonDocument document, BsonArray array, string code)
+        {
+            if (_cachedPushContext == null)
+                _cachedPushContext = new BsonDocumentWriterContext(this, contextType, document, array, code);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._document = document;
+                _cachedPushContext._array = array;
+                _cachedPushContext._code = code;
+                _cachedPushContext._name = null;
+            }
+            return _cachedPushContext;
         }
     }
 }
diff --git a/src/MongoDB.Bson/IO/JsonReaderContext.cs b/src/MongoDB.Bson/IO/JsonReaderContext.cs
index 8f12af683a1..e93707a4bae 100644
--- a/src/MongoDB.Bson/IO/JsonReaderContext.cs
+++ b/src/MongoDB.Bson/IO/JsonReaderContext.cs
@@ -18,7 +18,8 @@ namespace MongoDB.Bson.IO
     internal class JsonReaderContext
     {
         // private fields
-        private JsonReaderContext _parentContext;
+        private readonly JsonReaderContext _parentContext;
+        private JsonReaderContext _cachedPushContext;
         private ContextType _contextType;
 
         // constructors
@@ -56,7 +57,11 @@ public JsonReaderContext PopContext()
 
         internal JsonReaderContext PushContext(ContextType contextType)
         {
-            return new JsonReaderContext(this, contextType);
+            if (_cachedPushContext == null)
+                _cachedPushContext = new JsonReaderContext(this, contextType);
+            else
+                _cachedPushContext._contextType = contextType;
+            return _cachedPushContext;
         }
     }
 }
diff --git a/src/MongoDB.Bson/IO/JsonWriterContext.cs b/src/MongoDB.Bson/IO/JsonWriterContext.cs
index 609121ee129..cdc8b6c2cee 100644
--- a/src/MongoDB.Bson/IO/JsonWriterContext.cs
+++ b/src/MongoDB.Bson/IO/JsonWriterContext.cs
@@ -18,7 +18,8 @@ namespace MongoDB.Bson.IO
     internal class JsonWriterContext
     {
         // private fields
-        private JsonWriterContext _parentContext;
+        private readonly JsonWriterContext _parentContext;
+        private JsonWriterContext _cachedPushContext;
         private ContextType _contextType;
         private string _indentation;
         private bool _hasElements = false;
@@ -60,7 +61,14 @@ internal JsonWriterContext PopContext()
 
         internal JsonWriterContext PushContext(ContextType contextType, string indentChars)
         {
-            return new JsonWriterContext(this, contextType, indentChars);
+            if (_cachedPushContext == null)
+                _cachedPushContext = new JsonWriterContext(this, contextType, indentChars);
+            else
+            {
+                _cachedPushContext._contextType = contextType;
+                _cachedPushContext._hasElements = false;
+            }
+            return _cachedPushContext;
         }
     }
 }