@@ -4128,6 +4128,66 @@ codegen_validate_keywords(compiler *c, asdl_keyword_seq *keywords)
41284128 return SUCCESS ;
41294129}
41304130
4131+ /* Try to fold frozendict(key=const, ...) into LOAD_CONST with a runtime guard.
4132+ Called after the function has been loaded onto the stack.
4133+ Return 1 if optimization was emitted, 0 if not, -1 on error. */
4134+ static int
4135+ maybe_optimize_frozendict_call (compiler * c , expr_ty e , jump_target_label end )
4136+ {
4137+ expr_ty func = e -> v .Call .func ;
4138+ asdl_expr_seq * args = e -> v .Call .args ;
4139+ asdl_keyword_seq * kwds = e -> v .Call .keywords ;
4140+
4141+ if (func -> kind != Name_kind ||
4142+ !_PyUnicode_EqualToASCIIString (func -> v .Name .id , "frozendict" ) ||
4143+ asdl_seq_LEN (args ) != 0 )
4144+ {
4145+ return 0 ;
4146+ }
4147+
4148+ /* All keywords must have names (no **kwargs) and constant values */
4149+ Py_ssize_t nkwds = asdl_seq_LEN (kwds );
4150+ for (Py_ssize_t i = 0 ; i < nkwds ; i ++ ) {
4151+ keyword_ty kw = asdl_seq_GET (kwds , i );
4152+ if (kw -> arg == NULL || kw -> value -> kind != Constant_kind ) {
4153+ return 0 ;
4154+ }
4155+ }
4156+
4157+ /* Build the frozendict at compile time */
4158+ PyObject * dict = PyDict_New ();
4159+ if (dict == NULL ) {
4160+ return -1 ;
4161+ }
4162+ for (Py_ssize_t i = 0 ; i < nkwds ; i ++ ) {
4163+ keyword_ty kw = asdl_seq_GET (kwds , i );
4164+ if (PyDict_SetItem (dict , kw -> arg , kw -> value -> v .Constant .value ) < 0 ) {
4165+ Py_DECREF (dict );
4166+ return -1 ;
4167+ }
4168+ }
4169+ PyObject * fd = PyFrozenDict_New (dict );
4170+ Py_DECREF (dict );
4171+ if (fd == NULL ) {
4172+ return -1 ;
4173+ }
4174+
4175+ location loc = LOC (func );
4176+ NEW_JUMP_TARGET_LABEL (c , skip_optimization );
4177+
4178+ ADDOP_I (c , loc , COPY , 1 );
4179+ ADDOP_I (c , loc , LOAD_COMMON_CONSTANT , CONSTANT_BUILTIN_FROZENDICT );
4180+ ADDOP_COMPARE (c , loc , Is );
4181+ ADDOP_JUMP (c , loc , POP_JUMP_IF_FALSE , skip_optimization );
4182+ ADDOP (c , loc , POP_TOP );
4183+ ADDOP_LOAD_CONST (c , LOC (e ), fd );
4184+ Py_DECREF (fd );
4185+ ADDOP_JUMP (c , loc , JUMP , end );
4186+
4187+ USE_LABEL (c , skip_optimization );
4188+ return 1 ;
4189+ }
4190+
41314191static int
41324192codegen_call (compiler * c , expr_ty e )
41334193{
@@ -4143,6 +4203,7 @@ codegen_call(compiler *c, expr_ty e)
41434203 RETURN_IF_ERROR (check_caller (c , e -> v .Call .func ));
41444204 VISIT (c , expr , e -> v .Call .func );
41454205 RETURN_IF_ERROR (maybe_optimize_function_call (c , e , skip_normal_call ));
4206+ RETURN_IF_ERROR (maybe_optimize_frozendict_call (c , e , skip_normal_call ));
41464207 location loc = LOC (e -> v .Call .func );
41474208 ADDOP (c , loc , PUSH_NULL );
41484209 loc = LOC (e );
0 commit comments