diff --git a/pd/src/g_clone.c b/pd/src/g_clone.c
index bb85141a4dd698c36e8d4c2d92628bb82db4d554..2529161e6de5da95ad0291e413b39d86a16018be 100644
--- a/pd/src/g_clone.c
+++ b/pd/src/g_clone.c
@@ -144,6 +144,14 @@ static void clone_in_vis(t_in *x, t_floatarg fn, t_floatarg vis)
     canvas_vis(x->i_owner->x_vec[n].c_gl, (vis != 0));
 }
 
+static void clone_in_fwd(t_in *x, t_symbol *s, int argc, t_atom *argv)
+{
+    if(s != gensym("fwd"))
+        typedmess(&x->i_pd, s, argc, argv);
+    else
+        pd_error(x->i_owner, "clone-inlet: no method for 'fwd'");
+}
+
 static void clone_out_anything(t_out *x, t_symbol *s, int argc, t_atom *argv)
 {
     t_atom *outv;
@@ -405,7 +413,8 @@ static void *clone_new(t_symbol *s, int argc, t_atom *argv)
             obj_issignalinlet(&x->x_vec[0].c_gl->gl_obj, i);
         x->x_invec[i].i_n = i;
         if (x->x_invec[i].i_signal)
-            signalinlet_new(&x->x_obj, 0);
+            inlet_new(&x->x_obj, &x->x_invec[i].i_pd,
+                &s_signal, &s_signal);
         else inlet_new(&x->x_obj, &x->x_invec[i].i_pd, 0, 0);
     }
     x->x_nout = obj_noutlets(&x->x_vec[0].c_gl->gl_obj);
@@ -458,6 +467,8 @@ void clone_setup(void)
         A_GIMME, 0);
     class_addmethod(clone_in_class, (t_method)clone_in_vis, gensym("vis"),
         A_FLOAT, A_FLOAT, 0);
+    class_addmethod(clone_in_class, (t_method)clone_in_fwd, gensym("fwd"),
+        A_GIMME, 0);
     class_addlist(clone_in_class, (t_method)clone_in_list);
 
     clone_out_class = class_new(gensym("clone-outlet"), 0, 0,
diff --git a/pd/src/g_io.c b/pd/src/g_io.c
index c7330bf635d50c5c9f7c86743b3a0b8047b80653..eee1af66c3906f59210068faa3140745dab6cfa8 100644
--- a/pd/src/g_io.c
+++ b/pd/src/g_io.c
@@ -36,8 +36,8 @@ typedef struct _vinlet
   /* if not reblocking, the next slot communicates the parent's inlet
      signal from the prolog to the DSP routine: */
     t_signal *x_directsignal;
-
-  t_resample x_updown;
+    t_resample x_updown;
+    t_outlet *x_fwdout;  /* optional outlet for forwarding messages to inlet~ */
 } t_vinlet;
 
 static void *vinlet_new(t_symbol *s)
@@ -116,6 +116,19 @@ t_int *vinlet_perform(t_int *w)
     return (w+4);
 }
 
+static void vinlet_fwd(t_vinlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+    if(x->x_fwdout) /* inlet~ fwd */
+        outlet_anything(x->x_fwdout, s, argc, argv);
+    else if(x->x_buf == 0) /* inlet, need to forward message because we want
+                                it to accept fwd selector */
+        outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
+    else /* inlet~ without fwd */
+        pd_error(x->x_canvas, "inlet~: expected 'signal' but got '%s' "
+            "(Note: [inlet~] does not forward non-signal messages unless "
+            "argument 'fwd' is defined)", s->s_name);
+}
+
 static void vinlet_dsp(t_vinlet *x, t_signal **sp)
 {
     t_signal *outsig;
@@ -251,8 +264,10 @@ static void *vinlet_newsig(t_symbol *s)
     x->x_endbuf = x->x_buf = (t_float *)getbytes(0);
     x->x_bufsize = 0;
     x->x_directsignal = 0;
+    x->x_fwdout = 0;
     outlet_new(&x->x_obj, &s_signal);
-
+    /* this line was in pd vanilla but I don't think it is necessary
+       inlet_new(&x->x_obj, (t_pd *)x->x_inlet, 0, 0); */
     resample_init(&x->x_updown);
 
     /* this should be thought over: 
@@ -265,6 +280,8 @@ static void *vinlet_newsig(t_symbol *s)
     else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */
     else x->x_updown.method=0;                        /* up: zero-padding */
 
+    if (s == gensym("fwd"))         /* turn on forwarding */
+        x->x_fwdout = outlet_new(&x->x_obj, 0);
     return (x);
 }
 
