Skip to content

Commit 649ae0e

Browse files
jhonabreulclaude
andcommitted
Skip encoder inspection on ToPython when no encoders registered
Extends the previous TryEncode optimization to the EncodableByUser gate in Converter.ToPython. Previously every value conversion ran Type.GetTypeCode plus enum/type checks before TryEncode could cheaply short-circuit on the cached "no encoders" flag. EncodableByUser now checks HasEncoders first and returns false immediately when none are registered (the common case), so the entire encoder branch - including the type inspection - is skipped on the hot per-value conversion path. Also drop a redundant value.GetType() in EncodableByUser: the local already holds value.GetType() at every call site, so compare against it directly. Behavior is unchanged: with no encoders the branch was always going to fall through; with encoders, HasEncoders is true so the gate reduces to the previous EncodableByUser check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent a6f616f commit 649ae0e

2 files changed

Lines changed: 16 additions & 1 deletion

File tree

src/runtime/Codecs/PyObjectConversions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ public static class PyObjectConversions
2424
// Set when an encoder is registered, cleared on Reset (shutdown).
2525
static volatile bool hasEncoders;
2626

27+
/// <summary>
28+
/// True once at least one encoder has been registered. Lets hot conversion
29+
/// paths skip encoder inspection entirely when none are registered.
30+
/// </summary>
31+
internal static bool HasEncoders => hasEncoders;
32+
2733
/// <summary>
2834
/// Registers specified encoder (marshaller)
2935
/// <para>Python.NET will pick suitable encoder/decoder registered first</para>

src/runtime/Converter.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,10 +741,19 @@ internal static bool ToManagedValue(BorrowedReference value, Type obType,
741741

742742
static bool EncodableByUser(Type type, object value)
743743
{
744+
// When no encoders are registered (the common case) skip the type
745+
// inspection entirely: this runs on the hot per-value conversion path.
746+
if (!PyObjectConversions.HasEncoders)
747+
{
748+
return false;
749+
}
750+
751+
// type is already value.GetType() at every call site, so compare against
752+
// it directly instead of calling GetType again.
744753
TypeCode typeCode = Type.GetTypeCode(type);
745754
return type.IsEnum
746755
|| typeCode is TypeCode.DateTime or TypeCode.Decimal
747-
|| typeCode == TypeCode.Object && value.GetType() != typeof(object) && value is not Type;
756+
|| typeCode == TypeCode.Object && type != typeof(object) && value is not Type;
748757
}
749758

750759
static object? ToPyObjectSubclass(ConstructorInfo ctor, PyObject instance, bool setError)

0 commit comments

Comments
 (0)