Skip to content

Commit

Permalink
Allow multiple arguments for delete()
Browse files Browse the repository at this point in the history
Implements passing of multiple arguments to delete().

E.g. you can now do

@x[1] = 1;
@x[2] = 2;
@c = 5;
delete(@x[1], @x[2], @c);

instead of having to call delete() separately for each individual map
element.
  • Loading branch information
arthurshau authored and ajor committed Mar 14, 2024
1 parent 9c18d26 commit 5aa2ffa
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 19 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ and this project adheres to
- [#3027](https://github.com/bpftrace/bpftrace/pull/3027)
- Add LLVM 18 support
- [#3051](https://github.com/bpftrace/bpftrace/pull/3051)
- Add ability to call delete() with multiple arguments
- [#3046](https://github.com/bpftrace/bpftrace/pull/3046)
#### Changed
#### Deprecated
#### Removed
Expand Down
9 changes: 6 additions & 3 deletions man/adoc/bpftrace.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2292,8 +2292,8 @@ Functions that are marked *async* are asynchronous which can lead to unexpected
| Count how often this function is called.
| Sync

| <<map-functions-delete, `delete(mapkey k)`>>
| Delete a single key from a map. For a single value map this deletes the only element. For an associative-array the key to delete has to be specified.
| <<map-functions-delete, `delete(mapkey k, ...)`>>
| Delete a single key from a map. For a single value map this deletes the only element. For an associative-array the key to delete has to be specified. Multiple arguments can be passed to delete many keys at once.
| Sync

| <<map-functions-hist, `hist(int64 n[, int k])`>>
Expand Down Expand Up @@ -2399,18 +2399,21 @@ i:s:10 {
=== delete

.variants
* `delete(mapkey k)`
* `delete(mapkey k, ...)`

Delete a single key from a map.
For a single value map this deletes the only element.
For an associative-array the key to delete has to be specified.
Multiple arguments can be passed to delete many keys at once.

```
k:dummy {
@scalar = 1;
@associative[1,2] = 1;
delete(@scalar);
delete(@associative[1,2]);
// alternatively, you can delete both at once
delete(@scalar, @associative[1,2]);

delete(@associative); // error
}
Expand Down
23 changes: 12 additions & 11 deletions src/ast/passes/codegen_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,17 +555,18 @@ void CodegenLLVM::visit(Call &call)
b_.CreateLifetimeEnd(key);
expr_ = nullptr;
} else if (call.func == "delete") {
auto &arg = *call.vargs->at(0);
auto &map = static_cast<Map &>(arg);
auto [key, scoped_key_deleter] = getMapKey(map);
if (!is_bpf_map_clearable(map_types_[map.ident])) {
// store zero instead of calling bpf_map_delete_elem()
AllocaInst *val = b_.CreateAllocaBPF(map.type, map.ident + "_zero");
b_.CreateStore(Constant::getNullValue(b_.GetType(map.type)), val);
b_.CreateMapUpdateElem(ctx_, map, key, val, call.loc);
b_.CreateLifetimeEnd(val);
} else {
b_.CreateMapDeleteElem(ctx_, map, key, call.loc);
for (const auto &arg : *call.vargs) {
auto &map = static_cast<Map &>(*arg);
auto [key, scoped_key_deleter] = getMapKey(map);
if (!is_bpf_map_clearable(map_types_[map.ident])) {
// store zero instead of calling bpf_map_delete_elem()
AllocaInst *val = b_.CreateAllocaBPF(map.type, map.ident + "_zero");
b_.CreateStore(Constant::getNullValue(b_.GetType(map.type)), val);
b_.CreateMapUpdateElem(ctx_, map, key, val, call.loc);
b_.CreateLifetimeEnd(val);
} else {
b_.CreateMapDeleteElem(ctx_, map, key, call.loc);
}
}
expr_ = nullptr;
} else if (call.func == "str") {
Expand Down
11 changes: 6 additions & 5 deletions src/ast/passes/semantic_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,12 +606,13 @@ void SemanticAnalyser::visit(Call &call)
call.type = CreateStats(true);
} else if (call.func == "delete") {
check_assignment(call, false, false, false);
if (check_nargs(call, 1)) {
auto &arg = *call.vargs->at(0);
if (!arg.is_map)
LOG(ERROR, call.loc, err_) << "delete() expects a map to be provided";
if (check_varargs(call, 1, std::numeric_limits<size_t>::max())) {
for (const auto &arg : *call.vargs) {
if (!arg->is_map)
LOG(ERROR, arg->loc, err_)
<< "delete() only expects maps to be provided";
}
}

call.type = CreateNone();
} else if (call.func == "str") {
if (check_varargs(call, 1, 2)) {
Expand Down
6 changes: 6 additions & 0 deletions tests/runtime/basic
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ PROG BEGIN { @ = 1; @a[1] = 1; delete(@); delete(@a[1]); printf("ok\n"); exit();
EXPECT ok
TIMEOUT 1

NAME delete multiple-map
PROG BEGIN { @ = 1; @a[1] = 1; delete(@, @a[1]); exit(); }
EXPECT_NONE @: 1
EXPECT_NONE @a[1]: 1
TIMEOUT 1

NAME delete count-map
PROG BEGIN { @ = count(); @a[1] = count(); delete(@); delete(@a[1]); exit(); }
EXPECT @: 0
Expand Down
16 changes: 16 additions & 0 deletions tests/semantic_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,13 +538,29 @@ TEST(semantic_analyser, call_stats)
TEST(semantic_analyser, call_delete)
{
test("kprobe:f { @x = 1; delete(@x); }", 0);
test("kprobe:f { @x = 1; @y = 2; delete(@x, @y); }", 0);
test("kprobe:f { @x = 1; @y[5] = 5; delete(@x, @y[5]); }", 0);
test("kprobe:f { delete(1); }", 1);
test("kprobe:f { delete(); }", 1);
test("kprobe:f { @y = delete(@x); }", 1);
test("kprobe:f { $y = delete(@x); }", 1);
test("kprobe:f { @[delete(@x)] = 1; }", 1);
test("kprobe:f { @x = 1; if(delete(@x)) { 123 } }", 10);
test("kprobe:f { @x = 1; delete(@x) ? 0 : 1; }", 10);

test_error("kprobe:f { @x = 1; @y[5] = 5; delete(@x, @y); }", R"(
stdin:1:42-44: ERROR: Argument mismatch for @y: trying to access with arguments: [] when map expects arguments: [unsigned int64]
kprobe:f { @x = 1; @y[5] = 5; delete(@x, @y); }
~~
)");
test_error("kprobe:f { @x = 1; $y = 2; $c = 3; delete(@x, $y, $c); }", R"(
stdin:1:47-49: ERROR: delete() only expects maps to be provided
kprobe:f { @x = 1; $y = 2; $c = 3; delete(@x, $y, $c); }
~~
stdin:1:51-53: ERROR: delete() only expects maps to be provided
kprobe:f { @x = 1; $y = 2; $c = 3; delete(@x, $y, $c); }
~~
)");
}

TEST(semantic_analyser, call_exit)
Expand Down

0 comments on commit 5aa2ffa

Please sign in to comment.