aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c20
-rw-r--r--repl.c2
-rw-r--r--stdlib/arrays.c4
-rw-r--r--stdlib/optionals.c10
-rw-r--r--structs.c8
-rw-r--r--typecheck.c12
-rw-r--r--types.c58
-rw-r--r--types.h2
8 files changed, 68 insertions, 48 deletions
diff --git a/compile.c b/compile.c
index a0262608..9ea968a9 100644
--- a/compile.c
+++ b/compile.c
@@ -46,7 +46,7 @@ CORD promote_to_optional(type_t *t, CORD code)
} else if (t->tag == ByteType) {
return CORD_all("((OptionalByte_t){", code, "})");
} else if (t->tag == StructType) {
- return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){", code, "})");
+ return CORD_all("({ ", compile_type(Type(OptionalType, .type=t)), " nonnull = {.value=", code, "}; nonnull.is_null = false; nonnull; })");
} else {
return code;
}
@@ -302,11 +302,11 @@ static CORD compile_lvalue(env_t *env, ast_t *ast)
if (index->unchecked) {
return CORD_all("Array_lvalue_unchecked(", compile_type(item_type), ", ", target_code, ", ",
compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64)),
- ", ", CORD_asprintf("%ld", padded_type_size(item_type)), ")");
+ ", ", CORD_asprintf("%ld", type_size(item_type)), ")");
} else {
return CORD_all("Array_lvalue(", compile_type(item_type), ", ", target_code, ", ",
compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64)),
- ", ", CORD_asprintf("%ld", padded_type_size(item_type)),
+ ", ", CORD_asprintf("%ld", type_size(item_type)),
", ", heap_strf("%ld", ast->start - ast->file->text),
", ", heap_strf("%ld", ast->end - ast->file->text), ")");
}
@@ -720,7 +720,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
if (lhs_t->tag == TextType) {
return CORD_all(lhs, " = Texts(", lhs, ", ", rhs, ");");
} else if (lhs_t->tag == ArrayType) {
- CORD padded_item_size = CORD_asprintf("%ld", padded_type_size(Match(lhs_t, ArrayType)->item_type));
+ CORD padded_item_size = CORD_asprintf("%ld", type_size(Match(lhs_t, ArrayType)->item_type));
if (promote(env, &rhs, rhs_t, Match(lhs_t, ArrayType)->item_type)) {
// arr ++= item
if (update->lhs->tag == Var)
@@ -1814,7 +1814,7 @@ CORD compile_null(type_t *t)
case PointerType: return CORD_all("((", compile_type(t), ")NULL)");
case ClosureType: return "NULL_CLOSURE";
case NumType: return "nan(\"null\")";
- case StructType: return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){.is_null=true})");
+ case StructType: return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){.is_null=yes})");
case EnumType: {
env_t *enum_env = Match(t, EnumType)->env;
return CORD_all("((", compile_type(t), "){", namespace_prefix(enum_env, enum_env->namespace), "null})");
@@ -2157,7 +2157,7 @@ CORD compile(env_t *env, ast_t *ast)
return CORD_all("Text$concat(", lhs, ", ", rhs, ")");
}
case ArrayType: {
- CORD padded_item_size = CORD_asprintf("%ld", padded_type_size(Match(operand_t, ArrayType)->item_type));
+ CORD padded_item_size = CORD_asprintf("%ld", type_size(Match(operand_t, ArrayType)->item_type));
return CORD_all("Array$concat(", lhs, ", ", rhs, ", ", padded_item_size, ")");
}
default:
@@ -2296,9 +2296,9 @@ CORD compile(env_t *env, ast_t *ast)
case Array: {
type_t *array_type = get_type(env, ast);
type_t *item_type = Match(array_type, ArrayType)->item_type;
- if (padded_type_size(Match(array_type, ArrayType)->item_type) > ARRAY_MAX_STRIDE)
+ if (type_size(Match(array_type, ArrayType)->item_type) > ARRAY_MAX_STRIDE)
code_err(ast, "This array holds items that take up %ld bytes, but the maximum supported size is %ld bytes. Consider using an array of pointers instead.",
- padded_type_size(item_type), ARRAY_MAX_STRIDE);
+ type_size(item_type), ARRAY_MAX_STRIDE);
auto array = Match(ast, Array);
if (!array->items)
@@ -2581,7 +2581,7 @@ CORD compile(env_t *env, ast_t *ast)
switch (self_value_t->tag) {
case ArrayType: {
type_t *item_t = Match(self_value_t, ArrayType)->item_type;
- CORD padded_item_size = CORD_asprintf("%ld", padded_type_size(item_t));
+ CORD padded_item_size = CORD_asprintf("%ld", type_size(item_t));
if (streq(call->name, "insert")) {
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
@@ -2803,7 +2803,7 @@ CORD compile(env_t *env, ast_t *ast)
}
case ChannelType: {
type_t *item_t = Match(self_value_t, ChannelType)->item_type;
- CORD padded_item_size = CORD_asprintf("%ld", padded_type_size(item_t));
+ CORD padded_item_size = CORD_asprintf("%ld", type_size(item_t));
arg_t *front_default_end = new(arg_t, .name="front", .type=Type(BoolType), .default_val=FakeAST(Bool, false));
arg_t *front_default_start = new(arg_t, .name="front", .type=Type(BoolType), .default_val=FakeAST(Bool, true));
if (streq(call->name, "give")) {
diff --git a/repl.c b/repl.c
index bd741165..601231fe 100644
--- a/repl.c
+++ b/repl.c
@@ -510,7 +510,7 @@ void eval(env_t *env, ast_t *ast, void *dest)
char item_buf[item_size] = {};
for (ast_list_t *item = Match(ast, Array)->items; item; item = item->next) {
eval(env, item->ast, item_buf);
- Array$insert(&arr, item_buf, I(0), (int64_t)padded_type_size(Match(t, ArrayType)->item_type));
+ Array$insert(&arr, item_buf, I(0), (int64_t)type_size(Match(t, ArrayType)->item_type));
}
memcpy(dest, &arr, sizeof(Array_t));
break;
diff --git a/stdlib/arrays.c b/stdlib/arrays.c
index 274983b7..93676979 100644
--- a/stdlib/arrays.c
+++ b/stdlib/arrays.c
@@ -20,7 +20,7 @@ PUREFUNC static inline int64_t get_padded_item_size(const TypeInfo_t *info)
{
int64_t size = info->ArrayInfo.item->size;
if (info->ArrayInfo.item->align > 1 && size % info->ArrayInfo.item->align)
- size += info->ArrayInfo.item->align - (size % info->ArrayInfo.item->align); // padding
+ errx(1, "Item size is not padded!");
return size;
}
@@ -524,7 +524,7 @@ public int32_t Array$compare(const Array_t *x, const Array_t *y, const TypeInfo_
if (item->tag == PointerInfo || (item->tag == CustomInfo && item->CustomInfo.compare == NULL)) { // data comparison
int64_t item_padded_size = type->ArrayInfo.item->size;
if (type->ArrayInfo.item->align > 1 && item_padded_size % type->ArrayInfo.item->align)
- item_padded_size += type->ArrayInfo.item->align - (item_padded_size % type->ArrayInfo.item->align); // padding
+ errx(1, "Item size is not padded!");
if ((int64_t)x->stride == item_padded_size && (int64_t)y->stride == item_padded_size && item->size == item_padded_size) {
int32_t cmp = (int32_t)memcmp(x->data, y->data, (size_t)(MIN(x->length, y->length)*item_padded_size));
diff --git a/stdlib/optionals.c b/stdlib/optionals.c
index 37d1b1df..a3b3defc 100644
--- a/stdlib/optionals.c
+++ b/stdlib/optionals.c
@@ -43,9 +43,13 @@ public PUREFUNC bool is_null(const void *obj, const TypeInfo_t *non_optional_typ
case TableInfo: return ((Table_t*)obj)->entries.length < 0;
case FunctionInfo: return *(void**)obj == NULL;
case StructInfo: {
- int64_t offset = non_optional_type->size;
- if (offset % non_optional_type->align)
- offset += non_optional_type->align - (offset % non_optional_type->align);
+ int64_t offset = 0;
+ for (int i = 0; i < non_optional_type->StructInfo.num_fields; i++) {
+ NamedType_t field = non_optional_type->StructInfo.fields[i];
+ if (offset > 0 && (offset % field.type->align) > 0)
+ offset += field.type->align - (offset % field.type->align);
+ offset += field.type->size;
+ }
return *(bool*)(obj + offset);
}
case EnumInfo: return (*(int*)obj) == 0; // NULL tag
diff --git a/structs.c b/structs.c
index 14cebb73..02156cd5 100644
--- a/structs.c
+++ b/structs.c
@@ -55,14 +55,20 @@ CORD compile_struct_header(env_t *env, ast_t *ast)
}
CORD struct_code = CORD_all("struct ", full_name, "_s {\n");
struct_code = CORD_all(struct_code, "};\n");
+ type_t *t = Table$str_get(*env->types, def->name);
return CORD_all(
"typedef struct ", full_name, "_s ", full_name, "_t;\n",
"struct ", full_name, "_s {\n",
fields,
"};\n",
"typedef struct {\n",
+ "union {\n",
full_name, "_t value;\n"
- "Bool_t is_null:1;\n"
+ "struct {\n"
+ "char _padding[", heap_strf("%zu", unpadded_struct_size(t)), "];\n",
+ "Bool_t is_null;\n"
+ "};\n"
+ "};\n"
"} ", namespace_prefix(env, env->namespace), "$Optional", def->name, "_t;\n"
"extern const TypeInfo_t ", full_name, ";\n",
compile_namespace_header(env, def->name, def->namespace));
diff --git a/typecheck.c b/typecheck.c
index c50e01be..d056d6e4 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -54,9 +54,9 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
if (!item_t) code_err(item_type, "I can't figure out what this type is.");
if (has_stack_memory(item_t))
code_err(item_type, "Arrays can't have stack references because the array may outlive the stack frame.");
- if (padded_type_size(item_t) > ARRAY_MAX_STRIDE)
+ if (type_size(item_t) > ARRAY_MAX_STRIDE)
code_err(ast, "This array holds items that take up %ld bytes, but the maximum supported size is %ld bytes. Consider using an array of pointers instead.",
- padded_type_size(item_t), ARRAY_MAX_STRIDE);
+ type_size(item_t), ARRAY_MAX_STRIDE);
return Type(ArrayType, .item_type=item_t);
}
case SetTypeAST: {
@@ -65,9 +65,9 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
if (!item_t) code_err(item_type, "I can't figure out what this type is.");
if (has_stack_memory(item_t))
code_err(item_type, "Sets can't have stack references because the array may outlive the stack frame.");
- if (padded_type_size(item_t) > ARRAY_MAX_STRIDE)
+ if (type_size(item_t) > ARRAY_MAX_STRIDE)
code_err(ast, "This set holds items that take up %ld bytes, but the maximum supported size is %ld bytes. Consider using an set of pointers instead.",
- padded_type_size(item_t), ARRAY_MAX_STRIDE);
+ type_size(item_t), ARRAY_MAX_STRIDE);
return Type(SetType, .item_type=item_t);
}
case ChannelTypeAST: {
@@ -76,9 +76,9 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
if (!item_t) code_err(item_type, "I can't figure out what this type is.");
if (!can_send_over_channel(item_t))
code_err(ast, "This item type can't be sent over a channel because it contains reference to memory that may not be thread-safe.");
- if (padded_type_size(item_t) > ARRAY_MAX_STRIDE)
+ if (type_size(item_t) > ARRAY_MAX_STRIDE)
code_err(ast, "This channel holds items that take up %ld bytes, but the maximum supported size is %ld bytes.",
- padded_type_size(item_t), ARRAY_MAX_STRIDE);
+ type_size(item_t), ARRAY_MAX_STRIDE);
return Type(ChannelType, .item_type=item_t);
}
case TableTypeAST: {
diff --git a/types.c b/types.c
index a0e347ca..9407f957 100644
--- a/types.c
+++ b/types.c
@@ -398,6 +398,24 @@ PUREFUNC bool is_numeric_type(type_t *t)
return t->tag == IntType || t->tag == BigIntType || t->tag == NumType;
}
+PUREFUNC size_t unpadded_struct_size(type_t *t)
+{
+ arg_t *fields = Match(t, StructType)->fields;
+ size_t size = 0;
+ for (arg_t *field = fields; field; field = field->next) {
+ type_t *field_type = field->type;
+ if (field_type->tag == BoolType) {
+ size += 1; // Bit packing
+ } else {
+ size_t align = type_align(field_type);
+ if (align > 1 && size % align > 0)
+ size += align - (size % align); // Padding
+ size += type_size(field_type);
+ }
+ }
+ return size;
+}
+
PUREFUNC size_t type_size(type_t *t)
{
#pragma GCC diagnostic ignored "-Wswitch-default"
@@ -438,24 +456,22 @@ PUREFUNC size_t type_size(type_t *t)
case TYPE_IBITS8: return sizeof(OptionalInt8_t);
default: errx(1, "Invalid integer bit size");
}
- case StructType: return padded_type_size(nonnull) + 1;
+ case StructType: {
+ size_t size = unpadded_struct_size(nonnull);
+ size += sizeof(bool); // is_null flag
+ size_t align = type_align(nonnull);
+ if (align > 0 && (size % align) > 0)
+ size = (size + align) - (size % align);
+ return size;
+ }
default: return type_size(nonnull);
}
}
case StructType: {
- arg_t *fields = Match(t, StructType)->fields;
- size_t size = t->tag == StructType ? 0 : sizeof(void*);
- for (arg_t *field = fields; field; field = field->next) {
- type_t *field_type = field->type;
- if (field_type->tag == BoolType) {
- size += 1; // Bit packing
- } else {
- size_t align = type_align(field_type);
- if (align > 1 && size % align > 0)
- size += align - (size % align); // Padding
- size += type_size(field_type);
- }
- }
+ size_t size = unpadded_struct_size(t);
+ size_t align = type_align(t);
+ if (size > 0 && align > 0 && (size % align) > 0)
+ size = (size + align) - (size % align);
return size;
}
case EnumType: {
@@ -468,9 +484,12 @@ PUREFUNC size_t type_size(type_t *t)
if (size > max_size) max_size = size;
}
size_t size = sizeof(UnknownType); // generic enum
- if (max_align > 1 && size % max_align > 0)
+ if (max_align > 1 && size % max_align > 0) // Padding before first union field
size += max_align - (size % max_align);
size += max_size;
+ size_t align = MAX(__alignof__(UnknownType), max_align);
+ if (size % align > 0) // Padding after union
+ size += align - (size % align);
return size;
}
case TypeInfoType: return sizeof(TypeInfo_t);
@@ -545,15 +564,6 @@ PUREFUNC size_t type_align(type_t *t)
errx(1, "This should not be reachable");
}
-PUREFUNC size_t padded_type_size(type_t *t)
-{
- size_t size = type_size(t);
- size_t align = type_align(t);
- if (align > 1 && size % align > 0)
- size += align - (size % align); // Padding
- return size;
-}
-
type_t *get_field_type(type_t *t, const char *field_name)
{
t = value_type(t);
diff --git a/types.h b/types.h
index 598c6ec2..029692ad 100644
--- a/types.h
+++ b/types.h
@@ -151,7 +151,7 @@ PUREFUNC bool is_int_type(type_t *t);
PUREFUNC bool is_numeric_type(type_t *t);
PUREFUNC size_t type_size(type_t *t);
PUREFUNC size_t type_align(type_t *t);
-PUREFUNC size_t padded_type_size(type_t *t);
+PUREFUNC size_t unpadded_struct_size(type_t *t);
type_t *get_field_type(type_t *t, const char *field_name);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0