Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

changes the implementation of value_t arrays #25

Merged
merged 1 commit into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions microcontroller/core/include/c-runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@ typedef struct class_object {
// If start_index is 2, body[0] and body[1] don't hold a pointer.
const char* const name; // printable class name
const struct class_object* const superclass; // super class or NULL
uint32_t flags; // 1: array type. An array type supports [] and .length.
struct property_table table;
void* vtbl[1];
} class_object;

// A macro for declaring a class_object.
// n: the length of body (> 0).
#define CLASS_OBJECT(name, n) ALGIN const union { struct class_object clazz; struct { uint32_t s; uint32_t i; const char* const cn; const struct class_object* const sc; struct property_table pt; void* vtbl[n]; } body; } name
#define CLASS_OBJECT(name, n) ALGIN const union { struct class_object clazz; struct { uint32_t s; uint32_t i; const char* const cn; const struct class_object* const sc; uint32_t f; struct property_table pt; void* vtbl[n]; } body; } name

inline int32_t value_to_int(value_t v) { return (int32_t)v / 4; }
inline value_t int_to_value(int32_t v) { return (uint32_t)v << 2; }
Expand Down Expand Up @@ -248,10 +249,10 @@ extern value_t CR_SECTION gc_vector_get(value_t obj, int32_t index);
extern value_t CR_SECTION gc_vector_set(value_t obj, int32_t index, value_t new_value);
extern value_t CR_SECTION gc_make_vector(int32_t n, ...);

extern value_t CR_SECTION safe_value_to_array(value_t v);
extern bool CR_SECTION gc_is_instance_of_array(value_t obj);
extern value_t CR_SECTION safe_value_to_anyarray(value_t v);
extern value_t CR_SECTION gc_new_array(int32_t is_any, int32_t n, value_t init_value);
extern value_t CR_SECTION gc_make_array(int32_t is_any, int32_t n, ...);
extern value_t CR_SECTION gc_new_array(const class_object* clazz, int32_t n, value_t init_value);
extern value_t CR_SECTION gc_make_array(const class_object* clazz, int32_t n, ...);
extern int32_t CR_SECTION gc_array_length(value_t obj);
extern value_t* CR_SECTION gc_array_get(value_t obj, int32_t index);
extern value_t CR_SECTION gc_array_set(value_t obj, int32_t index, value_t new_value);
Expand Down
60 changes: 29 additions & 31 deletions microcontroller/core/src/c-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,10 +479,11 @@ void* method_lookup(value_t obj, uint32_t index) {
return get_objects_class(value_to_ptr(obj))->vtbl[index];
}

#define IS_ARRAY_TYPE(clazz) (clazz != NULL && (clazz)->flags & 1)
#define DEFAULT_PTABLE { .size = 0, .offset = 0, .unboxed = 0, .prop_names = NULL, .unboxed_types = NULL }

CLASS_OBJECT(object_class, 1) = {
.clazz = { .size = 0, .start_index = 0, .name = "Object", .superclass = NULL, .table = DEFAULT_PTABLE }};
.clazz = { .size = 0, .start_index = 0, .name = "Object", .superclass = NULL, .flags = 0, .table = DEFAULT_PTABLE }};

static pointer_t allocate_heap(uint16_t word_size);

Expand Down Expand Up @@ -630,7 +631,7 @@ value_t acc_anyobj_property(value_t obj, char op, int property, value_t value) {

static CLASS_OBJECT(function_object, 0) = {
.clazz = { .size = 3, .start_index = 2, .name = "Function",
.superclass = &object_class.clazz, .table = DEFAULT_PTABLE }};
.superclass = &object_class.clazz, .flags = 0, .table = DEFAULT_PTABLE }};

