Repository navigation
Shadow the function call, argument and fetch handlers natively - #6530
Merged
Merged
Conversation
ondrejmirtes
force-pushed
the
turbo-native-function-and-fetch-handlers
branch
from
September 22, 2026 12:09
ede92ae to
28754fe
Compare
Ports processArgs()/processDroppedArgs() with the twin's DI arginfo, exported as pt_arguments_handler_process_args() / _process_dropped_args(); the call handlers' CallHandlerSupport sites use them. Walk state, arg records and per-arg locals live in one emalloc'ed block, the argument loop runs under pt_engine_with_stack(). NodeScopeResolver, AssignHandler, the method reflections and SimpleImpurePoint are called through their direct entries (adds pt_node_scope_resolver_look_for_unset_allowed_undefined_expressions / _is_returning/_is_consuming_stored_expression_results), ClosureProcessor & co. through cached sites. Adds MutatingScope entries (push/popInFunctionCall, restoreThis, ...) and pt_type_utils_find_callable_type(). Class-map key added: closureHandler. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
…atively Ports the by-reference mode singletons (kept in the twin's static $registry) and the dummy parameter value classes. Entries: pt_passed_by_reference_create_*(), _mode(), _combine(), pt_dummy_parameter_new()/_construct(), pt_extended_dummy_parameter_new(); ParameterValues.h reads their slots in place. ArgumentsHandler reads parameters through those slots, TypeTraits and NativeParameterReflection use the entries. Class-map keys removed: passedByReference, dummyParameter, extendedDummyParameter; added: allowedConstantsResult. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
Ports the named-argument reordering: reorderArgs(), the four reorder*Arguments() and the call_user_func*() variants, exported as pt_arguments_normalizer_reorder_*(). A call without named arguments answers with the call itself without the array_values() copy; parameters are read through their DummyParameter slots, call arguments through pt_call_like_args(). CallHandlerSupport, MethodCallReturnTypeHelper and ClassReflection call the entries. Differential: reordering observations in tests/type-family.php. Class-map key removed: argumentsNormalizer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
Ports variant selection, the intrinsic argument overrides (array_map/filter/walk/find, curl_setopt(_array) incl. the option type table, implode, Closure::bind), the template predicates and variant combination; exported as pt_parameters_acceptor_selector_*(). applyIntrinsicArgOverrides() reads through callables or, for selectFromArgs(), the scope directly; ArgumentsHandler passes its native closure holders without \Closure wrappers. The Type, helper, call-handler and scope callers use the entries. Class-map key removed: parametersAcceptorSelector; added: genericParametersAcceptorResolver, functionVariant, extendedCallableFunctionVariant. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
FuncCallScopeEffectsHelper's by-ref array function effects, paired-read invalidations, possibly-impure remembering, extract(), output-buffer and volatile-expression invalidation run natively; applyCallScopeEffects() and applyArrayWalkResult() are exported as pt_func_call_scope_effects_helper_*, OutputBufferHelper as pt_output_buffer_helper_get_level_delta/_apply_level_delta. FunctionReflectionAccess.cpp reads NativeFunctionReflection's name/variants/ throw type/asserts/hasSideEffects/isBuiltin, ExtendedFunctionVariant's return type and parameters, ExtendedNativeParameterReflection::isOptional() and Assertions::getAll() from their slots (the method for any other class). New MutatingScope entries: after_extract_call, after_clearstatcache_call, after_open_ssl_call. AssignHandler and the CallLike arguments are reached through their direct entries; GeneralizePrecision stays PHP behind a cached site. Class map: nativeFunctionReflection. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
processExpr() (dynamic and named callees, immediately invoked closures, clone-with, array_walk's by-ref gatherer, __invoke) runs natively with the typeCallback / specifyTypesCallback / createTypesCallback / gatherer as native closures (the typeCallback keeps its real WeakReference to the storage); resolveReturnType(), specifyTypes(), isFuncCallNarrowable(), getFunctionThrowPoint(), getDynamicFunctionReturnType() and the compact() variable flow are native. New entries: pt_type_specifier_get_function_type_specifying_extensions, pt_early_terminating_call_helper_is_early_terminating_function_call, pt_args_result_with_resolved_parameters_acceptor, pt_arguments_normalizer_reorder_call_user_func_arguments/_array_arguments, AnalyserValues readers pt_statement_result_exit_points and pt_simple_impure_point_identifier/_description; reorderFuncArguments() and the call_user_func reorders join CallHandlerSupport.h. ArgumentsHandler, ArgumentsNormalizer, ParametersAcceptorSelector, the storage primer, SimpleImpurePoint, AssignHandler and the CallLike arguments are called through their direct entries; extensions through per-class direct-mapped sites. Class map: cloneHandler, cloneExpr, closureReturnStatementsNode. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
pt_reflection_provider_has_function() / _get_function() answer hasFunction() / getFunction() of a MemoizingReflectionProvider over a BetterReflectionProvider from its resolvedFunctionNames and functionReflections memos (nameResolutionCacheKey() rebuilt from the scope's namespace and the Name's slot, exit/die answering themselves); a miss, any other provider, name class or answerer calls the method, which resolves and memoizes. FuncCallHandler, DefaultNarrowingHelper, TypeSpecifier's function-call impurity gate and ConstantStringType's callable checks use them. Class map key betterReflectionProvider. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
…ertyFetchHandler and PropertyHookThrowPointsResolver natively The three property fetch handlers with their type, specify-types, create-types and issetability reflection-resolver callbacks as native closures (the nullsafe left-falsey-scope memo a shared reference capture), registered as handler entries; AssignHandler's composeResult(), set-hook and PhpVersion sites switched to the new pt_property_fetch_handler_compose_result / pt_static_property_fetch_handler_compose_result / pt_property_hook_throw_points_resolver_get_throw_points_from_property_hook entries. The per-fetch property reflection getters read the slots of the final Resolved/ChangedType/PhpPropertyReflection chain, PhpMethodFromParserNodeReflection and PhpVersion in place (pt_property_reflection_*, pt_php_version_supports_property_hooks). New entries: pt_mutating_scope_get_instance_property_reflection / _is_in_write_expression_assign, pt_class_reflection_has_native_property / _get_native_property, pt_non_nullability_helper_get_active_ensured_original_type / _ensure_shallow_non_nullability / _revert_non_nullability, pt_node_scope_resolver_process_expr_node_consuming_stored. Class-map keys nullsafePropertyFetchExpressionNode and phpVersion. Twin quirk mirrored: StaticPropertyFetchHandler::composeResult() drops its staticPropertyAccess impure point when the class is an expression. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
The offset fetch handler with its `$arr[]` and offset type callbacks and both specify-types callbacks as native closures, registered as the class's handler entry; the ArrayAccess offsetGet throw points and return type (MethodThrowPointHelper, MethodCallReturnTypeHelper) and the offset-read variable flow run natively. AssignHandler's composeResult() site uses the new pt_array_dim_fetch_handler_compose_result entry. VariableWriteOffset::fromType() is native too (pt_variable_write_offset_from_type, with a smoke differential), and VariableFlowBuilder calls it directly. Class-map key removed: variableWriteOffset. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
The constant and class constant fetch handlers with their type and specify-types callbacks as native closures (the class-type callback ClassConstFetchHandler hands to InitializerExprTypeResolver too), registered as handler entries. The true / false / null literals, the namespaced and global tracked constant fetches (MutatingScope::hasExpressionType() / getTrackedExpressionType()) resolve natively; ConstantResolver::resolveConstant() / resolveConstantType() and InitializerExprTypeResolver::getClassConstFetchTypeByReflection() stay PHP behind cached method sites. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
Ports processAttributeGroups() and processParams() with the twins' DI arginfo, exported as pt_attributes_handler_process_attribute_groups() / pt_parameters_processor_process_params(); StmtHandlerCalls.h's ptsh helpers (the declaration handlers' calls) now use them. An empty attribute or parameter list answers without a call. MutatingScope::resolveName(), the reflection provider and ClassReflection, the method reflection's variants, ParametersAcceptorSelector, ArgumentsNormalizer, ArgumentsHandler and NodeScopeResolver are called through their direct entries, so the attribute-argument closure recursion stays native. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q3SmhnNkB3pEeVRTxqbdbu
ondrejmirtes
force-pushed
the
turbo-native-function-and-fetch-handlers
branch
from
September 22, 2026 12:28
28754fe to
3a093d3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Shadows the function-call path, the argument machinery and the property, offset and constant fetch handlers natively. Apart from the
#[ShadowedByTurboExtension]/#[ReferencedByTurboExtension]attributes, the PHP twins are unchanged.Arguments
ArgumentsHandler:processArgs()/processDroppedArgs(). Walk state, argument records and per-argument locals live in one allocated block, and the argument loop runs underpt_engine_with_stack().PassedByReference,DummyParameterandExtendedDummyParameter, read in place throughParameterValues.h.ArgumentsNormalizer: named-argument reordering, including thecall_user_func*()variants. A call without named arguments returns the call itself, with no copy.ParametersAcceptorSelector: variant selection and the intrinsic argument overrides (array_map/filter/walk/find,curl_setopt(_array)with its option type table,implode,Closure::bind), plus variant combination.Function calls
FuncCallHandler.processExpr()covers dynamic and named callees, immediately invoked closures, clone-with,array_walk's by-reference gatherer and__invoke. Its callbacks are native closures, and return-type resolution, narrowing, throw points andcompact()'s variable flow are native too.FuncCallScopeEffectsHelperandOutputBufferHelper: by-reference array-function effects, paired-read invalidations,extract(), output-buffer level tracking and volatile-expression invalidation.hasFunction()/getFunction()of a memoizing provider over BetterReflection are answered from the provider's memos. A miss or any other provider calls the method as before.Fetch handlers
PropertyFetchHandler,StaticPropertyFetchHandler,NullsafePropertyFetchHandlerandPropertyHookThrowPointsResolver. The per-fetch property reflection getters read the slots of the final reflection chain in place.ArrayDimFetchHandler, including theArrayAccessoffsetGetthrow points and return type, andVariableWriteOffset.ConstFetchHandlerandClassConstFetchHandler. Thetrue/false/nullliterals and tracked constant fetches resolve natively;ConstantResolverand the initializer resolver stay PHP behind cached method sites.Declarations
AttributesHandlerandParametersProcessor, so the attribute-argument closure recursion stays native. An empty attribute or parameter list returns without a call.Verification
With the extension loaded and active:
side-by-side.php,signature-parity.phpandsmoke.phppass, andwalk-trace.phpreports identical traces (612,287 lines).make tests,make phpstan,make cs,make lint,make lint-turboandmake sanitize-turboare clean.make pgowith the strict flags passes under GCC 11.4 (CI's gnu image) against PHP 8.4 and PHP 8.6.🤖 Generated with Claude Code
https://claude.ai/code/session_017MvPby652L7wUqGAHEiEcN