@@ -279,6 +296,8 @@ static void vinlet_setup(void)
     class_addsymbol(vinlet_class, vinlet_symbol);
     class_addlist(vinlet_class, vinlet_list);
     class_addanything(vinlet_class, vinlet_anything);
+    class_addmethod(vinlet_class,(t_method)vinlet_fwd,  gensym("fwd"),
+        A_GIMME, 0);
     class_addmethod(vinlet_class, (t_method)vinlet_dsp, gensym("dsp"),
         A_CANT, 0);
     class_sethelpsymbol(vinlet_class, gensym("pd"));
diff --git a/pd/src/m_class.c b/pd/src/m_class.c
index f59edbb309e92d40448bb10a099be22e96204175..a398ffb15351846dfaa22cc209dd452928a04c4a 100644
--- a/pd/src/m_class.c
+++ b/pd/src/m_class.c
@@ -1182,3 +1182,37 @@ t_gotfn zgetfn(t_pd *x, t_symbol *s)
         if (m->me_name == s) return(m->me_fun);
     return(0);
 }
+
+t_gotfn zcheckgetfn(t_pd *x, t_symbol *s, t_atomtype arg1, ...)
+{
+    t_class *c = *x;
+    t_methodentry *m;
+    int i, j;
+
+    /* get arg types */
+    va_list ap;
+    int nargs = 0;
+    t_atomtype args[MAXPDARG+1], curr = arg1;
+    va_start(ap, arg1);
+    while (curr != A_NULL && nargs < MAXPDARG)
+    {
+        args[nargs++] = curr;
+        curr = va_arg(ap, t_atomtype);
+    }
+    if (curr != A_NULL) error("zcheckgetfn: only 5 arguments are typecheckable");
+    args[nargs] = A_NULL;
+    va_end(ap);
+
+    for (i = c->c_nmethod, m = c->c_methods; i--; m++)
+    {
+        if (m->me_name == s)
+        {
+            j = 0;
+            /* both argtype lists are valid, dont need to check whether j < MAXDPARG */
+            while(m->me_arg[j] != A_NULL && args[j] != A_NULL
+                    && m->me_arg[j] == args[j]) j++;
+            if(m->me_arg[j] == A_NULL && args[j] == A_NULL) return(m->me_fun);
+        }
+    }
+    return(0);
+}
diff --git a/pd/src/m_obj.c b/pd/src/m_obj.c
index ea1dd5dd2b73ddcaee60de608b2dbfe9072998e8..725ecf42514a51b4d7274165ecd502d0611070e1 100644
--- a/pd/src/m_obj.c
+++ b/pd/src/m_obj.c
@@ -80,6 +80,36 @@ static void inlet_wrong(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
         x->i_symfrom->s_name, s->s_name, type_hint(s, argc, argv, 1));
 }
 
+    /* forward a message to an inlet~ object */
+static int inlet_fwd(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
+{
+    if(x->i_symfrom == &s_signal
+        && zcheckgetfn(x->i_dest, gensym("fwd"), A_GIMME, A_NULL))
+    {
+        mess3(x->i_dest, gensym("fwd"), s, argc, argv);
+        return 1;
+    }
+    return 0;
+}
+
+static int inlet_fwd_symbol(t_inlet *x, t_symbol *s)
+{
+    t_atom sym; SETSYMBOL(&sym, s);
+    return inlet_fwd(x, &s_symbol, 1, &sym);
+}
+
+static int inlet_fwd_blob(t_inlet *x, t_blob *st)
+{
+    t_atom blob; SETBLOB(&blob, st);
+    return inlet_fwd(x, &s_blob, 1, &blob);
+}
+
+static int inlet_fwd_pointer(t_inlet *x, t_gpointer *gp)
+{
+    t_atom ptr; SETPOINTER(&ptr, gp);
+    return inlet_fwd(x, &s_pointer, 1, &ptr);
+}
+
 static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv);
 
     /* LATER figure out how to make these efficient: */
