From fd175115f793cfe7e767598e63b056c5bac90cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?= <grubba@grubba.org> Date: Wed, 25 Mar 2015 20:54:12 +0100 Subject: [PATCH] Runtime: Fixed over optimization of F_APPEND_MAPPING. F_APPEND_MAPPING now has the same special cases as F_APPEND_ARRAY. Fixes obj->map += ([ x:y ]) and obj["map"] += ([ x:y ]) when obj has lfun::`->=() and/or lfun::`[]=(). --- src/mapping.c | 21 +++++++++++++++------ src/testsuite.in | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/mapping.c b/src/mapping.c index 07c35c8273..5126ba9c39 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -1891,12 +1891,21 @@ void o_append_mapping( INT32 args ) 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), 2 ); - stack_pop_n_elems_keep_top(2+args); - return; + if ((TYPEOF(*lval) == T_OBJECT) && + lval->u.object->prog && + ((FIND_LFUN(lval->u.object->prog, LFUN_ASSIGN_INDEX) >= 0) || + (FIND_LFUN(lval->u.object->prog, LFUN_ASSIGN_ARROW) >= 0))) { + /* There's a function controlling assignments in this object, + * so we can't alter the mapping in place. + */ + } else { + 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), 2 ); + stack_pop_n_elems_keep_top(2+args); + return; + } } } diff --git a/src/testsuite.in b/src/testsuite.in index e8ac2a8774..4e69fc128f 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -4112,6 +4112,29 @@ test_any([[ return has_index(a->_modified, "foo"); ]], 1) +test_any([[ + // Since the addition of F_APPEND_MAPPING in set_bar below + // the setter is not being called anymore. Instead, the mapping + // _data->foo is modified in place. + class A(mapping foo) { + mapping _modified = ([]); + + mixed `->=(string sym, mixed v) { + return _modified[sym] = v; + } + + void set_bar(int v) { + this->foo += ([ "bar" : v ]); + } + }; + + object a = A(([ "foo" : ([]) ])); + + a->set_bar(2); + + return has_index(a->_modified, "foo"); +]], 1) + test_any([[ // Since the addition of F_APPEND_ARRAY the setter is not being // called anymore. Instead, the array _data is modified in place. -- GitLab