// this_object may be VALUE_UNDEF.
value_t gc_new_function(void* fptr, const char* signature, value_t captured_values) {
Expand Down Expand Up @@ -668,10 +669,10 @@ value_t gc_function_captured_value(value_t obj, int index) {
// or one primitive value. They are used for implementing a free variable.

static CLASS_OBJECT(boxed_value, 0) = { .clazz.size = 1, .clazz.start_index = 0,
.clazz.name = "boxed_value", .clazz.superclass = NULL, .clazz.table = DEFAULT_PTABLE };
.clazz.name = "boxed_value", .clazz.superclass = NULL, .clazz.flags = 0, .clazz.table = DEFAULT_PTABLE };

static CLASS_OBJECT(boxed_raw_value, 0) = { .clazz.size = 1, .clazz.start_index = SIZE_NO_POINTER,
.clazz.name = "boxed_raw_value", .clazz.superclass = NULL, .clazz.table = DEFAULT_PTABLE };
.clazz.name = "boxed_raw_value", .clazz.superclass = NULL, .clazz.flags = 0, .clazz.table = DEFAULT_PTABLE };

value_t gc_new_box(value_t value) {
ROOT_SET(rootset, 1)
Expand All @@ -698,7 +699,7 @@ value_t gc_new_float_box(float value) {
// This C string is not allocated in the heap memory managed by the garbage collector.

static CLASS_OBJECT(string_literal, 0) = { .clazz.size = 1, .clazz.start_index = SIZE_NO_POINTER,
.clazz.name = "string", .clazz.superclass = NULL, .clazz.table = DEFAULT_PTABLE };
.clazz.name = "string", .clazz.superclass = NULL, .clazz.flags = 0, .clazz.table = DEFAULT_PTABLE };

// str: a char array in the C language.
value_t gc_new_string(char* str) {
Expand Down Expand Up @@ -730,7 +731,7 @@ bool gc_is_string_object(value_t obj) {

static CLASS_OBJECT(intarray_object, 1) = {
.clazz = { .size = -1, .start_index = SIZE_NO_POINTER, .name = "Array<integer>",
.superclass = &object_class.clazz, .table = DEFAULT_PTABLE }};
.superclass = &object_class.clazz, .flags = 1, .table = DEFAULT_PTABLE }};

value_t safe_value_to_intarray(value_t v) {
return safe_value_to_value(&intarray_object.clazz, v);
Expand Down Expand Up @@ -798,7 +799,7 @@ bool gc_is_intarray(value_t v) {

static CLASS_OBJECT(floatarray_object, 1) = {
.clazz = { .size = -1, .start_index = SIZE_NO_POINTER, .name = "Array<float>",
.superclass = &object_class.clazz, .table = DEFAULT_PTABLE }};
.superclass = &object_class.clazz, .flags = 1, .table = DEFAULT_PTABLE }};

value_t safe_value_to_floatarray(value_t v) {
return safe_value_to_value(&floatarray_object.clazz, v);
Expand Down Expand Up @@ -865,11 +866,11 @@ bool gc_is_floatarray(value_t v) {

CLASS_OBJECT(class_Uint8Array, 1) = {
.clazz = { .size = -1, .start_index = SIZE_NO_POINTER, .name = "Uint8Array",
.superclass = &object_class.clazz, .table = DEFAULT_PTABLE }};
.superclass = &object_class.clazz, .flags = 1, .table = DEFAULT_PTABLE }};

static CLASS_OBJECT(boolarray_object, 1) = {
.clazz = { .size = -1, .start_index = SIZE_NO_POINTER, .name = "Array<boolean>",
.superclass = &object_class.clazz, .table = DEFAULT_PTABLE }};
.superclass = &object_class.clazz, .flags = 1, .table = DEFAULT_PTABLE }};

value_t safe_value_to_boolarray(value_t v) {
return safe_value_to_value(&boolarray_object.clazz, v);
Expand Down Expand Up @@ -953,7 +954,7 @@ bool gc_is_boolarray(value_t v) {

static CLASS_OBJECT(vector_object, 1) = {
.clazz = { .size = -1, .start_index = 1, .name = "Vector",
.superclass = &object_class.clazz, .table = DEFAULT_PTABLE }};
.superclass = &object_class.clazz, .flags = 1, .table = DEFAULT_PTABLE }};

