diff options
| -rw-r--r-- | compile.c | 20 | ||||
| -rw-r--r-- | repl.c | 2 | ||||
| -rw-r--r-- | stdlib/arrays.c | 4 | ||||
| -rw-r--r-- | stdlib/optionals.c | 10 | ||||
| -rw-r--r-- | structs.c | 8 | ||||
| -rw-r--r-- | typecheck.c | 12 | ||||
| -rw-r--r-- | types.c | 58 | ||||
| -rw-r--r-- | types.h | 2 |
8 files changed, 68 insertions, 48 deletions
@@ -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")) { @@ -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 @@ -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: { @@ -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); @@ -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 |
