Skip to content

Commit fdda9b6

Browse files
authored
Merge pull request #229 from nature-lang/feature/union_variable_size
feat: type_union value variable size
2 parents 6df4649 + c4d9517 commit fdda9b6

File tree

26 files changed

+663
-263
lines changed

26 files changed

+663
-263
lines changed

runtime/allocator.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
static uint8_t calc_sizeclass(uint64_t size) {
66
// 快速路径:精确判断常见大小
77
if (size == 1) return 1; // class 1: 8 bytes
8-
if (size == 2) return 2; // class 2: 16 bytes, n_union_t,n_interface_t
8+
if (size == 2) return 2; // class 2: 16 bytes, small structs (e.g. n_interface_t)
99
if (size == 40) return 5; // class 5: 48 bytes, n_string_t/n_vec_t
1010
if (size == 56) return 6; // class 6: 64 bytes, n_map_t
1111
if (size == 128) return 10; // class 10: 128 bytes, map default space

runtime/builtin.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ static char *space = " ";
1111

1212
// type_any_t 是 nature 中的类型,在 c 中是认不出来的
1313
// 这里按理来说应该填写 void*, 写 type_any_t 就是为了语义明确
14-
static void print_arg(n_union_t *arg) {
14+
static void print_arg(n_any_t *arg) {
1515
char sprint_buf[1024];
1616

1717
assert(arg && "[runtime.print_arg] arg is null");
@@ -20,9 +20,11 @@ static void print_arg(n_union_t *arg) {
2020
DEBUGF("[runtime.print_arg] arg->rtype=%p, kind=%s, arg->value=%lu", arg->rtype, type_kind_str[arg->rtype->kind],
2121
arg->value.i64_value);
2222

23+
void *value_ptr = arg->value.ptr_value;
24+
2325
if (arg->rtype->kind == TYPE_STRING) {
2426
// n_string_t 在内存视角,应该是由 2 块内存组成,一个是字符个数,一个是指向的数据结构(同样是内存视角)
25-
n_string_t *s = arg->value.ptr_value;// 字符串的内存视角
27+
n_string_t *s = value_ptr;// 字符串的内存视角
2628
assert(s && "[runtime.print_arg] string is null");
2729

2830
DEBUGF("[runtime.print_arg] string=%p, length=%lu, data=%p, len=%lu, cap=%lu, hash=%ld, element_size=%ld",
@@ -115,7 +117,7 @@ static void print_arg(n_union_t *arg) {
115117
}
116118

117119
// 其他所有类型都打印 ptr 地址
118-
int n = sprintf(sprint_buf, "%p", arg->value.ptr_value);
120+
int n = sprintf(sprint_buf, "%p", value_ptr);
119121
VOID write(STDOUT_FILENO, sprint_buf, n);
120122
}
121123

@@ -133,12 +135,12 @@ void print(n_vec_t args) {
133135
addr_t p = base + (i * element_size);
134136

135137
// 将 p 中存储的地址赋值给 a, 此时 a 中存储的是一个堆中的地址,其结构是 memory_any_t
136-
// void* p 只是转换为指针类型,而不会读取其中的值,所以这里 n_union_t* 是目标值, *value 才是读取 p 中的地址
137-
n_union_t *union_arg = (n_union_t *) p;
138+
// void* p 只是转换为指针类型,而不会读取其中的值,所以这里 n_any_t* 是目标值, *value 才是读取 p 中的地址
139+
n_any_t *any_arg = (n_any_t *) p;
138140

139-
DEBUGF("[runtime.print] union arg i=%d, addr=%p, union_arg_value=%p ", i, (void *) p, union_arg);
141+
DEBUGF("[runtime.print] any arg i=%d, addr=%p, any_arg_value=%p ", i, (void *) p, any_arg);
140142

141-
print_arg(union_arg);
143+
print_arg(any_arg);
142144
}
143145
}
144146

@@ -155,12 +157,12 @@ void println(n_vec_t args) {
155157
addr_t p = base + (i * element_size);
156158

157159
// 将 p 中存储的地址赋值给 a, 此时 a 中存储的是一个堆中的地址,其结构是 memory_any_t
158-
// void* p 只是转换为指针类型,而不会读取其中的值,所以这里 n_union_t* 是目标值, *value 才是读取 p 中的地址
159-
n_union_t *union_arg = (n_union_t *) p;
160+
// void* p 只是转换为指针类型,而不会读取其中的值,所以这里 n_any_t* 是目标值, *value 才是读取 p 中的地址
161+
n_any_t *any_arg = (n_any_t *) p;
160162

161-
DEBUGF("[runtime.println] union arg i=%d, addr=%p, union_arg_value=%p ", i, (void *) p, union_arg);
163+
DEBUGF("[runtime.println] any arg i=%d, addr=%p, any_arg_value=%p ", i, (void *) p, any_arg);
162164

163-
print_arg(union_arg);
165+
print_arg(any_arg);
164166

165167
if (i < (args.length - 1)) {
166168
VOID write(STDOUT_FILENO, space, 1);

runtime/nutils/map.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ n_map_t *rt_map_alloc(uint64_t rtype_hash, uint64_t key_rhash, uint64_t value_rh
117117
return map_heap;
118118
}
119119

120+
void rt_map_new_out(n_map_t *out, uint64_t rtype_hash, uint64_t key_rhash, uint64_t value_rhash) {
121+
n_map_t map_data = rt_map_new(rtype_hash, key_rhash, value_rhash);
122+
*out = map_data;
123+
DEBUGF("[rt_map_new_out] success, out=%p, len=%lu, cap=%lu", out, out->length, out->capacity);
124+
}
125+
120126
/**
121127
* m["key"] = v
122128
* @param m

runtime/nutils/map.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ n_map_t rt_map_new(uint64_t rtype_hash, uint64_t key_rhash, uint64_t value_rhash
99

1010
n_map_t *rt_map_alloc(uint64_t rtype_hash, uint64_t key_rhash, uint64_t value_rhash);
1111

12+
void rt_map_new_out(n_map_t *out, uint64_t rtype_hash, uint64_t key_rhash, uint64_t value_rhash);
13+
1214
uint64_t rt_map_length(n_map_t *l);
1315

1416
void map_grow(n_map_t *m);

runtime/nutils/nutils.c

Lines changed: 107 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,46 @@ void union_assert(n_union_t *mu, int64_t target_rtype_hash, void *value_ref) {
8181

8282
rtype_t *rtype = rt_find_rtype(target_rtype_hash);
8383
if (rtype->storage_kind == STORAGE_KIND_IND) {
84-
memmove(value_ref, mu->value.ptr_value, rtype->storage_size);
84+
memmove(value_ref, &mu->value.struct_, rtype->storage_size);
8585
} else {
8686
memmove(value_ref, &mu->value, rtype->storage_size);
8787
}
8888
DEBUGF(
8989
"[union_assert] success, union_base: %p, union_rtype_kind: %s, heap_out_size: %lu, union_i64_value: %ld, "
9090
"values_ref: %p",
91-
mu, type_kind_str[mu->rtype->kind], size, mu->value.i64_value, value_ref);
91+
mu, type_kind_str[mu->rtype->kind], rtype->storage_size, mu->value.i64_value, value_ref);
92+
}
93+
94+
void any_assert(n_any_t *mu, int64_t target_rtype_hash, void *value_ref) {
95+
if (mu->rtype->hash != target_rtype_hash) {
96+
DEBUGF("[any_assert] type assert failed, mu->rtype->kind: %s, target_rtype_hash: %ld",
97+
type_kind_str[mu->rtype->kind],
98+
target_rtype_hash);
99+
100+
rti_throw("type assert failed", true);
101+
return;
102+
}
103+
104+
rtype_t *rtype = rt_find_rtype(target_rtype_hash);
105+
if (rtype->storage_kind == STORAGE_KIND_IND) {
106+
memmove(value_ref, mu->value.ptr_value, rtype->storage_size);
107+
} else {
108+
memmove(value_ref, &mu->value, rtype->storage_size);
109+
}
110+
DEBUGF(
111+
"[any_assert] success, any_base: %p, any_rtype_kind: %s, heap_out_size: %lu, any_i64_value: %ld, "
112+
"values_ref: %p",
113+
mu, type_kind_str[mu->rtype->kind], rtype->storage_size, mu->value.i64_value, value_ref);
92114
}
93115

94116
bool union_is(n_union_t *mu, int64_t target_rtype_hash) {
95117
return mu->rtype->hash == target_rtype_hash;
96118
}
97119

120+
bool any_is(n_any_t *mu, int64_t target_rtype_hash) {
121+
return mu->rtype->hash == target_rtype_hash;
122+
}
123+
98124
bool interface_is(n_interface_t *mu, int64_t target_rtype_hash) {
99125
return mu->rtype->hash == target_rtype_hash;
100126
}
@@ -163,7 +189,8 @@ n_interface_t *interface_casting(uint64_t input_rtype_hash, void *value_ref, int
163189
* @param value
164190
* @return
165191
*/
166-
n_union_t union_casting(int64_t input_rtype_hash, void *value_ref) {
192+
void union_casting(n_union_t *out, int64_t input_rtype_hash, void *value_ref) {
193+
assert(out && "union_casting out is null");
167194
// - 根据 input_rtype_hash 找到对应的
168195
rtype_t *rtype = rt_find_rtype(input_rtype_hash);
169196
assert(rtype && "cannot find rtype by hash");
@@ -172,41 +199,92 @@ n_union_t union_casting(int64_t input_rtype_hash, void *value_ref) {
172199

173200
TRACEF("[union_casting] input_kind=%s", type_kind_str[rtype->kind]);
174201

202+
DEBUGF("[union_casting] union_base: %p, memmove value_ref(%p) -> any->value(%p), size=%lu, fetch_value_8byte=%p",
203+
out, value_ref,
204+
&out->value, rtype->storage_size, (void *) fetch_addr_value((addr_t) value_ref));
205+
out->rtype = rtype;
206+
207+
uint64_t storage_size = rtype->storage_size;
208+
out->value.i64_value = 0;
209+
210+
if (rtype->storage_kind == STORAGE_KIND_IND) {
211+
memmove(&out->value.struct_, value_ref, storage_size);
212+
} else {
213+
memmove(&out->value, value_ref, storage_size);
214+
}
175215

176-
n_union_t mu = {0};
177216

178-
DEBUGF("[union_casting] union_base: %p, memmove value_ref(%p) -> any->value(%p), size=%lu, fetch_value_8byte=%p",
179-
&mu, value_ref,
180-
&mu.value, rtype->storage_size, (void *) fetch_addr_value((addr_t) value_ref));
181-
mu.rtype = rtype;
217+
DEBUGF("[union_casting] success, union_base: %p, union_rtype: %p, union_i64_value: %ld", out, out->rtype,
218+
out->value.i64_value);
219+
}
220+
221+
/**
222+
* any 参考旧版 union 处理 storage_ind 类型
223+
* @param input_rtype_hash
224+
* @param value_ref
225+
* @return
226+
*/
227+
void any_casting(n_any_t *out, int64_t input_rtype_hash, void *value_ref) {
228+
assert(out && "any_casting out is null");
229+
// - 根据 input_rtype_hash 找到对应的
230+
rtype_t *rtype = rt_find_rtype(input_rtype_hash);
231+
assert(rtype && "cannot find rtype by hash");
232+
233+
ASSERT_ADDR(value_ref);
234+
235+
TRACEF("[any_casting] input_kind=%s", type_kind_str[rtype->kind]);
236+
237+
DEBUGF("[any_casting] any_base: %p, memmove value_ref(%p) -> any->value(%p), size=%lu, fetch_value_8byte=%p",
238+
out, value_ref,
239+
&out->value, rtype->storage_size, (void *) fetch_addr_value((addr_t) value_ref));
240+
out->rtype = rtype;
182241

183242
uint64_t storage_size = rtype->storage_size;
243+
out->value.i64_value = 0;
184244

185-
// TODO union 产生了 GC? 这个问题稍后再解决。甚至现在总是会产生 GC。
186-
// 甚至 return union 类型变得寸步难行。
187245
if (rtype->storage_kind == STORAGE_KIND_IND) {
188-
// union 进行了数据的额外缓存,并进行值 copy,不需要担心 arr/struct 这样的大数据的丢失问题
189246
void *new_value = rti_gc_malloc(rtype->gc_heap_size, rtype);
190247
memmove(new_value, value_ref, storage_size);
191-
mu.value.ptr_value = new_value;
248+
out->value.ptr_value = new_value;
192249
} else {
193-
memmove(&mu.value, value_ref, storage_size);
250+
memmove(&out->value, value_ref, storage_size);
194251
}
195252

253+
DEBUGF("[any_casting] success, any_base: %p, any_rtype: %p, any_i64_value: %ld", out, out->rtype,
254+
out->value.i64_value);
255+
}
196256

197-
DEBUGF("[union_casting] success, union_base: %p, union_rtype: %p, union_i64_value: %ld", &mu, mu.rtype,
198-
mu.value.i64_value);
257+
/**
258+
* union -> any: 提取 union 的 rtype 和 value 传递给 any_casting
259+
*/
260+
void union_to_any(n_any_t *out, n_union_t *input) {
261+
assert(out && "union_to_any out is null");
262+
assert(input && "union_to_any input is null");
263+
assert(input->rtype && "union_to_any input rtype is null");
199264

200-
return mu;
265+
rtype_t *rtype = input->rtype;
266+
267+
DEBUGF("[union_to_any] input rtype kind=%s, hash=%ld", type_kind_str[rtype->kind], rtype->hash);
268+
269+
// union value 根据 storage_kind 确定 value_ref
270+
void *value_ref;
271+
if (rtype->storage_kind == STORAGE_KIND_IND) {
272+
value_ref = &input->value.struct_;
273+
} else {
274+
value_ref = &input->value;
275+
}
276+
277+
any_casting(out, rtype->hash, value_ref);
201278
}
202279

203-
n_tagged_union_t tagged_union_casting(int64_t tag_hash, int64_t value_rtype_hash, void *value_ref) {
280+
void tagged_union_casting(n_tagged_union_t *out, int64_t tag_hash, int64_t value_rtype_hash, void *value_ref) {
281+
assert(out && "tagged_union_casting out is null");
204282
DEBUGF("[tagged_union_casting] tag_hash=%ld, value_hash=%ld", tag_hash, value_rtype_hash);
205283

206-
n_tagged_union_t mu = {0};
207-
mu.tag_hash = tag_hash;
284+
out->tag_hash = tag_hash;
285+
out->value.i64_value = 0;
208286
if (value_rtype_hash == 0) {
209-
return mu;
287+
return;
210288
}
211289

212290
// - 根据 input_rtype_hash 找到对应的
@@ -217,24 +295,18 @@ n_tagged_union_t tagged_union_casting(int64_t tag_hash, int64_t value_rtype_hash
217295

218296
DEBUGF(
219297
"[tagged_union_casting] union_base: %p, memmove value_ref(%p) -> any->value(%p), kind=%s, size=%lu, fetch_value_8byte=%p",
220-
&mu, value_ref,
221-
&mu.value, type_kind_str[rtype->kind], rtype->storage_size, (void *) fetch_addr_value((addr_t) value_ref));
298+
out, value_ref,
299+
&out->value, type_kind_str[rtype->kind], rtype->storage_size, (void *) fetch_addr_value((addr_t) value_ref));
222300

223301
uint64_t storage_size = rtype->storage_size;
224302
if (rtype->storage_kind == STORAGE_KIND_IND) {
225-
// union 进行了数据的额外缓存,并进行值 copy,不需要担心 arr/struct 这样的大数据的丢失问题
226-
void *new_value = rti_gc_malloc(rtype->gc_heap_size, rtype);
227-
memmove(new_value, value_ref, storage_size);
228-
229-
mu.value.ptr_value = new_value;
303+
memmove(&out->value.struct_, value_ref, storage_size);
230304
} else {
231-
memmove(&mu.value, value_ref, storage_size);
305+
memmove(&out->value, value_ref, storage_size);
232306
}
233307

234-
DEBUGF("[tagged_union_casting] success, base: %p, id: %ld, union_i64_value: %ld", &mu, mu.tag_hash,
235-
mu.value.i64_value);
236-
237-
return mu;
308+
DEBUGF("[tagged_union_casting] success, base: %p, id: %ld, union_i64_value: %ld", out, out->tag_hash,
309+
out->value.i64_value);
238310
}
239311

240312

@@ -400,9 +472,9 @@ void co_throw_error(n_interface_t *error, char *path, char *fn_name, n_int_t lin
400472

401473
n_string_t err_msg = rti_error_msg(error);
402474
DEBUGF("[runtime.co_throw_error] co=%p, error=%p, path=%s, fn_name=%s, line=%ld, column=%ld, msg=%s", co,
403-
(void *) error, path, fn_name,
404-
line,
405-
column, (char *) rt_string_ref(&err_msg));
475+
(void *) error, path, fn_name,
476+
line,
477+
column, (char *) rt_string_ref(&err_msg));
406478

407479
assert(co->traces.data == NULL);
408480
n_vec_t traces = rti_vec_new(&errort_trace_rtype, 0, 0);

runtime/nutils/nutils.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,29 @@ extern char **command_argv;
1515

1616
void union_assert(n_union_t *mu, int64_t target_rtype_hash, void *value_ref);
1717

18+
void any_assert(n_any_t *mu, int64_t target_rtype_hash, void *value_ref);
19+
1820
void interface_assert(n_interface_t *mu, int64_t target_rtype_hash, void *value_ref);
1921

2022
bool union_is(n_union_t *mu, int64_t target_rtype_hash);
2123

24+
bool any_is(n_any_t *mu, int64_t target_rtype_hash);
25+
2226
bool interface_is(n_interface_t *mu, int64_t target_rtype_hash);
2327

2428
/**
2529
* input rtype index 是 value 具体的类型
30+
* @param out
2631
* @param input_rtype_hash
2732
* @param value_ref
28-
* @return
2933
*/
30-
n_union_t union_casting(int64_t input_rtype_hash, void *value_ref);
34+
void union_casting(n_union_t *out, int64_t input_rtype_hash, void *value_ref);
35+
36+
void any_casting(n_any_t *out, int64_t input_rtype_hash, void *value_ref);
37+
38+
void union_to_any(n_any_t *out, n_union_t *input);
3139

32-
n_tagged_union_t tagged_union_casting(int64_t id, int64_t value_rtype_hash, void *value_ref);
40+
void tagged_union_casting(n_tagged_union_t *out, int64_t id, int64_t value_rtype_hash, void *value_ref);
3341

3442
n_interface_t *interface_casting(uint64_t input_rtype_hash, void *value_ref, int64_t method_count, int64_t *methods);
3543

runtime/nutils/set.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ n_set_t rt_set_new(uint64_t rtype_hash, uint64_t key_hash) {
118118
return set_data;
119119
}
120120

121+
void rt_set_new_out(n_set_t *out, uint64_t rtype_hash, uint64_t key_hash) {
122+
n_set_t set_data = rt_set_new(rtype_hash, key_hash);
123+
*out = set_data;
124+
DEBUGF("[rt_set_new_out] success, out=%p, len=%lu, cap=%lu", out, out->length, out->capacity);
125+
}
126+
121127
/**
122128
* 如果值已经存在则返回 false
123129
* @param m

runtime/nutils/set.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
n_set_t rt_set_new(uint64_t rtype_hash, uint64_t key_hash);
1313

14+
void rt_set_new_out(n_set_t *out, uint64_t rtype_hash, uint64_t key_hash);
15+
1416
bool rt_set_add(n_set_t *m, void *key_ref);
1517

1618
bool rt_set_contains(n_set_t *m, void *key_ref);

runtime/nutils/vec.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ n_vec_t *rt_vec_alloc(int64_t hash, int64_t element_hash, int64_t capacity) {
164164
return vec_heap;
165165
}
166166

167+
void rt_vec_new_out(n_vec_t *out, int64_t hash, int64_t element_hash, int64_t capacity) {
168+
n_vec_t vec = rt_vec_cap(hash, element_hash, capacity);
169+
*out = vec;
170+
DEBUGF("[rt_vec_new_out] success, out=%p, data=%p, element_size=%lu, cap=%d", out, out->data,
171+
out->element_size, capacity);
172+
}
173+
167174
/**
168175
* @param l
169176
* @param index

runtime/nutils/vec.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ n_vec_t rt_vec_cap(int64_t hash, int64_t element_hash, int64_t capacity);
2727

2828
n_vec_t *rt_vec_alloc(int64_t hash, int64_t element_hash, int64_t capacity);
2929

30+
void rt_vec_new_out(n_vec_t *out, int64_t hash, int64_t element_hash, int64_t capacity);
31+
3032
n_anyptr_t rt_vec_element_addr(n_vec_t *l, uint64_t index);
3133

3234
/**

0 commit comments

Comments
 (0)