release the allocator when an updated value escapes to a query (#306)
This commit is contained in:
1 parent
d3960aff31
commit
0a32e14537
3 files changed
+42
-5
No files matched your search
@@ -5502,6 +5502,22 @@
|
|||||||
expected: |
|
expected: |
|
||||||
[1,3,6,5,5]
|
[1,3,6,5,5]
|
||||||
|
|
||||||
|
- name: update-assignment operator against object with overlapping paths
|
||||||
|
args:
|
||||||
|
- -c
|
||||||
|
- '(.a.b,.a,.a.p.z) |= {p: ., q: .}'
|
||||||
|
input: '{"a":{"b":1}}'
|
||||||
|
expected: |
|
||||||
|
{"a":{"p":{"b":{"p":1,"q":1},"z":{"p":null,"q":null}},"q":{"b":{"p":1,"q":1}}}}
|
||||||
|
|
||||||
|
- name: update-assignment operator against nested object with overlapping paths
|
||||||
|
args:
|
||||||
|
- -c
|
||||||
|
- '(.a.b.c,.a,.a.p.b.z) |= {p: ., q: .}'
|
||||||
|
input: '{"a":{"b":{"c":1}}}'
|
||||||
|
expected: |
|
||||||
|
{"a":{"p":{"b":{"c":{"p":1,"q":1},"z":{"p":null,"q":null}}},"q":{"b":{"c":{"p":1,"q":1}}}}}
|
||||||
|
|
||||||
- name: update-assignment operator with optional operator
|
- name: update-assignment operator with optional operator
|
||||||
args:
|
args:
|
||||||
- -c
|
- -c
|
||||||
|
|||||||
+6
-5
@@ -1093,7 +1093,7 @@ func (c *compiler) compileModify() {
|
|||||||
&code{op: opcall, v: [3]any{funcAllocator, 0, "_allocator"}},
|
&code{op: opcall, v: [3]any{funcAllocator, 0, "_allocator"}},
|
||||||
&code{op: opstore, v: a},
|
&code{op: opstore, v: a},
|
||||||
&code{op: opload, v: v},
|
&code{op: opload, v: v},
|
||||||
&code{op: opfork, v: len(c.codes) + 39}, // reduce [L1]
|
&code{op: opfork, v: len(c.codes) + 40}, // reduce [L1]
|
||||||
&code{op: oppathbegin}, // path(p)
|
&code{op: oppathbegin}, // path(p)
|
||||||
&code{op: opload, v: p},
|
&code{op: opload, v: p},
|
||||||
&code{op: opcallpc},
|
&code{op: opcallpc},
|
||||||
@@ -1102,12 +1102,13 @@ func (c *compiler) compileModify() {
|
|||||||
&code{op: opstore, v: p}, // as $p (.;
|
&code{op: opstore, v: p}, // as $p (.;
|
||||||
&code{op: opforklabel, v: l}, // label $l |
|
&code{op: opforklabel, v: l}, // label $l |
|
||||||
&code{op: opload, v: v}, //
|
&code{op: opload, v: v}, //
|
||||||
&code{op: opfork, v: len(c.codes) + 36}, // [L2]
|
&code{op: opfork, v: len(c.codes) + 37}, // [L2]
|
||||||
&code{op: oppop}, // (getpath($p) |
|
&code{op: oppop}, // (getpath($p) |
|
||||||
&code{op: opload, v: a},
|
&code{op: opload, v: a},
|
||||||
|
&code{op: opload, v: a},
|
||||||
&code{op: opload, v: p},
|
&code{op: opload, v: p},
|
||||||
&code{op: opload, v: v},
|
&code{op: opload, v: v},
|
||||||
&code{op: opcall, v: [3]any{internalFuncs["getpath"].callback, 1, "getpath"}},
|
&code{op: opcall, v: [3]any{funcGetpathWithAllocator, 2, "getpath"}},
|
||||||
&code{op: opload, v: f}, // f)
|
&code{op: opload, v: f}, // f)
|
||||||
&code{op: opcallpc},
|
&code{op: opcallpc},
|
||||||
&code{op: opload, v: p}, // setpath($p; ...)
|
&code{op: opload, v: p}, // setpath($p; ...)
|
||||||
@@ -1115,8 +1116,8 @@ func (c *compiler) compileModify() {
|
|||||||
&code{op: opcall, v: [3]any{funcSetpathWithAllocator, 3, "_setpath"}},
|
&code{op: opcall, v: [3]any{funcSetpathWithAllocator, 3, "_setpath"}},
|
||||||
&code{op: opstore, v: v},
|
&code{op: opstore, v: v},
|
||||||
&code{op: opload, v: v}, // ., break $l
|
&code{op: opload, v: v}, // ., break $l
|
||||||
&code{op: opfork, v: len(c.codes) + 34}, // [L4]
|
&code{op: opfork, v: len(c.codes) + 35}, // [L4]
|
||||||
&code{op: opjump, v: len(c.codes) + 38}, // [L3]
|
&code{op: opjump, v: len(c.codes) + 39}, // [L3]
|
||||||
&code{op: opload, v: l}, // [L4]
|
&code{op: opload, v: l}, // [L4]
|
||||||
&code{op: opcall, v: [3]any{funcBreak(""), 0, "_break"}},
|
&code{op: opcall, v: [3]any{funcBreak(""), 0, "_break"}},
|
||||||
&code{op: opload, v: p}, // append $p to $d [L2]
|
&code{op: opload, v: p}, // append $p to $d [L2]
|
||||||
|
|||||||
@@ -1488,6 +1488,17 @@ func (a allocator) allocated(v any) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// release forgets every allocated address when the value is one of them, so
|
||||||
|
// that a value handed to a query is copied on update again.
|
||||||
|
func (a allocator) release(v any) {
|
||||||
|
switch v.(type) {
|
||||||
|
case map[string]any, []any:
|
||||||
|
if a.allocated(v) {
|
||||||
|
clear(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a allocator) makeObject(l int) map[string]any {
|
func (a allocator) makeObject(l int) map[string]any {
|
||||||
v := make(map[string]any, l)
|
v := make(map[string]any, l)
|
||||||
if a != nil {
|
if a != nil {
|
||||||
@@ -1514,6 +1525,15 @@ func funcSetpathWithAllocator(v any, args []any) any {
|
|||||||
return setpath(v, args[0], args[1], args[2].(allocator))
|
return setpath(v, args[0], args[1], args[2].(allocator))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used in compiler#compileModify: the update function may store the value
|
||||||
|
// anywhere, so it must not be modified in place afterwards. Registered as
|
||||||
|
// getpath to keep tracking paths through the call.
|
||||||
|
func funcGetpathWithAllocator(v any, args []any) any {
|
||||||
|
w := funcGetpath(v, args[0])
|
||||||
|
args[1].(allocator).release(w)
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
func setpath(v, p, n any, a allocator) any {
|
func setpath(v, p, n any, a allocator) any {
|
||||||
path, ok := p.([]any)
|
path, ok := p.([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
Reference in new issue
Block a user