value_t safe_value_to_vector(value_t v) {
return safe_value_to_value(&vector_object.clazz, v);
Expand Down Expand Up @@ -1036,29 +1037,26 @@ value_t gc_make_vector(int32_t n, ...) {
return array;
}

// An any-type array
// any-type and other arrays

/* this may be Array<string> etc. */
static CLASS_OBJECT(array_object, 1) = {
.clazz = { .size = 2, .start_index = 1, .name = "Array",
.superclass = &object_class.clazz, .table = DEFAULT_PTABLE }};
// Returns true when obj is an array of any kind of type.
bool gc_is_instance_of_array(value_t obj) {
class_object* clazz = gc_get_class_of(obj);
return IS_ARRAY_TYPE(clazz);
}

static CLASS_OBJECT(anyarray_object, 1) = {
.clazz = { .size = 2, .start_index = 1, .name = "Array<any>",
.superclass = &object_class.clazz, .table = DEFAULT_PTABLE }};

value_t safe_value_to_array(value_t v) {
return safe_value_to_value(&array_object.clazz, v);
}
.superclass = &object_class.clazz, .flags = 1, .table = DEFAULT_PTABLE }};

value_t safe_value_to_anyarray(value_t v) {
return safe_value_to_value(&anyarray_object.clazz, v);
}

