This is an automated email from the ASF dual-hosted git repository.

papegaaij pushed a commit to branch wicket-6774
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit 234ff1c36a51f6acc41b9371be7d3288e5b7ea0c
Author: Emond Papegaaij <[email protected]>
AuthorDate: Sat Sep 5 14:18:23 2026 +0200

    WICKET-6774: do not store a model that lazy initialisation did not find
    
    getDefaultModel() memoises the inherited model lookup: when a component has 
no
    model of its own, initModel() walks the parent chain for an
    IComponentInheritedModel and, on a hit, allocates a wrapper bound to this
    component, which setModelImpl() then stores so the next call is cheap. The
    matching invalidation lives in detach().
    
    It also stored the misses, and storing a miss records nothing, because the 
null
    leaves FLAG_MODEL_SET clear and the next call walks the hierarchy again 
anyway.
    So the write bought nothing while costing two field stores, to data and to
    flags, on every call for a component without a model. Most components have
    none: of 548285 components measured on a production application, 61% carry 
no
    model. Master pays nothing here only incidentally, its setModelImpl() 
falling
    through both branches when the flag is clear.
    
    Skipping the call is a no-op by construction. FLAG_MODEL_SET is set exactly
    when a non-null model was stored, and only setModelImpl() writes the model
    slot, so getModelImpl() returning null implies the flag is clear; with the 
flag
    clear ComponentState.setModel(null, data, false) returns data unchanged down
    every branch and the setFlag() is already false. Nothing overrides
    setModelImpl() or getModelImpl(), and initModel() raises
    FLAG_INHERITABLE_MODEL only on the path that returns non-null.
    
    Measured with wicket-benchmarks, reading models over an array of components,
    harness overhead subtracted, ns per component:
    
                            master   before    after
        model present        1.117    0.871    0.889
        model absent         0.316    1.399    0.352
        mixed                0.654    1.197    0.340
    
    The absent path was 4.4x master and is now level with it, and reading state
    over interleaved components is faster than master rather than 83% slower.
    
    Note that a miss is still not memoised, on master or here: every
    getDefaultModel() on a component without a model re-walks its ancestors.
    Fixing that needs somewhere to record that the lookup already failed.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 wicket-core/src/main/java/org/apache/wicket/Component.java | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/wicket-core/src/main/java/org/apache/wicket/Component.java 
b/wicket-core/src/main/java/org/apache/wicket/Component.java
index 9bd693b7e3..896cf8c2f1 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Component.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Component.java
@@ -1400,7 +1400,10 @@ public abstract class Component
                {
                        // give subclass a chance to lazy-init model
                        model = initModel();
-                       setModelImpl(model);
+                       if (model != null)
+                       {
+                               setModelImpl(model);
+                       }
                }
 
                return model;

Reply via email to