Skip to content

Commit

Permalink
Merge pull request #25 from chibash/transpiler
Browse files Browse the repository at this point in the history
changes the implementation of value_t arrays
  • Loading branch information
maejima-fumika authored Nov 21, 2024
2 parents b5b57ee + 4a27753 commit 9ff6424
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 74 deletions.
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

0 comments on commit 9ff6424

Please sign in to comment.