Skip to content

Commit

Permalink
Fix some bugs and add test
Browse files Browse the repository at this point in the history
  • Loading branch information
maejima-fumika committed Nov 14, 2024
1 parent 021ac92 commit f06be32
Show file tree
Hide file tree
Showing 13 changed files with 317 additions and 80 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/microcontroller_core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,10 @@ jobs:
run: gcc -DTEST64 float-test.c -o float-test -lm

- name: Run float-test
run: ./float-test
run: ./float-test

- name: Build profiler-test
run: gcc -DTEST64 profiler-test.c -o profiler-test -lm

- name: Run profiler-test
run: ./profiler-test
3 changes: 2 additions & 1 deletion microcontroller/core/include/c-runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ extern value_t CR_SECTION gc_new_bytearray(bool is_boolean, int32_t n, int32_t i
extern value_t CR_SECTION gc_make_bytearray(bool is_boolean, int32_t n, ...);
extern int32_t CR_SECTION gc_bytearray_length(value_t obj);
extern uint8_t* CR_SECTION gc_bytearray_get(value_t obj, int32_t index);
extern bool CR_SECTION gc_is_bytearray(value_t v);
extern bool CR_SECTION gc_is_boolarray(value_t v);

extern value_t CR_SECTION safe_value_to_vector(value_t v);
extern value_t CR_SECTION gc_new_vector(int32_t n, value_t init_value);
Expand All @@ -255,6 +255,7 @@ extern value_t CR_SECTION gc_make_array(int32_t is_any, 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);
extern bool CR_SECTION gc_is_anyarray(value_t v);

extern int32_t CR_SECTION get_all_array_length(value_t obj);
extern value_t CR_SECTION get_anyobj_length_property(value_t obj, int property);
Expand Down
2 changes: 2 additions & 0 deletions microcontroller/core/include/profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#ifdef TEST64
typedef uint64_t typeint_t;
#define CORE_TEXT_SECTION
#define CORE_DATA_SECTION
#else
typedef uint32_t typeint_t;
#define CORE_TEXT_SECTION __attribute__((section(".core_text")))
Expand Down
22 changes: 16 additions & 6 deletions microcontroller/core/src/c-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ int32_t* gc_intarray_get(value_t obj, int32_t index) {

bool gc_is_intarray(value_t v) {
const class_object* type = gc_get_class_of(v);
return type == &intarray_object;
return type == &intarray_object.clazz;
}

// A float array
Expand Down Expand Up @@ -856,6 +856,11 @@ float* gc_floatarray_get(value_t obj, int32_t index) {
}
}

bool gc_is_floatarray(value_t v) {
const class_object* type = gc_get_class_of(v);
return type == &floatarray_object.clazz;
}

// A byte array and a boolean array

CLASS_OBJECT(class_Uint8Array, 1) = {
Expand All @@ -870,11 +875,6 @@ value_t safe_value_to_boolarray(value_t v) {
return safe_value_to_value(&boolarray_object.clazz, v);
}

bool gc_is_bytearray(value_t v) {
const class_object* type = gc_get_class_of(v);
return type == &bytearray_object;
}

/*
A byte (or unsigned 8 bit) array. It cannot contain a pointer.
n: the size of the array in bytes.
Expand Down Expand Up @@ -944,6 +944,11 @@ uint8_t* gc_bytearray_get(value_t obj, int32_t idx) {
}
}

bool gc_is_boolarray(value_t v) {
const class_object* type = gc_get_class_of(v);
return type == &boolarray_object.clazz;
}

// A fixed-length array

static CLASS_OBJECT(vector_object, 1) = {
Expand Down Expand Up @@ -1194,6 +1199,11 @@ value_t gc_safe_array_acc(value_t obj, int32_t index, char op, value_t value) {
return gc_safe_array_set(obj, index, new_value);
}

bool gc_is_anyarray(value_t v) {
const class_object* type = gc_get_class_of(v);
return type == &anyarray_object.clazz;
}

// Compute an object size. It is always an even number.
//
// length: length of object_type.body[]
Expand Down
10 changes: 5 additions & 5 deletions microcontroller/core/src/profiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static typeint_t value_to_typeint(value_t p) {
}
}

static char* typeint_to_str(typeint_t typeint) {
static const char* typeint_to_str(typeint_t typeint) {
if (typeint == 0b00) {
return "integer";
} else if (typeint == 0b01) {
Expand Down Expand Up @@ -67,10 +67,10 @@ static bool row_match_param_types(typeint_t* type_profile_row, value_t p1, value
}

static char* row_to_str(typeint_t* type_profile_row) {
char* p1_str = typeint_to_str(*(type_profile_row + 1));
char* p2_str = typeint_to_str(*(type_profile_row + 2));
char* p3_str = typeint_to_str(*(type_profile_row + 3));
char* p4_str = typeint_to_str(*(type_profile_row + 4));
const char* p1_str = typeint_to_str(*(type_profile_row + 1));
const char* p2_str = typeint_to_str(*(type_profile_row + 2));
const char* p3_str = typeint_to_str(*(type_profile_row + 3));
const char* p4_str = typeint_to_str(*(type_profile_row + 4));
snprintf(types_str, sizeof(types_str), "%s, %s, %s, %s", p1_str, p2_str, p3_str, p4_str);
return types_str;
}
Expand Down
26 changes: 13 additions & 13 deletions microcontroller/core/test/profiler-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,57 +27,57 @@ static int32_t test_function_object00(int32_t v) {
static void test_converter() {
value_t any_i = int_to_value(42);
typeint_t typeint_i = value_to_typeint(any_i);
char* result_str_i = typeint_to_str(typeint_i);
const char* result_str_i = typeint_to_str(typeint_i);
Assert_str_equals(result_str_i, "integer");

value_t any_f = float_to_value(13.5);
typeint_t typeint_f = value_to_typeint(any_f);
char* result_str_f = typeint_to_str(typeint_f);
const char* result_str_f = typeint_to_str(typeint_f);
Assert_str_equals(result_str_f, "float");

value_t any_b = VALUE_FALSE;
typeint_t typeint_b = value_to_typeint(any_b);
char* result_str_b = typeint_to_str(typeint_b);
const char* result_str_b = typeint_to_str(typeint_b);
Assert_str_equals(result_str_b, "boolean");

value_t any_u = VALUE_UNDEF;
typeint_t typeint_u = value_to_typeint(any_u);
char* result_str_u = typeint_to_str(typeint_u);
const char* result_str_u = typeint_to_str(typeint_u);
Assert_str_equals(result_str_u, "undefined");

value_t any_n = VALUE_NULL;
typeint_t typeint_n = value_to_typeint(any_n);
char* result_str_n = typeint_to_str(typeint_n);
const char* result_str_n = typeint_to_str(typeint_n);
Assert_str_equals(result_str_n, "undefined");

value_t s = gc_new_string("test");
typeint_t typeint_s = value_to_typeint(s);
char* result_str_s = typeint_to_str(typeint_s);
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));
typeint_t typeint_arr = value_to_typeint(arr);
char* result_str_arr = typeint_to_str(typeint_arr);
const char* result_str_arr = typeint_to_str(typeint_arr);
Assert_str_equals(result_str_arr, "Array<any>");

value_t iarr = gc_new_intarray(3, 0);
typeint_t typeint_iarr = value_to_typeint(iarr);
char* result_str_iarr = typeint_to_str(typeint_iarr);
const char* result_str_iarr = typeint_to_str(typeint_iarr);
Assert_str_equals(result_str_iarr, "Array<integer>");

value_t farr = gc_new_floatarray(4, 1.2);
typeint_t typeint_farr = value_to_typeint(farr);
char* result_str_farr = typeint_to_str(typeint_farr);
const char* result_str_farr = typeint_to_str(typeint_farr);
Assert_str_equals(result_str_farr, "Array<float>");

value_t barr = gc_new_bytearray(5, 0);
value_t barr = gc_new_bytearray(true, 5, 0);
typeint_t typeint_barr = value_to_typeint(barr);
char* result_str_barr = typeint_to_str(typeint_barr);
Assert_str_equals(result_str_barr, "ByteArray");
const char* result_str_barr = typeint_to_str(typeint_barr);
Assert_str_equals(result_str_barr, "Array<boolean>");

value_t func = gc_new_function(test_function_object00, "(i)i", int_to_value(3));
typeint_t typeint_func = value_to_typeint(func);
char* result_str_func = typeint_to_str(typeint_func);
const char* result_str_func = typeint_to_str(typeint_func);
Assert_str_equals(result_str_func, "Function");
}

Expand Down
5 changes: 4 additions & 1 deletion notebook/src/services/network.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios from "axios";
import { CompileError } from "../utils/error";
import { CompileError, InternalError } from "../utils/error";
import { MemInfo } from "../utils/type";


Expand Down Expand Up @@ -45,6 +45,9 @@ async function post(path: string, body: object) {
if (e.response?.status === CompileError.errorCode) {
throw new CompileError(JSON.parse(e.response?.data).message.messages)
}
if (e.response?.status === InternalError.errorCode) {
throw new InternalError(JSON.parse(e.response?.data).message.message)
}
}
throw e;
}
Expand Down
11 changes: 10 additions & 1 deletion notebook/src/utils/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,13 @@ interface SourceLocation {
line: number;
column: number;
};
}
}

export class InternalError extends Error {
static errorCode = 462;

public constructor(message?: string) {
super(`Internal Error: ${message}`);
}
}

15 changes: 8 additions & 7 deletions server/src/jit/jit-code-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {FunctionDeclaration} from "@babel/types";
import * as cr from "../transpiler/code-generator/c-runtime";
import {getStaticType, NameInfo, NameTableMaker} from "../transpiler/names";
import {jitTypecheck, JitTypeChecker} from "./jit-type-checker";
import {getSpecializedNode} from "./utils";
import {getSpecializedNode, JITCompileError, ProfileError} from "./utils";
import {InstanceType} from "../transpiler/classes";
import {classNameInC} from "../transpiler/code-generator/c-runtime";

Expand Down Expand Up @@ -73,16 +73,17 @@ function specializedFunctionBodyName(name: string) {
// returns '(' or '<type check function>('
// '(' is returned if the type cannot be checked.
function checkType(type?: StaticType) {

if (type instanceof ArrayType) {
if (type.elementType === Integer)
return 'gc_is_intarray(';
if (type.elementType === Float)
return 'gc_is_floatarray(';
if (type.elementType === BooleanT)
return 'gc_is_bytearray(';
return 'gc_is_boolarray(';
if (type.elementType === Any)
return 'gc_is_anyarray(';
else
return undefined
throw new JITCompileError('Unknown array type.');
}

if (type instanceof InstanceType) {
Expand Down Expand Up @@ -122,7 +123,7 @@ export class JitCodeGenerator extends CodeGenerator{
const funcName = funcInfo ? funcInfo.transpiledName(name) : name
const fenv = new FunctionEnv(getVariableNameTable(node), env)

if (!funcType.paramTypes.includes(Any) || funcType.paramTypes.filter(t=> t === Any).length > maxParamNum) {
if (!Profiler.funcIsSpecializeable(funcType)) {
super.functionDeclaration(node, env);
return;
}
Expand All @@ -147,7 +148,7 @@ export class JitCodeGenerator extends CodeGenerator{
case 'specializing': {
const specializedNode = getSpecializedNode(node);
if (specializedNode === undefined)
throw new Error('Fatal: cannot find specialized node.')
throw new ProfileError(`Cannot find specialized node. Node: ${node}`)
const specializedFenv = new FunctionEnv(getVariableNameTable(specializedNode), env)
this.functionBodyDeclaration2(specializedNode, specializedFuncName, specializedFuncBodyName, specializedFenv, false)
this.wrapperFunctionBodyDeclaration(node, funcName, true, funcProfile, fenv)
Expand All @@ -163,7 +164,7 @@ export class JitCodeGenerator extends CodeGenerator{
case 'specialized': {
const specializedNode = getSpecializedNode(node);
if (specializedNode === undefined)
throw new Error('Fatal: cannot find specialized node.')
throw new ProfileError(`Cannot find specialized node. Node: ${node}`)
const specializedFenv = new FunctionEnv(getVariableNameTable(specializedNode), env)
this.functionBodyDeclaration2(specializedNode, specializedFuncName, specializedFuncBodyName, specializedFenv, true)
this.functionBodyDeclaration2(node, originalFuncName, originalFuncBodyName, fenv, true)
Expand Down
27 changes: 20 additions & 7 deletions server/src/jit/profiler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Any, FunctionType, StaticType} from "../transpiler/types";
import {Any, ArrayType, FunctionType, StaticType} from "../transpiler/types";
import {ProfileError} from "./utils";


export type FunctionState =
Expand All @@ -24,18 +25,30 @@ export const maxParamNum = 4;
export class Profiler {
private nextFuncId: number = 0;
private profiles: Map<string, FunctionProfile> = new Map();
private id2Name: Map<number, string> = new Map();
private idToName: Map<number, string> = new Map();

setFunctionProfile(name: string, src: string, type: FunctionType) {
const id = this.nextFuncId++;
const profile:FunctionProfile = {id, name, src, type, state: {state: "profiling"}}
this.profiles.set(name, profile);
this.id2Name.set(id, name);
this.idToName.set(id, name);
return profile;
}

static funcIsSpecializeable(funcType: FunctionType) {
const returnType = funcType.returnType;
if (!funcType.paramTypes.includes(Any) || funcType.paramTypes.filter(t=> t === Any).length > maxParamNum)
return false;
if (returnType instanceof FunctionType)
return false;
const acceptableElementTypes: StaticType[] = ['integer', 'float', 'boolean', 'any']
if (returnType instanceof ArrayType && !acceptableElementTypes.includes(returnType.elementType))
return false;
return true;
}

getFunctionProfileById(id: number) {
const funcName = this.id2Name.get(id);
const funcName = this.idToName.get(id);
return funcName ? this.profiles.get(funcName) : undefined;
}

Expand All @@ -50,12 +63,12 @@ export class Profiler {
}

setFuncSpecializedType(id: number, paramTypes: StaticType[]) {
const funcName = this.id2Name.get(id);
const funcName = this.idToName.get(id);
if (funcName === undefined)
throw new Error(`Cannot not find the target function. id: ${id}`);
throw new ProfileError(`Cannot find the target function. id: ${id}`);
const func = this.profiles.get(funcName);
if (func === undefined)
throw new Error(`Cannot not find the target function. name: ${funcName}`);
throw new ProfileError(`Cannot not find the target function. name: ${funcName}`);
if (paramTypes.slice(0, func.type.paramTypes.length).every(t => t === Any)) {
func.state = {state: 'undoing'}
return;
Expand Down
18 changes: 16 additions & 2 deletions server/src/jit/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ export function typeStringToStaticType(typeString: string, gvnt?: GlobalVariable
return new ArrayType('integer')
} else if (typeString === 'Array<float>') {
return new ArrayType('float')
} else if (typeString === 'ByteArray') {
} else if (typeString === 'Array<boolean>') {
return new ArrayType('boolean')
} else if (typeString === 'Array') {
return 'any'
} else if (typeString === 'Function') {
return 'any'
} else {
const clazz = gvnt === undefined ? undefined : gvnt.classTable().findClass(typeString)
if (clazz === undefined)
throw new Error("Cannot find class");
throw new ProfileError(`Cannot find the profiled class: ${typeString}`)
return clazz
}
}
Expand Down Expand Up @@ -113,3 +115,15 @@ export function convertAst(ast: AST.Node, profiler: Profiler) {
})
}


export class ProfileError extends Error {
public constructor(message?: string) {
super(`Profile Error: ${message}`);
}
}

export class JITCompileError extends Error {
public constructor(message?: string) {
super(`JIT Compile Error: ${message}`);
}
}
7 changes: 6 additions & 1 deletion server/src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import {Buffer} from "node:buffer";
import {ErrorLog} from "../transpiler/utils";
import Session from "./session";
import {execSync} from "child_process";
import {JITCompileError, ProfileError} from "../jit/utils";

const ERROR_CODE = {
COMPILE_ERROR: 460,
LINK_ERROR: 461
LINK_ERROR: 461,
INTERNAL_ERROR: 462,
}

export default class HttpServer {
Expand Down Expand Up @@ -114,6 +116,9 @@ export default class HttpServer {
if (e instanceof ErrorLog) {
responseBody = {message: e};
statusCode = ERROR_CODE.COMPILE_ERROR;
} else if (e instanceof ProfileError || e instanceof JITCompileError) {
responseBody = {message: e};
statusCode = ERROR_CODE.INTERNAL_ERROR;
} else {
responseBody = {message: e};
statusCode = 500;
Expand Down
Loading

0 comments on commit f06be32

Please sign in to comment.