@@ -90,7 +120,8 @@ static void inlet_bang(t_inlet *x)
     else if (!x->i_symfrom) pd_bang(x->i_dest);
     else if (x->i_symfrom == &s_list)
         inlet_list(x, &s_bang, 0, 0);
-    else inlet_wrong(x, &s_bang, 0, 0);
+    else if (!inlet_fwd(x, &s_bang, 0, 0))
+        inlet_wrong(x, &s_bang, 0, 0);
 }
 
 static void inlet_pointer(t_inlet *x, t_gpointer *gp)
@@ -104,7 +135,8 @@ static void inlet_pointer(t_inlet *x, t_gpointer *gp)
         SETPOINTER(&a, gp);
         inlet_list(x, &s_pointer, 1, &a);
     }
-    else inlet_wrong(x, &s_pointer, 0, 0);
+    else if (!inlet_fwd_pointer(x, gp))
+        inlet_wrong(x, &s_pointer, 0, 0);
 }
 
 static void inlet_float(t_inlet *x, t_float f)
@@ -129,7 +161,7 @@ static void inlet_symbol(t_inlet *x, t_symbol *s)
     if (x->i_symfrom == &s_symbol) 
         pd_vmess(x->i_dest, x->i_symto, "s", s);
     else if (!x->i_symfrom) pd_symbol(x->i_dest, s);
-    else
+    else if (!inlet_fwd_symbol(x, s))
     {
         t_atom a;
         SETSYMBOL(&a, s);
@@ -153,7 +185,7 @@ static void inlet_blob(t_inlet *x, t_blob *st) /* MP20061226 blob type */
         /*post("inlet_blob calling pd_blob");*/
         pd_blob(x->i_dest, st);
     }
-    else
+    else if (!inlet_fwd_blob(x, st))
     {
         /*post("inlet_blob calling inlet_wrong");*/
         inlet_wrong(x, &s_blob, 0, 0);
@@ -172,7 +204,8 @@ static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
       inlet_float(x, atom_getfloat(argv));
     else if (argc==1 && argv->a_type == A_SYMBOL)
       inlet_symbol(x, atom_getsymbol(argv));
-    else inlet_wrong(x, &s_list, 0, 0);
+    else if (!inlet_fwd(x, &s_list, argc, argv))
+        inlet_wrong(x, &s_list, 0, 0);
 }
 
 static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
@@ -181,7 +214,8 @@ static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
         typedmess(x->i_dest, x->i_symto, argc, argv);
     else if (!x->i_symfrom)
         typedmess(x->i_dest, s, argc, argv);
-    else inlet_wrong(x, s, 0, 0);
+    else if (!inlet_fwd(x, s, argc, argv))
+        inlet_wrong(x, s, 0, 0);
 }
 
 void inlet_free(t_inlet *x)
diff --git a/scripts/regression_tests.pd b/scripts/regression_tests.pd
index cf661a67804247163d5fe7b551ff45a83d50a0c0..e8f29fc6eca1e8b1f09661edbd81c3bae5c9f5b8 100644
--- a/scripts/regression_tests.pd
+++ b/scripts/regression_tests.pd
@@ -1,7 +1,7 @@
-#N canvas 243 24 750 572 12;
+#N canvas 244 48 750 572 12;
 #X obj 465 281 r \$0-result;
-#X obj 212 239 bng 15 250 50 0 empty empty Run_all 17 7 0 10 #fcfcfc
-#000000 #000000;
+#X obj 212 239 bng 15 250 50 0 empty empty Run_all 17 7 0 10 -262144
+-1 -1;
 #X obj 56 25 r init;
 #X obj 345 191 route dollarzero;
 #X obj 198 281 rtest msg_dollarzero;
