diff --git a/python/dune/perftool/compile.py b/python/dune/perftool/compile.py
index 627eec43b223c2941ba198411fab387a1a7ac05d..67ec44bbb6d997d6a3fdc8bc02c0b70436e87d00 100644
--- a/python/dune/perftool/compile.py
+++ b/python/dune/perftool/compile.py
@@ -92,4 +92,4 @@ def compile_form():
                 filename = name_localoperator_file(formdata, data)
 
                 from dune.perftool.pdelab.localoperator import generate_localoperator_file
-                generate_localoperator_file(kernels, filename)
+                generate_localoperator_file(formdata, kernels, filename)
diff --git a/python/dune/perftool/pdelab/driver.py b/python/dune/perftool/pdelab/driver.py
index 2ed58b4a9876475383b2eb6850762d13faac6f8d..4aab981edad9fac379a3610c5fba918929290f96 100644
--- a/python/dune/perftool/pdelab/driver.py
+++ b/python/dune/perftool/pdelab/driver.py
@@ -1145,7 +1145,7 @@ def dune_solve():
         go = name_gridoperator(formdata)
         x = name_vector(formdata)
         include_file("dune/perftool/matrixfree.hh", filetag="driver")
-        solve = "solveMatrixFree({},{});".format(go, x)
+        solve = "solveNonlinearMatrixFree({},{});".format(go, x)
     elif not linear and not matrix_free:
         go_type = type_gridoperator(_driver_data['formdata'])
         go = name_gridoperator(_driver_data['formdata'])
diff --git a/python/dune/perftool/pdelab/localoperator.py b/python/dune/perftool/pdelab/localoperator.py
index 592e606b1baf174845cf4ed741e6f76b73efdf8c..2596e099bdb5be7e19ef33ec8314be3c8819d3e1 100644
--- a/python/dune/perftool/pdelab/localoperator.py
+++ b/python/dune/perftool/pdelab/localoperator.py
@@ -165,11 +165,15 @@ def assembler_routine_name():
     return "{}_{}".format(part1, part2)
 
 
-def assembly_routine_signature():
+def assembly_routine_signature(formdata):
     from dune.perftool.generation import get_global_context_value
     integral_type = get_global_context_value("integral_type")
     form_type = get_global_context_value("form_type")
 
+    # Check if form is linear
+    from dune.perftool.pdelab.driver import is_linear
+    linear = is_linear(formdata.preprocessed_form)
+
     if form_type == 'residual':
         if integral_type == 'cell':
             from dune.perftool.pdelab.signatures import alpha_volume_signature
@@ -193,15 +197,26 @@ def assembly_routine_signature():
             return jacobian_skeleton_signature()
 
     if form_type == 'jacobian_apply':
-        if integral_type == 'cell':
-            from dune.perftool.pdelab.signatures import jacobian_apply_volume_signature
-            return jacobian_apply_volume_signature()
-        if integral_type == 'exterior_facet':
-            from dune.perftool.pdelab.signatures import jacobian_apply_boundary_signature
-            return jacobian_apply_boundary_signature()
-        if integral_type == 'interior_facet':
-            from dune.perftool.pdelab.signatures import jacobian_apply_skeleton_signature
-            return jacobian_apply_skeleton_signature()
+        if linear:
+            if integral_type == 'cell':
+                from dune.perftool.pdelab.signatures import jacobian_apply_volume_signature
+                return jacobian_apply_volume_signature()
+            if integral_type == 'exterior_facet':
+                from dune.perftool.pdelab.signatures import jacobian_apply_boundary_signature
+                return jacobian_apply_boundary_signature()
+            if integral_type == 'interior_facet':
+                from dune.perftool.pdelab.signatures import jacobian_apply_skeleton_signature
+                return jacobian_apply_skeleton_signature()
+        else:
+            if integral_type == 'cell':
+                from dune.perftool.pdelab.signatures import nonlinear_jacobian_apply_volume_signature
+                return nonlinear_jacobian_apply_volume_signature()
+            if integral_type == 'exterior_facet':
+                from dune.perftool.pdelab.signatures import nonlinear_jacobian_apply_boundary_signature
+                return nonlinear_jacobian_apply_boundary_signature()
+            if integral_type == 'interior_facet':
+                from dune.perftool.pdelab.signatures import nonlinear_jacobian_apply_skeleton_signature
+                return nonlinear_jacobian_apply_skeleton_signature()
 
     assert False
 
@@ -522,14 +537,14 @@ def generate_localoperator_kernels(formdata, data):
     return operator_kernels
 
 
-def generate_localoperator_file(kernels, filename):
+def generate_localoperator_file(formdata, kernels, filename):
     operator_methods = []
 
     # Make generables from the given kernels
     for method, kernel in kernels.items():
         it, ft = method
         with global_context(integral_type=it, form_type=ft):
