Skip to content

Commit 59031b6

Browse files
committed
Doesn't matter if size is aligned; heap pointer must be
Add tests.
1 parent a3392df commit 59031b6

File tree

2 files changed

+19
-11
lines changed

2 files changed

+19
-11
lines changed

compiler_tests.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,12 @@ def test_small_string(self) -> None:
4848
def test_small_string_concat(self) -> None:
4949
self.assertEqual(self._run('"abc" ++ "def"'), '"abcdef"\n')
5050

51-
def test_heap_string(self) -> None:
51+
def test_const_large_string(self) -> None:
5252
self.assertEqual(self._run('"hello world"'), '"hello world"\n')
5353

54+
def test_heap_string_concat(self) -> None:
55+
self.assertEqual(self._run('"hello world" ++ " and goodbye"'), '"hello world and goodbye"\n')
56+
5457
def test_const_list(self) -> None:
5558
self.assertEqual(
5659
self._run("""[1, "2", [3, 4], {a=1}, #foo ()]"""),
@@ -69,6 +72,9 @@ def test_mul(self) -> None:
6972
def test_list(self) -> None:
7073
self.assertEqual(self._run("[1, 2, 3]"), "[1, 2, 3]\n")
7174

75+
def test_list_concat(self) -> None:
76+
self.assertEqual(self._run("0 >+ [1, 2, 3]"), "[0, 1, 2, 3]\n")
77+
7278
def test_var(self) -> None:
7379
self.assertEqual(self._run("a . a = 1"), "1\n")
7480

runtime.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,10 @@ struct gc_heap {
124124
struct space space;
125125
};
126126

127-
static uintptr_t align(uintptr_t val, uintptr_t alignment) {
127+
static ALWAYS_INLINE uintptr_t align(uintptr_t val, uintptr_t alignment) {
128128
return (val + alignment - 1) & ~(alignment - 1);
129129
}
130-
static uintptr_t align_size(uintptr_t size) {
130+
static ALWAYS_INLINE uintptr_t align_size(uintptr_t size) {
131131
return align(size, sizeof(uintptr_t));
132132
}
133133

@@ -163,12 +163,20 @@ void init_heap(struct gc_heap* heap, struct space space) {
163163
heap->from_space = heap->limit = heap->hp + space.size / 2;
164164
}
165165

166+
static ALWAYS_INLINE bool is_power_of_two(uword x) { return (x & (x - 1)) == 0; }
167+
168+
static ALWAYS_INLINE bool is_aligned(uword value, uword alignment) {
169+
assert(is_power_of_two(alignment));
170+
return (value & (alignment - 1)) == 0;
171+
}
172+
166173
struct gc_obj* copy(struct gc_heap* heap, struct gc_obj* obj) {
167174
size_t size = heap_object_size(obj);
168175
struct gc_obj* new_obj = (struct gc_obj*)heap->hp;
169176
memcpy(new_obj, obj, size);
170177
forward(obj, new_obj);
171178
heap->hp += align_size(size);
179+
assert(is_aligned(heap->hp, 1 << kPrimaryTagBits) && "need 3 bits for tagging");
172180
return new_obj;
173181
}
174182

@@ -292,13 +300,6 @@ static NEVER_INLINE void heap_grow(struct gc_heap* heap) {
292300
}
293301
#endif
294302

295-
bool is_power_of_two(uword x) { return (x & (x - 1)) == 0; }
296-
297-
bool is_aligned(uword value, uword alignment) {
298-
assert(is_power_of_two(alignment));
299-
return (value & (alignment - 1)) == 0;
300-
}
301-
302303
uword make_tag(uword tag, uword size_bytes) {
303304
assert(size_bytes <= 0xffffffff);
304305
return (size_bytes << kBitsPerByte) | tag;
@@ -321,13 +322,14 @@ static NEVER_INLINE void allocate_slow_path(struct gc_heap* heap, uword size) {
321322

322323
static ALWAYS_INLINE ALLOCATOR struct object* allocate(struct gc_heap* heap,
323324
uword tag, uword size) {
324-
assert(is_aligned(size, 1 << kPrimaryTagBits) && "need 3 bits for tagging");
325325
uintptr_t addr = heap->hp;
326326
uintptr_t new_hp = align_size(addr + size);
327+
assert(is_aligned(new_hp, 1 << kPrimaryTagBits) && "need 3 bits for tagging");
327328
if (UNLIKELY(heap->limit < new_hp)) {
328329
allocate_slow_path(heap, size);
329330
addr = heap->hp;
330331
new_hp = align_size(addr + size);
332+
assert(is_aligned(new_hp, 1 << kPrimaryTagBits) && "need 3 bits for tagging");
331333
}
332334
heap->hp = new_hp;
333335
((struct gc_obj*)addr)->tag = make_tag(tag, size);

0 commit comments

Comments
 (0)