From 9c72b1146bf6bc85a205c212705cc8bde1bbfbbd Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Thu, 25 Jun 2026 21:49:01 +0300 Subject: [PATCH] Add write-side inline cache for obj.prop = value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reads of `obj.prop` already use a version-gated own-property inline cache in JintMemberExpression.GetValue that skips the dictionary lookup on repeat reads. Writes had no equivalent: every `obj.prop = value` rented a Reference, called PutValue, re-hashed the property key, and did a dictionary lookup before the in-place store. Add TryAssignFast as the write-side counterpart, reusing the same cache slots. When the receiver is a PlainObject whose shape is unchanged and the own property is a live writable, non-accessor, non-custom data descriptor, the value is written straight into the descriptor with no Reference rent, key hash, or lookup — exactly the in-place store ObjectInstance.Set already performs (which by design does not bump _propertiesVersion). The writability/data/custom flags are re-read live on every store, because Object.defineProperty mutates them in place without a version bump. The fast path declines only at the eligibility gate (before evaluating anything); once base and RHS are evaluated (each once, in spec order) it always completes the assignment, falling back to PutValue rented from the already-resolved base+key for absent / accessor / read-only / custom-value / non-PlainObject cases — so a side-effecting base or RHS is never evaluated twice and prototype-setter, CreateDataProperty, and strict read-only semantics are preserved. Benchmarks (net10.0, AMD 5950X): ObjectAccess.UpdateObjectProperty -9.5..13%, new WriteObjectProperty (pure write, write-miss population) -14%, PropertyAlloc.Constructor1 -11%; allocations unchanged; no read-path or Test262 regressions. Co-Authored-By: Claude Opus 4.8 (1M context) --- Jint.Benchmark/ObjectAccessBenchmark.cs | 15 +++ .../Expressions/JintAssignmentExpression.cs | 12 ++- .../Expressions/JintMemberExpression.cs | 92 +++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/Jint.Benchmark/ObjectAccessBenchmark.cs b/Jint.Benchmark/ObjectAccessBenchmark.cs index e3886c9fef..8fca1a8561 100644 --- a/Jint.Benchmark/ObjectAccessBenchmark.cs +++ b/Jint.Benchmark/ObjectAccessBenchmark.cs @@ -6,11 +6,19 @@ namespace Jint.Benchmark; public class ObjectAccessBenchmark { private readonly Prepared