-            signature = assembly_routine_signature()
+            signature = assembly_routine_signature(formdata)
             operator_methods.append(AssemblyMethod(signature, kernel, filename))
 
     if get_option('timer'):
diff --git a/python/dune/perftool/pdelab/signatures.py b/python/dune/perftool/pdelab/signatures.py
index e778b5952ac299f852c4bb071c8e933a00a74207..103cf761d0ab4dac5c02b64a74c836e625309751 100644
--- a/python/dune/perftool/pdelab/signatures.py
+++ b/python/dune/perftool/pdelab/signatures.py
@@ -345,3 +345,123 @@ def jacobian_apply_skeleton_signature():
                 avt,
                 av_n,)
             ]
+
+
+@symbol
+def nonlinear_jacobian_apply_volume_signature():
+    geot = type_geometry_wrapper()
+    geo = name_geometry_wrapper()
+    lfsut = type_trialfunctionspace()
+    lfsu = name_trialfunctionspace(Restriction.NONE)
+    lfsvt = type_testfunctionspace()
+    lfsv = name_testfunctionspace(Restriction.NONE)
+    cct = type_coefficientcontainer()
+    cc = name_coefficientcontainer(Restriction.NONE)
+    ac = name_applycontainer(Restriction.NONE)
+    avt = type_accumulation_variable()
+    av = name_accumulation_variable((Restriction.NONE,))
+    return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot,
+                                                                                               lfsut,
+                                                                                               cct,
+                                                                                               lfsvt,
+                                                                                               avt,
+                                                                                               ),
+            'void jacobian_apply_volume(const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}) const'.format(
+                geot,
+                geo,
+                lfsut,
+                lfsu,
+                cct,
+                cc,
+                cct,
+                ac,
+                lfsvt,
+                lfsv,
+                avt,
+                av,)
+            ]
+
+
+@symbol
+def nonlinear_jacobian_apply_boundary_signature():
+    geot = type_geometry_wrapper()
+    geo = name_geometry_wrapper()
+    lfsut = type_trialfunctionspace()
+    lfsu = name_trialfunctionspace(Restriction.NEGATIVE)
+    lfsvt = type_testfunctionspace()
+    lfsv = name_testfunctionspace(Restriction.NEGATIVE)
+    cct = type_coefficientcontainer()
+    cc = name_coefficientcontainer(Restriction.NEGATIVE)
+    ac = name_applycontainer(Restriction.NEGATIVE)
+    avt = type_accumulation_variable()
+    av = name_accumulation_variable((Restriction.NEGATIVE,))
+    return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot,
+                                                                                               lfsut,
+                                                                                               cct,
+                                                                                               lfsvt,
+                                                                                               avt,
+                                                                                               ),
+            'void jacobian_apply_boundary(const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}) const'.format(
+                geot,
+                geo,
+                lfsut,
+                lfsu,
+                cct,
+                cc,
+                cct,
+                ac,
+                lfsvt,
+                lfsv,
+                avt,
+                av,)
+            ]
+
+
+@symbol
+def nonlinear_jacobian_apply_skeleton_signature():
+    geot = type_geometry_wrapper()
+    geo = name_geometry_wrapper()
+    lfsut = type_trialfunctionspace()
+    lfsu_s = name_trialfunctionspace(Restriction.NEGATIVE)
+    lfsu_n = name_trialfunctionspace(Restriction.POSITIVE)
+    lfsvt = type_testfunctionspace()
+    lfsv_s = name_testfunctionspace(Restriction.NEGATIVE)
+    lfsv_n = name_testfunctionspace(Restriction.POSITIVE)
+    cct = type_coefficientcontainer()
+    cc_s = name_coefficientcontainer(Restriction.NEGATIVE)
+    cc_n = name_coefficientcontainer(Restriction.POSITIVE)
+    ac_s = name_applycontainer(Restriction.NEGATIVE)
+    ac_n = name_applycontainer(Restriction.POSITIVE)
+    avt = type_accumulation_variable()
+    av_s = name_accumulation_variable((Restriction.NEGATIVE,))
+    av_n = name_accumulation_variable((Restriction.POSITIVE,))
+    return ['template<typename {}, typename {}, typename {}, typename {}, typename {}>'.format(geot,
+                                                                                               lfsut,
+                                                                                               cct,
+                                                                                               lfsvt,
+                                                                                               avt,
+                                                                                               ),
+            'void nonlinear_jacobian_apply_skeleton(const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, const {}& {}, {}& {}, {}& {}) const'.format(
+                geot,
+                geo,
+                lfsut,
+                lfsu_s,
+                cct,
+                cc_s,
+                cct,
+                ac_s,
+                lfsvt,
+                lfsv_s,
+                lfsut,
+                lfsu_n,
+                cct,
+                cc_n,
+                cct,
+                ac_n,
+                lfsvt,
+                lfsv_n,
+                avt,
+                av_s,
+                avt,
+                av_n,)
+            ]