value_t gc_new_array(int32_t is_any, int32_t n, value_t init_value) {
value_t gc_new_array(const class_object* clazz, int32_t n, value_t init_value) {
ROOT_SET(rootset, 2)
rootset.values[0] = init_value;
pointer_t obj = gc_allocate_object(is_any ? &anyarray_object.clazz : &array_object.clazz);
pointer_t obj = gc_allocate_object(clazz == NULL ? &anyarray_object.clazz : clazz);
rootset.values[1] = ptr_to_value(obj);
value_t vec = gc_new_vector(n, init_value);
obj->body[1] = vec;
Expand All @@ -1072,9 +1070,9 @@ value_t gc_new_array(int32_t is_any, int32_t n, value_t init_value) {
A caller function must guarantee that they are reachable
from the root.
*/
value_t gc_make_array(int32_t is_any, int32_t n, ...) {
value_t gc_make_array(const class_object* clazz, int32_t n, ...) {
va_list args;
value_t array = gc_new_array(is_any, n, VALUE_UNDEF);
value_t array = gc_new_array(clazz, n, VALUE_UNDEF);
pointer_t arrayp = value_to_ptr(array);
va_start(args, n);

Expand Down Expand Up @@ -1116,11 +1114,11 @@ value_t gc_array_set(value_t obj, int32_t index, value_t new_value) {

int32_t get_all_array_length(value_t obj) {
class_object* clazz = gc_get_class_of(obj);
if (clazz == &intarray_object.clazz || clazz == &floatarray_object.clazz
|| clazz == &vector_object.clazz || clazz == &array_object.clazz || clazz == &anyarray_object.clazz)
return value_to_ptr(obj)->body[0];
else if (clazz == &class_Uint8Array.clazz || clazz == &boolarray_object.clazz)
return value_to_ptr(obj)->body[1];
if (IS_ARRAY_TYPE(clazz))
if (clazz == &class_Uint8Array.clazz || clazz == &boolarray_object.clazz)
return value_to_ptr(obj)->body[1];
else
return value_to_ptr(obj)->body[0];
else
return -1;
}
Expand All @@ -1146,7 +1144,7 @@ value_t gc_safe_array_get(value_t obj, int32_t idx) {
return bool_to_value(*gc_bytearray_get(obj, idx));
else if (clazz == &vector_object.clazz)
return gc_vector_get(obj, idx);
else if (clazz == &array_object.clazz || clazz == &anyarray_object.clazz)
else if (IS_ARRAY_TYPE(clazz)) // for arrays of value_t
return *gc_array_get(obj, idx);
else {
runtime_type_error("reading a non array");
Expand All @@ -1168,7 +1166,7 @@ value_t gc_safe_array_set(value_t obj, int32_t idx, value_t new_value) {
}
else if (clazz == &vector_object.clazz)
return gc_vector_set(obj, idx, new_value);
else if (clazz == &array_object.clazz || clazz == &anyarray_object.clazz)
else if (IS_ARRAY_TYPE(clazz)) // for arrays of value_t
return gc_array_set(obj, idx, new_value);
else {
runtime_type_error("assignment to a non array");
Expand Down
2 changes: 1 addition & 1 deletion microcontroller/core/test/c-runtime-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ bool is_live_object(value_t obj) {
}

static value_t gc_new_array2(int32_t n) {
return gc_new_array(1, n, VALUE_UNDEF);
return gc_new_array(NULL, n, VALUE_UNDEF);
}

static value_t gc_new_vector2(int32_t n) {
Expand Down
4 changes: 2 additions & 2 deletions microcontroller/core/test/c-runtime-test2.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ void test_array2() {
}

void test_array() {
value_t arr = gc_make_array(1, 3, int_to_value(1), int_to_value(2), int_to_value(3));
value_t arr = gc_make_array(NULL, 3, int_to_value(1), int_to_value(2), int_to_value(3));
Assert_equals(gc_array_length(arr), 3);
*gc_array_get(arr, 2) = int_to_value(4);
Assert_equals(*gc_array_get(arr, 2), int_to_value(4));
Expand All @@ -180,7 +180,7 @@ void test_string_literal() {
value_t str = gc_new_string("foo");
root_set.values[0] = str;
value_t i = int_to_value(3);
value_t a = gc_make_array(1, 2, VALUE_FALSE, VALUE_NULL);
value_t a = gc_make_array(NULL, 2, VALUE_FALSE, VALUE_NULL);
root_set.values[1] = a;
Assert_true(gc_is_string_literal(str));
Assert_true(!gc_is_string_literal(i));
Expand Down
2 changes: 1 addition & 1 deletion microcontroller/core/test/profiler-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ static void test_converter() {
const char* result_str_s = typeint_to_str(typeint_s);
Assert_str_equals(result_str_s, "string");

value_t arr = gc_new_array(true, 2, int_to_value(4));
value_t arr = gc_new_array(NULL, 2, int_to_value(4));
typeint_t typeint_arr = value_to_typeint(arr);
const char* result_str_arr = typeint_to_str(typeint_arr);
Assert_str_equals(result_str_arr, "Array<any>");
Expand Down
2 changes: 1 addition & 1 deletion server/src/jit/jit-code-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ export class JitCodeGenerator extends CodeGenerator{
const info = fenv.table.lookup(paramName)
if (info !== undefined) {
const name = info.transpiledName(paramName)
paramSig.push(`${cr.typeConversion(argTypes[i], funcType.paramTypes[i], node)}${name})`);
paramSig.push(`${cr.typeConversion(argTypes[i], funcType.paramTypes[i], fenv, node)}${name})`);
}
}
this.result.write(paramSig.join(', ')).write(');');
Expand Down
33 changes: 21 additions & 12 deletions server/src/transpiler/code-generator/c-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Integer, Float, BooleanT, StringT, Void, Null, Any,
StaticType, isPrimitiveType, typeToString, ArrayType, sameType, encodeType, isSubtype,
ByteArrayClass, } from '../types'
import { InstanceType, ClassTable } from '../classes'
import { VariableEnv } from './variables'

export const anyTypeInC = 'value_t'
export const funcTypeInC = 'value_t'
Expand Down Expand Up @@ -73,7 +74,7 @@ function typeConversionError(from: StaticType | undefined, to: StaticType | unde
// returns '(' or '<conversion function>('
// "from" or "to" is undefined when type conversion is unnecessary
export function typeConversion(from: StaticType | undefined, to: StaticType | undefined,
node: AST.Node) {
env: VariableEnv, node: AST.Node) {
if (from === undefined || to === undefined)
return '('

Expand Down Expand Up @@ -153,9 +154,7 @@ export function typeConversion(from: StaticType | undefined, to: StaticType | un
else if (to.elementType === Any)
return 'safe_value_to_anyarray('
else
break
// cannot determine wether a given array
// is an array of String or Any
return `safe_value_to_value(&${env.useArrayType(to)[0]}.clazz, `
}
else if (to instanceof InstanceType)
if (isSubtype(from, to))
Expand Down Expand Up @@ -359,30 +358,32 @@ export function arrayElementSetter(arrayType: StaticType | undefined) {
export const accumulateInUnknownArray = 'gc_safe_array_acc'

// makes an array object from elements
export function arrayFromElements(t: StaticType) {
export function arrayFromElements(arrayType: ArrayType, env: VariableEnv) {
const t = arrayType.elementType
if (t === Integer)
return 'gc_make_intarray('
else if (t === Float)
return 'gc_make_floatarray('
else if (t === BooleanT)
return 'gc_make_bytearray(true, '
else if (t === Any)
return 'gc_make_array(1, '
return 'gc_make_array((void*)0, '
else
return 'gc_make_array(0, '
return `gc_make_array(&${env.useArrayType(arrayType)[0]}.clazz, `
}

export function arrayFromSize(t: StaticType) {
export function arrayFromSize(arrayType: ArrayType, env: VariableEnv) {
const t = arrayType.elementType
if (t === Integer)
return 'gc_new_intarray('
else if (t === Float)
return 'gc_new_floatarray('
else if (t === BooleanT)
return 'gc_new_bytearray(true, '
else if (t === Any)
return 'gc_new_array(1, '
return 'gc_new_array((void*)0, '
else
return 'gc_new_array(0, '
return `gc_new_array(&${env.useArrayType(arrayType)[0]}.clazz, `
}

export function actualElementType(t: StaticType) {
Expand All @@ -403,7 +404,7 @@ export function getArrayLengthIndex(t: StaticType) {
return 0
}

export const runtimeTypeArray = 'array_object'
export const isInstanceOfArray = `gc_is_instance_of_array(`

export const stringMaker = 'gc_new_string'
export const isStringType = 'gc_is_string_object('
Expand Down Expand Up @@ -493,7 +494,7 @@ export function classDeclaration(clazz: InstanceType, classTable: ClassTable) {
const propList = `static const uint16_t ${propListName}[] = { ${ptable.props.join(', ')} };`

return `${propList}\nCLASS_OBJECT(${classNameInC(name)}, ${table.length}) = {
.body = { .s = ${size}, .i = ${start}, .cn = "${name}", .sc = ${superAddr} , .pt = ${propTable}, .vtbl = { ${tableArray} }}};`
.body = { .s = ${size}, .i = ${start}, .cn = "${name}", .sc = ${superAddr} , .f = 0, .pt = ${propTable}, .vtbl = { ${tableArray} }}};`
}

export function makeInstance(clazz: InstanceType) {
Expand All @@ -511,3 +512,11 @@ export function methodLookup(method: [StaticType, number, InstanceType], func: s
export function isInstanceOf(t: InstanceType) {
return `gc_is_instance_of(&${classObjectNameInC(t.name())}, `
}

export function arrayTypeDeclaration(type: ArrayType, name: string, is_declared: boolean) {
const typeName = typeToString(type)
if (is_declared)
return `CLASS_OBJECT(${name}, 0) = { .body = { .s = 2, .i = 1, .cn = "${typeName}", .sc = &object_class.clazz, .f = 1, .pt = { .size = 0, .offset = 0, .unboxed = 0, .prop_names = (void*)0, .unboxed_types = (void*)0 }, .vtbl = {}}};\n`
else
return `extern CLASS_OBJECT(${name}, 0);\n`
}
Loading