diff --git a/std/assembly/rt/README.md b/std/assembly/rt/README.md
index 1fb78f57..6e501d92 100644
--- a/std/assembly/rt/README.md
+++ b/std/assembly/rt/README.md
@@ -12,6 +12,9 @@ Interface
Dynamically allocates a chunk of memory of at least the specified size and returns its address.
Alignment is guaranteed to be 16 bytes to fit up to v128 values naturally.
+* **__rt_reallocate**(ref: `usize`, size: `usize`): `usize`
+ Dynamically changes the size of a chunk of memory, possibly moving it to a new address.
+
* **__rt_free**(ref: `usize`): `void`
Frees a dynamically allocated chunk of memory by its address.
diff --git a/std/assembly/rt/stub.ts b/std/assembly/rt/stub.ts
index da02be77..386a202d 100644
--- a/std/assembly/rt/stub.ts
+++ b/std/assembly/rt/stub.ts
@@ -2,7 +2,7 @@ import { AL_MASK, CommonBlock } from "./common";
// @ts-ignore: decorator
@inline
-const BLOCK_OVERHEAD = offsetof();
+const BLOCK_OVERHEAD = (offsetof() + AL_MASK) & ~AL_MASK;
// @ts-ignore: decorator
@inline
@@ -43,9 +43,15 @@ function __rt_allocate(size: usize, id: u32): usize {
@unsafe @global
function __rt_reallocate(ref: usize, size: usize): usize {
var block = changetype(ref - BLOCK_OVERHEAD);
- var newRef = __rt_allocate(size, block.rtId);
- memory.copy(newRef, ref, block.rtSize);
- return newRef;
+ var oldSize = block.rtSize;
+ if (size > oldSize) {
+ let newRef = __rt_allocate(size, block.rtId);
+ memory.copy(newRef, ref, oldSize);
+ ref = newRef;
+ } else {
+ block.rtSize = size;
+ }
+ return ref;
}
// @ts-ignore: decorator