diff --git a/src/docode.c b/src/docode.c
index a7e8b70db23bc3d636e42312569512f28ba247fc..f12a32d1d71b26bdccdc9830f40fb9dd2ad65fd3 100644
--- a/src/docode.c
+++ b/src/docode.c
@@ -1149,6 +1149,17 @@ static int do_docode2(node *n, int flags)
     return 1;
   }
 
+  case F_APPEND_MAPPING: {
+    emit0(F_MARK);
+    PUSH_CLEANUP_FRAME(do_pop_mark, 0);
+    do_docode(CAR(n),DO_LVALUE);
+    emit0(F_CONST0);	/* Reserved for svalue. */
+    do_docode(CDR(n),0);
+    emit0(F_APPEND_MAPPING);
+    POP_AND_DONT_CLEANUP;
+    return 1;
+  }
+
   case '?':
   {
     INT32 *prev_switch_jumptable = current_switch.jumptable;
diff --git a/src/interpret_functions.h b/src/interpret_functions.h
index e67e12c7ac5544ca06b2d231ee0ffbece85d214e..bfffd60b8c4c2393d8d4d2babd1419f96fd522be 100644
--- a/src/interpret_functions.h
+++ b/src/interpret_functions.h
@@ -2021,6 +2021,10 @@ OPCODE0(F_APPEND_ARRAY, "append array", I_UPDATE_SP|I_UPDATE_M_SP, {
     o_append_array(Pike_sp - *(--Pike_mark_sp));
   });
 
+OPCODE0(F_APPEND_MAPPING, "append mapping", I_UPDATE_SP|I_UPDATE_M_SP, {
+    o_append_mapping(Pike_sp - *(--Pike_mark_sp));
+  });
+
 OPCODE2(F_LOCAL_LOCAL_INDEX, "local[local]", I_UPDATE_SP, {
   LOCAL_VAR(struct svalue *s);
   s = Pike_fp->locals + arg1;
diff --git a/src/las.c b/src/las.c
index c4d4e2ab2e94ea2efb7db906f66160b23c5903ea..ba0ae0e11c6daa43c7ff6d90c2246b4aaf388898 100644
--- a/src/las.c
+++ b/src/las.c
@@ -919,6 +919,7 @@ node *debug_mknode(int token, node *a, node *b)
     break;
 
   case F_APPEND_ARRAY:
+  case F_APPEND_MAPPING:
   case F_MULTI_ASSIGN:
   case F_ASSIGN:
   case F_ASSIGN_SELF:
@@ -2742,7 +2743,8 @@ static void find_written_vars(node *n,
     find_written_vars(CDR(n), p, 1);
     break;
 
-    case F_APPEND_ARRAY:
+  case F_APPEND_MAPPING:
+  case F_APPEND_ARRAY:
       find_written_vars(CAR(n), p, 1);
       find_written_vars(CDR(n), p, 0);
       break;
@@ -3199,6 +3201,16 @@ void fix_type_field(node *n)
     }
     break;
 
+  case F_APPEND_MAPPING:
+    if (!CAR(n) || (CAR(n)->type == void_type_string)) {
+      yyerror("Assigning a void expression.");
+      copy_pike_type(n->type, void_type_string);
+    }
+    else
+      /* FIXME: Not really correct, should calculate type of RHS. */
+      copy_pike_type(n->type, CAR(n)->type);
+   break;
+
   case F_APPEND_ARRAY:
     if (!CAR(n) || (CAR(n)->type == void_type_string)) {
       yyerror("Assigning a void expression.");
diff --git a/src/mapping.c b/src/mapping.c
index cfe0e2afaf6ae2076f974059ed9a9af4dea740a8..7421b4d55f22b4631bf937e685dd64567974a3cd 100644
--- a/src/mapping.c
+++ b/src/mapping.c
@@ -1856,6 +1856,39 @@ PMOD_EXPORT struct mapping *merge_mapping_array_unordered(struct mapping *a,
   return m;
 }
 
+void o_append_mapping( INT32 args )
+{
+  struct svalue *lval = Pike_sp - args;
+  struct svalue *val = lval + 2;
+#ifdef PIKE_DEBUG
+  if (args < 3) {
+    Pike_fatal("Too few arguments to o_append_mapping(): %d\n", args);
+  }
+#endif
+  args -= 3;
+  /* Note: val should always be a zero here! */
+  lvalue_to_svalue_no_free(val, lval);
+
+  if (TYPEOF(*val) == T_MAPPING)
+  {
+    struct mapping *m = val->u.mapping;
+    if( m->refs == 2 )
+    {
+      int i;
+      /* fprintf( stderr, "map_refs==2\n" ); */
+      for( i=0; i<args; i+=2 )
+        low_mapping_insert( m, Pike_sp-(i+2), Pike_sp-(i+1), 0 );
+      stack_pop_n_elems_keep_top(2+args);
+      return;
+    }
+  }
+
+  f_aggregate_mapping(args);
+  f_add(2);
+  assign_lvalue(lval, val);
+  stack_pop_2_elems_keep_top();
+}
+
 /* NOTE: May perform destructive operations on either of the arguments
  *       if it has only a single reference.
  */
diff --git a/src/mapping.h b/src/mapping.h
index f4e11165c5358b51b3dc12d9bac75b4ba66e9116..62c790bcd196ed62958aac7a5832776987679552 100644
--- a/src/mapping.h
+++ b/src/mapping.h
@@ -390,6 +390,7 @@ int mapping_is_constant(struct mapping *m,
 			struct processing *p);
 void free_all_mapping_blocks(void);
 
+void o_append_mapping( INT32 args );
 /* Prototypes end here */
 
 #define allocate_mapping(X) dmalloc_touch(struct mapping *,debug_allocate_mapping(X))
diff --git a/src/treeopt.in b/src/treeopt.in
index a66af5c311840f2fdfa5bb2f1ca8e0737ae8db63..4115308a46c769dc2f77dceb470e643cb637b86f 100644
--- a/src/treeopt.in
+++ b/src/treeopt.in
@@ -995,6 +995,21 @@ F_ADD_EQ(0, F_APPLY(F_CONSTANT
 		    [$$->u.sval.u.efun->function == debug_f_aggregate], 1)):
   F_APPEND_ARRAY($0, $1);
 
+
+// a += ([ args... ])  ->  F_APPEND_MAPPING(a, args...)
+F_ADD_EQ(0, F_APPLY(F_CONSTANT
+		    [TYPEOF($$->u.sval) == T_FUNCTION]
+		    [SUBTYPEOF($$->u.sval) == FUNCTION_BUILTIN]
+		    [$$->u.sval.u.efun->function == f_aggregate_mapping], 1)):
+  F_APPEND_MAPPING($0, $1);
+
+// a += ([ args... ])  ->  F_APPEND_MAPPING(a, args...)
+F_OR_EQ(0, F_APPLY(F_CONSTANT
+                   [TYPEOF($$->u.sval) == T_FUNCTION]
+                   [SUBTYPEOF($$->u.sval) == FUNCTION_BUILTIN]
+                   [$$->u.sval.u.efun->function == f_aggregate_mapping], 1)):
+  F_APPEND_MAPPING($0, $1);
+
 F_INDEX(-, 0 = *):
   F_COMMA_EXPR(F_POP_VALUE($0, -), 0);