static void compile_stmt(CueCodeGenerator *cg, CueAstStmt *stmt) { switch (stmt->type) { case CUE_AST_STMT_USE: { break; } case CUE_AST_STMT_EXPR: { compile_expr(cg, stmt->v.expr.value); _fmt(cg, ";\n"); break; } case CUE_AST_STMT_RET: { _fmt(cg, "return"); if (stmt->v.ret.value) { _fmt(cg, " ("); compile_expr(cg, stmt->v.ret.value); _fmt(cg, ")"); } _fmt(cg, ";\n"); break; } case CUE_AST_STMT_FUNC_DECL: { CueListNode *node; _fmt(cg, "int\n"); /* TODO return types :) */ _fmt(cg, "_%s__%s(void)", _join(cg->pool, "_", cg->ns), stmt->v.func_decl.name); _fmt(cg, "{\n"); cg->indent++; node = stmt->v.func_decl.body->head; while (node != NULL) { compile_stmt(cg, (CueAstStmt*)node->data); node = node->next; } cg->indent--; _fmt(cg, "}\n\n"); break; } default: fprintf(stderr, "unknown stmt type: %d\n", stmt->type); }; }
static void compile_expr(CueCodeGenerator *cg, CueAstExpr *expr) { switch (expr->type) { case CUE_AST_EXPR_NAME: { _fmt(cg, "%s", expr->v.name.id); break; } case CUE_AST_EXPR_STR: { _fmt(cg, "%s", expr->v.str.value); break; } case CUE_AST_EXPR_INTEGER: { _fmt(cg, "%s", expr->v.integer.value); break; } case CUE_AST_EXPR_BOOLEAN: { _fmt(cg, "%d", expr->v.boolean.value ? 1 : 0); break; } case CUE_AST_EXPR_GET_ATTR: { _fmt(cg, "("); compile_expr(cg, expr->v.get_attr.target); _fmt(cg, ")->%s", expr->v.get_attr.attr); break; } case CUE_AST_EXPR_CALL: { CueListNode *node = expr->v.call.args->head; compile_expr(cg, expr->v.call.target); _fmt(cg, "("); while (node != NULL) { compile_expr(cg, (CueAstExpr*)node->data); if (node->next) _fmt(cg, ", "); node = node->next; } _fmt(cg, ")"); break; } }; }
int compile_for_platform(Cell* expr, Cell** res) { jit_out = fopen("/tmp/jit_out.s","w"); jit_init(); register void* sp asm ("sp"); Frame empty_frame = {NULL, 0, 0, sp}; int success = compile_expr(expr, &empty_frame, TAG_ANY); jit_ret(); if (!success) { printf("<compile_expr failed: %d>\r\n",success); } if (success) { int codesz = 1024; fclose(jit_out); struct stat src_stat; stat("/tmp/jit_out.s", &src_stat); off_t generated_sz = src_stat.st_size; FILE* asm_f = fopen("/tmp/jit_out.s","r"); uint32_t* jit_asm = malloc(generated_sz); memset(jit_asm,0,generated_sz); fread(jit_asm,1,generated_sz,asm_f); fclose(asm_f); #ifdef DEBUG printf("\nJIT ---------------------\n%s-------------------------\n\n",jit_asm); #endif free(jit_asm); // prefix with arm-none-eabi- on ARM -mlittle-endian system("as -L /tmp/jit_out.s -o /tmp/jit_out.o"); #if defined(__APPLE__) && defined(__MACH__) system("gobjcopy /tmp/jit_out.o -O binary /tmp/jit_out.bin"); #else system("objcopy /tmp/jit_out.o -O binary /tmp/jit_out.bin"); #endif stat("/tmp/jit_out.bin", &src_stat); generated_sz = src_stat.st_size; while (generated_sz>codesz) { codesz*=2; printf ("<compiler: doubling code block size to %d>\r\n",codesz); } FILE* binary_f = fopen("/tmp/jit_out.bin","r"); uint32_t* jit_binary = mmap(0, codesz, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); int bytes_read = fread(jit_binary,1,codesz,binary_f); fclose(binary_f); #ifdef DEBUG printf("<assembled bytes: %d at: %p>\n",bytes_read,jit_binary); char cmd[256]; sprintf(cmd,"cp /tmp/jit_out.o /tmp/jit_%p.o",jit_binary); system(cmd); sprintf(cmd,"cp /tmp/jit_out.s /tmp/jit_%p.s",jit_binary); system(cmd); #endif if (bytes_read>codesz) { printf("<error: max assembly size of %d exhausted. aborting>\n",codesz); munmap(jit_binary,codesz); return 0; } // read symbols for linking lambdas #if defined(__APPLE__) && defined(__MACH__) system("gnm /tmp/jit_out.o > /tmp/jit_out.syms 2> /dev/null"); #else system("nm /tmp/jit_out.o > /tmp/jit_out.syms"); #endif FILE* link_f = fopen("/tmp/jit_out.syms","r"); if (link_f) { char* link_line=malloc(128); while(fgets(link_line, 128, link_f)) { if (strlen(link_line)>22) { char ida=link_line[19]; char idb=link_line[20]; char idc=link_line[21]; //printf("link_line: %s %c %c %c\n",link_line,ida,idb,idc); if (ida=='L' && idc=='_') { Cell* lambda = (Cell*)strtoul(&link_line[24], NULL, 16); if (idb=='0') { // function entrypoint // TODO: 64/32 bit unsigned long long offset = strtoul(link_line, NULL, 16); void* binary = ((uint8_t*)jit_binary) + offset; //printf("function %p entrypoint: %p (+%ld)\n",lambda,binary,offset); if (lambda->tag == TAG_LAMBDA) { lambda->dr.next = binary; } else { printf("fatal error: no lambda found at %p!\n",lambda); } } else if (idb=='1') { // function exit unsigned long long offset = strtoul(link_line, NULL, 16); //printf("function exit point: %p\n",offset); } } } } free(link_line); } int mp_res = mprotect(jit_binary, codesz, PROT_EXEC|PROT_READ); if (!mp_res) { *res = execute_jitted(jit_binary); success = 1; } else { printf("<mprotect result: %d\n>",mp_res); *res = NULL; success = 0; } } return success; }