Browse Source

don't allocate for arrays <2 elements long

master
Martin Dørum 3 years ago
parent
commit
01f1b7d2f9
3 changed files with 75 additions and 31 deletions
  1. 8
    3
      include/lang2/vm/vm.h
  2. 8
    1
      lib/vm/builtins.c
  3. 59
    27
      lib/vm/vm.c

+ 8
- 3
include/lang2/vm/vm.h View File

const char *l2_value_type_name(enum l2_value_type typ); const char *l2_value_type_name(enum l2_value_type typ);


enum l2_value_flags { enum l2_value_flags {
L2_VAL_MARKED = 1 << 6,
L2_VAL_CONST = 1 << 7,
L2_VAL_CONT_CALLBACK = 1 << 7, // Re-use the const bit
L2_VAL_MARKED = 1 << 7,
L2_VAL_CONST = 1 << 6,
L2_VAL_CONT_CALLBACK = 1 << 6, // Re-use the const bit
L2_VAL_SBO = 1 << 5,
}; };


struct l2_vm_contcontext { struct l2_vm_contcontext {
double real; double real;
char *buffer; char *buffer;
struct l2_vm_array *array; struct l2_vm_array *array;
l2_word shortarray[2];
struct l2_vm_namespace *ns; struct l2_vm_namespace *ns;
struct { struct {
l2_word pos; l2_word pos;


#define l2_value_get_type(val) ((enum l2_value_type)((val)->flags & 0x0f)) #define l2_value_get_type(val) ((enum l2_value_type)((val)->flags & 0x0f))


l2_word l2_value_arr_get(struct l2_vm *vm, struct l2_vm_value *val, l2_word k);
l2_word l2_value_arr_set(struct l2_vm *vm, struct l2_vm_value *val, l2_word k, l2_word v);

struct l2_vm_array { struct l2_vm_array {
size_t size; size_t size;
l2_word data[]; l2_word data[];

+ 8
- 1
lib/vm/builtins.c View File



case L2_VAL_TYPE_ARRAY: case L2_VAL_TYPE_ARRAY:
out->write(out, "[", 1); out->write(out, "[", 1);
l2_word *data;
if (val->flags & L2_VAL_SBO) {
data = val->shortarray;
} else {
data = val->array->data;
}

for (size_t i = 0; i < val->extra.arr_length; ++i) { for (size_t i = 0; i < val->extra.arr_length; ++i) {
if (i != 0) { if (i != 0) {
out->write(out, " ", 1); out->write(out, " ", 1);
} }


print_val(vm, out, &vm->values[val->array->data[i]]);
print_val(vm, out, &vm->values[data[i]]);
} }
out->write(out, "]", 1); out->write(out, "]", 1);
break; break;

+ 59
- 27
lib/vm/vm.c View File

} }


static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val) { static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val) {
if (val->array == NULL) {
return;
l2_word *data;
if (val->flags & L2_VAL_SBO) {
data = val->shortarray;
} else {
data = val->array->data;
} }


for (size_t i = 0; i < val->extra.arr_length; ++i) { for (size_t i = 0; i < val->extra.arr_length; ++i) {
gc_mark(vm, val->array->data[i]);
gc_mark(vm, data[i]);
} }
} }


// Don't need to do anything more; the next round of GC will free // Don't need to do anything more; the next round of GC will free
// whichever values were only referenced by the array // whichever values were only referenced by the array
int typ = l2_value_get_type(val); int typ = l2_value_get_type(val);
if (typ == L2_VAL_TYPE_ARRAY) {
if (typ == L2_VAL_TYPE_ARRAY && !(val->flags & L2_VAL_SBO)) {
free(val->array); free(val->array);
} else if (typ == L2_VAL_TYPE_BUFFER) { } else if (typ == L2_VAL_TYPE_BUFFER) {
free(val->buffer); free(val->buffer);
return "(unknown)"; return "(unknown)";
} }


l2_word l2_value_arr_get(struct l2_vm *vm, struct l2_vm_value *val, l2_word k) {
if (k >= val->extra.arr_length) {
return l2_vm_error(vm, "Array index out of bounds");
}

if (val->flags & L2_VAL_SBO) {
return val->shortarray[k];
}

return val->array->data[k];
}

l2_word l2_value_arr_set(struct l2_vm *vm, struct l2_vm_value *val, l2_word k, l2_word v) {
if (k >= val->extra.arr_length) {
return l2_vm_error(vm, "Array index out of bounds");
}

if (val->flags & L2_VAL_SBO) {
return val->shortarray[k] = v;
}

return val->array->data[k] = v;
}

void l2_vm_init(struct l2_vm *vm, unsigned char *ops, size_t opslen) { void l2_vm_init(struct l2_vm *vm, unsigned char *ops, size_t opslen) {
if (!stdio_inited) { if (!stdio_inited) {
std_output.w.write = l2_io_file_write; std_output.w.write = l2_io_file_write;
} }


l2_word l2_vm_type_error(struct l2_vm *vm, struct l2_vm_value *val) { l2_word l2_vm_type_error(struct l2_vm *vm, struct l2_vm_value *val) {
enum l2_value_type typ = l2_value_get_type(val);
if (typ == L2_VAL_TYPE_ERROR) {
return val - vm->values;
}

return l2_vm_error(vm, "Unexpected type %s", l2_value_type_name(l2_value_get_type(val))); return l2_vm_error(vm, "Unexpected type %s", l2_value_type_name(l2_value_get_type(val)));
} }


} }


l2_word arr_id = alloc_val(vm); l2_word arr_id = alloc_val(vm);
vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY;
vm->values[arr_id].array = malloc(
sizeof(struct l2_vm_array) + sizeof(l2_word) * argc);
vm->values[arr_id].extra.arr_length = argc;
struct l2_vm_array *arr = vm->values[arr_id].array;
arr->size = argc;

for (l2_word i = 0; i < argc; ++i) {
arr->data[i] = argv[i];
struct l2_vm_value *arr = &vm->values[arr_id];
arr->extra.arr_length = argc;
if (argc <= 2) {
arr->flags = L2_VAL_TYPE_ARRAY | L2_VAL_SBO;
memcpy(arr->shortarray, argv, argc * sizeof(l2_word));
} else {
arr->flags = L2_VAL_TYPE_ARRAY;
arr->array = malloc(
sizeof(struct l2_vm_array) + sizeof(l2_word) * argc);
arr->array->size = argc;
memcpy(arr->array->data, argv, argc * sizeof(l2_word));
} }


vm->stack[vm->sptr++] = arr_id; vm->stack[vm->sptr++] = arr_id;
l2_word count = read(vm); \ l2_word count = read(vm); \
l2_word arr_id = alloc_val(vm); \ l2_word arr_id = alloc_val(vm); \
struct l2_vm_value *arr = &vm->values[arr_id]; \ struct l2_vm_value *arr = &vm->values[arr_id]; \
arr->flags = L2_VAL_TYPE_ARRAY; \
arr->extra.arr_length = count; \ arr->extra.arr_length = count; \
if (count == 0) { \
arr->array = NULL; \
vm->stack[vm->sptr++] = arr_id; \
break; \
l2_word *data; \
if (count <= 2) { \
arr->flags = L2_VAL_TYPE_ARRAY | L2_VAL_SBO; \
data = arr->shortarray; \
} else { \
arr->flags = L2_VAL_TYPE_ARRAY; \
arr->array = malloc(sizeof(struct l2_vm_array) + count * sizeof(l2_word)); \
arr->array->size = count; \
data = arr->array->data; \
} \ } \
arr->array = malloc(sizeof(struct l2_vm_array) + count * sizeof(l2_word)); \
arr->array->size = count; \
for (l2_word i = 0; i < count; ++i) { \ for (l2_word i = 0; i < count; ++i) { \
arr->array->data[count - 1 - i] = vm->stack[--vm->sptr]; \
data[count - 1 - i] = vm->stack[--vm->sptr]; \
} \ } \
vm->stack[vm->sptr++] = arr_id; vm->stack[vm->sptr++] = arr_id;
case L2_OP_ALLOC_ARRAY_U4: { X(read_u4le); } break; case L2_OP_ALLOC_ARRAY_U4: { X(read_u4le); } break;
struct l2_vm_value *arr = &vm->values[arr_id]; \ struct l2_vm_value *arr = &vm->values[arr_id]; \
if (l2_value_get_type(arr) != L2_VAL_TYPE_ARRAY) { \ if (l2_value_get_type(arr) != L2_VAL_TYPE_ARRAY) { \
vm->stack[vm->sptr++] = l2_vm_type_error(vm, arr); \ vm->stack[vm->sptr++] = l2_vm_type_error(vm, arr); \
} else if (key >= arr->extra.arr_length) { \
vm->stack[vm->sptr++] = l2_vm_error(vm, "Index out of range"); \
} else { \ } else { \
vm->stack[vm->sptr++] = arr->array->data[key]; \
vm->stack[vm->sptr++] = l2_value_arr_get(vm, arr, key); \
} }
case L2_OP_ARRAY_LOOKUP_U4: { X(read_u4le); } break; case L2_OP_ARRAY_LOOKUP_U4: { X(read_u4le); } break;
case L2_OP_ARRAY_LOOKUP_U1: { X(read_u1le); } break; case L2_OP_ARRAY_LOOKUP_U1: { X(read_u1le); } break;
struct l2_vm_value *arr = &vm->values[arr_id]; \ struct l2_vm_value *arr = &vm->values[arr_id]; \
if (l2_value_get_type(arr) != L2_VAL_TYPE_ARRAY) { \ if (l2_value_get_type(arr) != L2_VAL_TYPE_ARRAY) { \
vm->stack[vm->sptr - 1] = l2_vm_type_error(vm, arr); \ vm->stack[vm->sptr - 1] = l2_vm_type_error(vm, arr); \
} else if (key >= arr->extra.arr_length) { \
vm->stack[vm->sptr - 1] = l2_vm_error(vm, "Index out of range"); \
} else { \ } else { \
arr->array->data[key] = val; \
vm->stack[vm->sptr - 1] = l2_value_arr_set(vm, arr, key, val); \
} }
case L2_OP_ARRAY_SET_U4: { X(read_u4le); } break; case L2_OP_ARRAY_SET_U4: { X(read_u4le); } break;
case L2_OP_ARRAY_SET_U1: { X(read_u1le); } break; case L2_OP_ARRAY_SET_U1: { X(read_u1le); } break;

Loading…
Cancel
Save