Skip to content

Commit 0ee3162

Browse files
committed
Add pass to instrument memory.grow instructions
1 parent a4966d7 commit 0ee3162

File tree

6 files changed

+159
-0
lines changed

6 files changed

+159
-0
lines changed

src/passes/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ set(passes_SOURCES
5353
Inlining.cpp
5454
InstrumentLocals.cpp
5555
InstrumentMemory.cpp
56+
InstrumentMemoryGrow.cpp
5657
Intrinsics.cpp
5758
J2CLItableMerging.cpp
5859
J2CLOpts.cpp

src/passes/InstrumentMemoryGrow.cpp

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2025 WebAssembly Community Group participants
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
//
18+
// Instruments the build with code to intercept all memory.grow operations.
19+
//
20+
// Before:
21+
// (memory.grow (const.i32 6))
22+
//
23+
// After:
24+
// (call $post_memory_grow
25+
// (i32.const 1) // ID
26+
// (memory.grow
27+
// (call $pre_memory_grow
28+
// (i32.const 1) // ID
29+
// (i32.const 6) // number of pages
30+
// )
31+
// )
32+
// )
33+
//
34+
35+
#include "asmjs/shared-constants.h"
36+
#include <pass.h>
37+
#include <wasm-builder.h>
38+
39+
namespace wasm {
40+
41+
static Name pre_memory_grow("pre_memory_grow");
42+
static Name post_memory_grow("post_memory_grow");
43+
44+
struct InstrumentMemoryGrow
45+
: public WalkerPass<PostWalker<InstrumentMemoryGrow>> {
46+
// Adds calls to new imports.
47+
bool addsEffects() override { return true; }
48+
49+
void visitMemoryGrow(MemoryGrow* curr) {
50+
id++;
51+
Builder builder(*getModule());
52+
auto addressType = getModule()->getMemory(curr->memory)->addressType;
53+
curr->delta =
54+
builder.makeCall(pre_memory_grow,
55+
{builder.makeConst(int32_t(id)), curr->delta},
56+
addressType);
57+
replaceCurrent(builder.makeCall(
58+
post_memory_grow, {builder.makeConst(int32_t(id)), curr}, addressType));
59+
}
60+
61+
void visitModule(Module* curr) {
62+
auto addressType =
63+
curr->memories.empty() ? Type::i32 : curr->memories[0]->addressType;
64+
addImport(curr, pre_memory_grow, {Type::i32, addressType}, addressType);
65+
addImport(curr, post_memory_grow, {Type::i32, addressType}, addressType);
66+
}
67+
68+
private:
69+
Index id;
70+
71+
void addImport(Module* curr, Name name, Type params, Type results) {
72+
auto import = Builder::makeFunction(name, Signature(params, results), {});
73+
import->module = ENV;
74+
import->base = name;
75+
curr->addFunction(std::move(import));
76+
}
77+
};
78+
79+
Pass* createInstrumentMemoryGrowPass() { return new InstrumentMemoryGrow(); }
80+
81+
} // namespace wasm

src/passes/pass.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ void PassRegistry::registerPasses() {
263263
"instrument-memory",
264264
"instrument the build with code to intercept all loads and stores",
265265
createInstrumentMemoryPass);
266+
registerPass(
267+
"instrument-memory-grow",
268+
"instrument the build with code to intercept all memory.grow operations",
269+
createInstrumentMemoryGrowPass);
266270
registerPass(
267271
"licm", "loop invariant code motion", createLoopInvariantCodeMotionPass);
268272
registerPass("limit-segments",

src/passes/passes.h

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ Pass* createIntrinsicLoweringPass();
8181
Pass* createTraceCallsPass();
8282
Pass* createInstrumentLocalsPass();
8383
Pass* createInstrumentMemoryPass();
84+
Pass* createInstrumentMemoryGrowPass();
8485
Pass* createLLVMMemoryCopyFillLoweringPass();
8586
Pass* createLoopInvariantCodeMotionPass();
8687
Pass* createMemory64LoweringPass();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
2+
;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up.
3+
4+
;; RUN: foreach %s %t wasm-opt --instrument-memory-grow -S -o - | filecheck %s
5+
6+
(module
7+
(memory 256 256)
8+
9+
;; CHECK: (type $0 (func (param i32 i32) (result i32)))
10+
11+
;; CHECK: (type $1 (func))
12+
(type $1 (func))
13+
14+
;; CHECK: (import "env" "pre_memory_grow" (func $pre_memory_grow (param i32 i32) (result i32)))
15+
16+
;; CHECK: (import "env" "post_memory_grow" (func $post_memory_grow (param i32 i32) (result i32)))
17+
18+
;; CHECK: (memory $0 256 256)
19+
20+
;; CHECK: (func $A
21+
;; CHECK-NEXT: (drop
22+
;; CHECK-NEXT: (call $post_memory_grow
23+
;; CHECK-NEXT: (i32.const 1)
24+
;; CHECK-NEXT: (memory.grow
25+
;; CHECK-NEXT: (call $pre_memory_grow
26+
;; CHECK-NEXT: (i32.const 1)
27+
;; CHECK-NEXT: (i32.const 4)
28+
;; CHECK-NEXT: )
29+
;; CHECK-NEXT: )
30+
;; CHECK-NEXT: )
31+
;; CHECK-NEXT: )
32+
;; CHECK-NEXT: )
33+
(func $A (type $1)
34+
(drop (memory.grow (i32.const 4)))
35+
)
36+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
2+
;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up.
3+
4+
;; RUN: foreach %s %t wasm-opt --instrument-memory-grow --enable-memory64 -S -o - | filecheck %s
5+
6+
(module
7+
(memory i64 256 256)
8+
9+
;; CHECK: (type $0 (func (param i32 i64) (result i64)))
10+
11+
;; CHECK: (type $1 (func))
12+
(type $1 (func))
13+
14+
;; CHECK: (import "env" "pre_memory_grow" (func $pre_memory_grow (param i32 i64) (result i64)))
15+
16+
;; CHECK: (import "env" "post_memory_grow" (func $post_memory_grow (param i32 i64) (result i64)))
17+
18+
;; CHECK: (memory $0 i64 256 256)
19+
20+
;; CHECK: (func $A
21+
;; CHECK-NEXT: (drop
22+
;; CHECK-NEXT: (call $post_memory_grow
23+
;; CHECK-NEXT: (i32.const 1)
24+
;; CHECK-NEXT: (memory.grow
25+
;; CHECK-NEXT: (call $pre_memory_grow
26+
;; CHECK-NEXT: (i32.const 1)
27+
;; CHECK-NEXT: (i64.const 4)
28+
;; CHECK-NEXT: )
29+
;; CHECK-NEXT: )
30+
;; CHECK-NEXT: )
31+
;; CHECK-NEXT: )
32+
;; CHECK-NEXT: )
33+
(func $A (type $1)
34+
(drop (memory.grow (i64.const 4)))
35+
)
36+
)

0 commit comments

Comments
 (0)