@@ -25,7 +25,7 @@ is handy for some binbuf tests.;
 #X obj 198 659 rtest makefilename_double_percent;
 #X obj 198 710 rtest makefilename_code_coverage;
 #N canvas 461 242 450 323 (subpatch) 0;
-#X restore 201 2415 pd;
+#X restore 201 2555 pd;
 #X obj 198 761 rtest makefilename_default;
 #X obj 198 812 rtest makefilename_default_bang;
 #X obj 198 863 rtest makefilename_float;
@@ -62,6 +62,8 @@ is handy for some binbuf tests.;
 #X obj 198 2196 rtest iemgui_color_symbolargs;
 #X obj 198 2251 rtest log_right_inlet;
 #X obj 198 2306 rtest log_base;
+#X obj 198 2361 rtest inlet~_no_fwd;
+#X obj 198 2416 rtest inlet~_fwd_large_message;
 #X connect 0 0 27 0;
 #X connect 1 0 4 0;
 #X connect 2 0 42 0;
@@ -109,3 +111,5 @@ is handy for some binbuf tests.;
 #X connect 53 0 54 0;
 #X connect 54 0 55 0;
 #X connect 55 0 56 0;
+#X connect 56 0 57 0;
+#X connect 57 0 58 0;
diff --git a/scripts/regression_tests/inlet~_fwd_large_message.pd b/scripts/regression_tests/inlet~_fwd_large_message.pd
new file mode 100644
index 0000000000000000000000000000000000000000..e8b34272e24cfe8e500167083639d60f52234f55
--- /dev/null
+++ b/scripts/regression_tests/inlet~_fwd_large_message.pd
@@ -0,0 +1,23 @@
+#N canvas 240 193 835 453 12;
+#X obj 57 22 inlet;
+#X obj 57 260 outlet;
+#X msg 57 51 bang;
+#X obj 321 27 array define \$0-big;
+#X obj 318 160 array size \$0-big;
+#X msg 318 135 5e+06;
+#X obj 132 138 array get \$0-big;
+#N canvas 0 0 450 300 \$0-fwd-test~ 0;
+#X obj 61 40 inlet~ fwd;
+#X restore 132 176 pd \$0-fwd-test~;
+#X obj 57 79 trigger bang bang bang;
+#X obj 57 138 f 1;
+#X obj 57 215 list append large messages to [inlet~ fwd] should not
+blow the stack;
+#X connect 0 0 2 0;
+#X connect 2 0 8 0;
+#X connect 5 0 4 0;
+#X connect 8 0 9 0;
+#X connect 8 1 6 0;
+#X connect 8 2 5 0;
+#X connect 9 0 10 0;
+#X connect 10 0 1 0;
diff --git a/scripts/regression_tests/inlet~_no_fwd.pd b/scripts/regression_tests/inlet~_no_fwd.pd
new file mode 100644
index 0000000000000000000000000000000000000000..2ade5b6fffe6d30d76ea8b7737f2f431d7319cd1
--- /dev/null
+++ b/scripts/regression_tests/inlet~_no_fwd.pd
@@ -0,0 +1,23 @@
+#N canvas 239 169 507 299 12;
+#X obj 57 22 inlet;
+#X obj 57 230 outlet;
+#N canvas 0 0 450 300 \$0-test~ 0;
+#X obj 61 40 inlet~;
+#X restore 171 146 pd \$0-test~;
+#X obj 132 117 unpost;
+#X obj 57 117 list;
+#X obj 57 146 list length;
+#X obj 57 185 list append non-signal message to inlet~ should trigger
+an error;
+#X msg 57 51 bang;
+#X obj 57 79 trigger bang bang bang;
+#X connect 0 0 7 0;
+#X connect 3 0 4 1;
+#X connect 3 1 2 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X connect 7 0 8 0;
+#X connect 8 0 4 0;
+#X connect 8 1 3 0;
+#X connect 8 2 4 1;