Beispiel #1
0
void* simon_gc_malloc(size_t n)
{
	gc_lock();
	
	void* ptr = memory_heap_allocate(young, n);
	if (!ptr)
	{
		gc_collect();
		ptr = memory_heap_allocate(young, n);
	}
	
	gc_unlock();
	return ptr;
}
Beispiel #2
0
Datei: test5.c Projekt: hsk/docs
void* gc_alloc(ObjectType type, int size) {
  if (heap_num == heap_max) gc_collect();

  ObjectHeader* head = malloc(sizeof(ObjectHeader)+size);

  debug("gc_alloc %p\n", head);
  head->type = type;
  head->next = heap_list;
  heap_list = head;
  head->marked = 0;
  head->size=size;
  heap_num++;

  return &head[1];
}
Beispiel #3
0
Datei: test6.c Projekt: hsk/docs
void test() {
  void* frame[2];

  static void* start_ptr = &&end; goto *start_ptr; start:;

  printf("frame[1]=%p\n", frame);

  frame[0] = gc_alloc(OBJ_BOXED_ARRAY,sizeof(long)*2);
lbl1:;
  assert(heap_num==1);
  gc_collect();
  assert(heap_num==1);
lbl2:;
  gc_collect();
  assert(heap_num==1);
lbl3:;
  gc_collect();
  assert(heap_num==0);
  return;
end:;
  static int bitmap[] = {1,1};
  static Frame frames[] = {
    {&&lbl1,1,&bitmap[0]},
    {&&lbl2,1,&bitmap[1]},
Beispiel #4
0
Datei: gc.c Projekt: hsk/docs
void test_record() {
    ENTER_FRAME(frame,2);

    // レコード
    enum {RECORD_SIZE=3,RECORD_BITMAP=BIT(1)|BIT(2)};
    Object* A = pool(gc_alloc_record(RECORD_SIZE));
    A->longs[RECORD_SIZE] = RECORD_BITMAP;// レコードのビットマップ(cpuビット数分でアラインする。ビットマップもcpu bit数)
    A->longs[0] = 10; // undata
    A->field[1] = gc_alloc_int(20);
    A->field[2] = test_int(30);

    assert(vm->heap_num==3);
    gc_collect();
    assert(vm->heap_num==3);
    LEAVE_FRAME(frame);
}
Beispiel #5
0
Datei: test5.c Projekt: hsk/docs
void test() {
  void* frame[2];

  static void* start_ptr = &&end; goto *start_ptr; start:;

  printf("frame[1]=%p\n", frame);
  assert(heap_num==0);
  frame[0] = gc_alloc(OBJ_BOXED_ARRAY,sizeof(long)*2);
  assert(heap_num==1);
  gc_collect();
  assert(heap_num==1);
  return;
end:;
  static StackMap f = {3, (void*)test,&&end, NULL};
  gc_add_stack_map(&f); start_ptr=&&start; goto start;
}
Beispiel #6
0
Datei: gc.c Projekt: CRogers/obc
void *gc_alloc(value *desc, unsigned size, value *sp) {
    unsigned alloc_size;
    word *p = NULL;
    header *h;

    if (debug['z']) gc_collect(sp);

    size = round_up(size+4, BYTES_PER_WORD);

    if (size <= MAX_SMALL_BYTES) {
        /* Try to allocate from the appropriate pool */
        unsigned index = pool_map(size);
        alloc_size = pool_size(index);
        ASSERT(alloc_size >= size);

        if (free_count[index] == 0) {
            while (pool_total + pool_block(index) > heap_size
                    && free_count[index] == 0)
                scavenge(sp, pool_block(index));

            if (free_count[index] == 0)
                add_block(index);
        }

        p = (word *) free_ptr[index];
        free_ptr[index] += alloc_size;
        free_count[index]--;
    } else {
        /* Allocate whole pages */
        alloc_size = round_up(size, GC_PAGESIZE);

        while (pool_total + alloc_size > heap_size)
            scavenge(sp, alloc_size);

        h = find_block(alloc_size, alloc_size);
        insert(block_pool[n_sizes], h);
        pool_total += alloc_size;
        p = (word *) h->h_memory;
    }

    alloc_since_gc += alloc_size;
    DEBUG_PRINT('c', ("[Alloc %d %p]", size, p));
    *p = (word) desc;
    return p+1;
}
Beispiel #7
0
Datei: test5.c Projekt: hsk/docs
void test_record() {
  enum {A, DUMMY, SIZE};
  Object* frame[SIZE];
  static void* start_ptr = &&end; goto *start_ptr; start:;
  // レコード
  enum {RECORD_SIZE=3,RECORD_BITMAP=BIT(1)|BIT(2)};
  frame[A] = gc_alloc_record(RECORD_SIZE);
  frame[A]->longs[0] = 10; // undata
  frame[A]->field[1] = gc_alloc_int(20);
  frame[A]->field[2] = test_int(30);
  frame[A]->longs[RECORD_SIZE] = RECORD_BITMAP;// レコードのビットマップ(cpuビット数分でアラインする。ビットマップもcpu bit数)

  assert(heap_num==3);
  gc_collect();
  assert(heap_num==3);
  return;
end:;
  static StackMap f = {SIZE, (void*)test_record,&&end, NULL};
  gc_add_stack_map(&f); start_ptr=&&start; goto *start_ptr;
}
Beispiel #8
0
Datei: test5.c Projekt: hsk/docs
void test3() {
  enum {A, B, unboxed, DUMMY, SIZE};
  Object* frame[SIZE];
  static void* start_ptr = &&end; goto *start_ptr; start:;

  printf("test frame=%p\n", frame);

  // ペア
  frame[A] = gc_alloc_pair();
  frame[A]->pair.fst = gc_alloc_int(10);
  frame[A]->pair.snd = gc_alloc_int(20);

  // オブジェクト配列
  frame[B] = gc_alloc_boxed_array(2);
  frame[B]->field[0] = gc_alloc_int(30);
  frame[B]->field[1] = gc_alloc_int(40);

  // int配列
  frame[unboxed] = gc_alloc_unboxed_array(sizeof(int)*2);
  frame[unboxed]->ints[0] = 50;
  frame[unboxed]->ints[1] = 60;

  printf("data1 = %p %d\n", frame[A]->pair.fst, frame[A]->pair.fst->intv);
  printf("data2 = %p %d\n", frame[A]->pair.snd, frame[A]->pair.snd->intv);

  printf("data3 = %p %d\n", frame[B]->field[0], frame[B]->field[0]->intv);
  printf("data4 = %p %d\n", frame[B]->field[1], frame[B]->field[1]->intv);

  printf("data5 = %p %d\n", &frame[unboxed]->ints[0], frame[unboxed]->ints[0]);
  printf("data6 = %p %d\n", &frame[unboxed]->ints[1], frame[unboxed]->ints[1]);
  assert(heap_num==7);
  gc_collect();
  assert(heap_num==7);
  return;
end:;
  static StackMap f = {SIZE, (void*)test3,&&end, NULL};
  gc_add_stack_map(&f); start_ptr=&&start; goto start;
}
Beispiel #9
0
void 
gc_collect_garbage()
{
  int             i;
  for (i = 0; i < NUM_CELLS; i++) {
    gc_header(cells[i])->marked = 0;
  }
  gc_mark(_stack);
  gc_mark(_environ);
  gc_mark(_control);
  gc_mark(_dump);
  gc_mark(_work);
  gc_mark(_true);
  gc_mark(_false);
  gc_mark(_nil);

  gc_collect();

  if (ff == NULL) {
    printf("out of memory: %s", __func__);
    exit(-1);
  }
}
Beispiel #10
0
int main(int argc, char** argv) {
     GarbageCollector gc = gc_create(10,sizeof(struct node),node_mark,NULL,NULL);

     Node head = NULL;
     gc_protect(gc,&head); /* protect the list from garbage collection */

     /* populate the list */
     head = node(gc,head,1);
     head = node(gc,head,2);
     head = node(gc,head,3);

     /* force collect */
     gc_collect(gc);

     /* check whether list still exists */
     Node cur;
     for (cur = head; cur ; cur = cur->next)
          printf("%d\n",cur->value);

     gc_free(&gc);
     
     return 0;
}
Beispiel #11
0
Datei: gc.c Projekt: GJDuck/SMCHR
/*
 * GC should collect?
 */
static inline void gc_maybe_collect(uint32_t size)
{
    gc_alloc_size += size;
    if (gc_alloc_size >= gc_trigger_size)
    {
        if (!gc_enabled)
            return;
        gc_collect();
        size_t gc_scan_size = 0;
        size_t stacksize = gc_stackbottom - gc_stacktop();
        gc_scan_size += 2*stacksize;
        gc_root_t root = gc_roots;
        while (root != NULL)
        {
            gc_scan_size += (*root->sizeptr)*root->elemsize;
            root = root->next;
        }
        gc_scan_size += 2*gc_used_size;
        gc_trigger_size = (size_t)(gc_scan_size / GC_SPACE_FACTOR);
        gc_trigger_size = (gc_trigger_size < GC_MIN_TRIGGER? GC_MIN_TRIGGER:
            gc_trigger_size);
        gc_alloc_size = size;
    }
}
Beispiel #12
0
void simon_gc_collect()
{
	gc_lock();
	gc_collect();
	gc_unlock();
}
Beispiel #13
0
Datei: test5.c Projekt: hsk/docs
void gc_free() {
  gc_collect();
  assert(heap_num==0);
}
Beispiel #14
0
// parses, compiles and executes the code in the lexer
// frees the lexer before returning
bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) {
    mp_parse_error_kind_t parse_error_kind;
    mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_error_kind);
    qstr source_name = mp_lexer_source_name(lex);

    if (pn == MP_PARSE_NODE_NULL) {
        // parse error
        mp_parse_show_exception(lex, parse_error_kind);
        mp_lexer_free(lex);
        return false;
    }

    mp_lexer_free(lex);

    mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, is_repl);

    if (mp_obj_is_exception_instance(module_fun)) {
        mp_obj_print_exception(module_fun);
        return false;
    }

    nlr_buf_t nlr;
    bool ret;
    uint32_t start = HAL_GetTick();
    if (nlr_push(&nlr) == 0) {
        usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us
        mp_call_function_0(module_fun);
        usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
        nlr_pop();
        ret = true;
    } else {
        // uncaught exception
        // FIXME it could be that an interrupt happens just before we disable it here
        usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
        mp_obj_print_exception((mp_obj_t)nlr.ret_val);
        ret = false;
    }

    // display debugging info if wanted
    if (is_repl && repl_display_debugging_info) {
        uint32_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
        printf("took %lu ms\n", ticks);
        gc_collect();
        // qstr info
        {
            mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
            qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
            printf("qstr:\n  n_pool=" UINT_FMT "\n  n_qstr=" UINT_FMT "\n  n_str_data_bytes=" UINT_FMT "\n  n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
        }

        // GC info
        {
            gc_info_t info;
            gc_info(&info);
            printf("GC:\n");
            printf("  " UINT_FMT " total\n", info.total);
            printf("  " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
            printf("  1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
        }
    }

    return ret;
}
Beispiel #15
0
// parses, compiles and executes the code in the lexer
// frees the lexer before returning
// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, int exec_flags) {
    int ret = 0;
    uint32_t start = 0;

    nlr_buf_t nlr;
    if (nlr_push(&nlr) == 0) {
        // parse and compile the script
        qstr source_name = lex->source_name;
        mp_parse_node_t pn = mp_parse(lex, input_kind);
        mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL);

        // execute code
        mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us
        start = HAL_GetTick();
        mp_call_function_0(module_fun);
        mp_hal_set_interrupt_char(-1); // disable interrupt
        nlr_pop();
        ret = 1;
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
            mp_hal_stdout_tx_strn("\x04", 1);
        }
    } else {
        // uncaught exception
        // FIXME it could be that an interrupt happens just before we disable it here
        mp_hal_set_interrupt_char(-1); // disable interrupt
        // print EOF after normal output
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
            mp_hal_stdout_tx_strn("\x04", 1);
        }
        // check for SystemExit
        if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) {
            // at the moment, the value of SystemExit is unused
            ret = PYEXEC_FORCED_EXIT;
        } else {
            mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
            ret = 0;
        }
    }

    // display debugging info if wanted
    if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {
        mp_uint_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
        printf("took " UINT_FMT " ms\n", ticks);
        gc_collect();
        // qstr info
        {
            mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
            qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
            printf("qstr:\n  n_pool=" UINT_FMT "\n  n_qstr=" UINT_FMT "\n  n_str_data_bytes=" UINT_FMT "\n  n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
        }

        // GC info
        gc_dump_info();
    }

    if (exec_flags & EXEC_FLAG_PRINT_EOF) {
        mp_hal_stdout_tx_strn("\x04", 1);
    }

    return ret;
}
Beispiel #16
0
int main( int argc, char *argv[] ){
	int ret = 0;
	signed char option;
	int i = 0;
	int lastopt = 0;
	bool interactive = false;
	bool load_libs = true;
	bool set_a_gc_profile = false;
	unsigned new_gc_profile = 0;

	stack_frame_t *global_frame;

	if ( argc < 2 ){
		// By default, go into an REPL
		interactive = true;

	} else {
		// otherwise parse options
		lastopt = 1;

		for ( i = 1; i < argc && argv[i][0] == '-'; i++ ){
			option = argv[i][1];

			switch ( option ){
				case 'i':
					interactive = true;
					break;

				case 'h':
					print_help( );
					exit( 0 );
					break;

				case 'L':
					load_libs = false;
					break;

				case 'g':
					{
						char *profile = argv[++i];

						set_a_gc_profile = true;

						if ( strcmp( profile, "fast" ) == 0 ){
							new_gc_profile = GC_PROFILE_FAST;

						} else if ( strcmp( profile, "balanced" ) == 0 ){
							new_gc_profile = GC_PROFILE_BALANCED;

						} else if ( strcmp( profile, "lowmem" ) == 0 ){
							new_gc_profile = GC_PROFILE_LOWMEM;

						} else {
							printf( "Unknown garbage collector profile \"%s\", "
							        "using \"balanced\" instead...\n", profile );

							new_gc_profile = GC_PROFILE_BALANCED;
						}
					}

				case 'v':
					break;

				default:
					print_help( );
					exit( 1 );
					break;
			}

			/* This keeps track of where the argument after the current argument is,
			   in order to find the filenames after option parsing is done.          */
			lastopt = i + 1;
		}
	}

	// print some info about the interpreter going into a REPL
	if ( interactive ){
		printf( "%s\n", GOJIRA_BUILD_NAME );
	}

	// Initialize the global interpreter state
	global_frame = frame_create( NULL, NULL, MAKE_ENV );
	init_global_frame( global_frame );

	if ( set_a_gc_profile ){
		gc_set_profile( get_current_gc( global_frame ), new_gc_profile );
	}

	// Load the 'base' library for needed primatives
	if ( load_libs ){
		evaluate_file( global_frame, BASE_LIB );
	}

	make_argument_var( global_frame, lastopt, argc, argv );

	if ( lastopt ){
		evaluate_file( global_frame, argv[lastopt] );
	}

	// Go into the REPL if the interpreter flag is set
	if ( interactive ){
		read_eval_print( global_frame );
	}

	// Clean up the global frame, and free all tokens left in the token cache
	gc_collect( get_current_gc( global_frame ));
	destroy_token_cache( );

	return ret;
} 
Beispiel #17
0
static pobject collect(pobject env, pobject params)
{
    gc_collect(env);
    return NIL;
}
Beispiel #18
0
void *gc_alloc(machine_uint_t n_bytes, bool has_finaliser) {
    machine_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
    DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks);

    // check if GC is locked
    if (gc_lock_depth > 0) {
        return NULL;
    }

    // check for 0 allocation
    if (n_blocks == 0) {
        return NULL;
    }

    machine_uint_t i;
    machine_uint_t end_block;
    machine_uint_t start_block;
    machine_uint_t n_free = 0;
    int collected = 0;
    for (;;) {

        // look for a run of n_blocks available blocks
        for (i = 0; i < gc_alloc_table_byte_len; i++) {
            byte a = gc_alloc_table_start[i];
            if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }
            if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }
            if (ATB_2_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 2; goto found; } } else { n_free = 0; }
            if (ATB_3_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 3; goto found; } } else { n_free = 0; }
        }

        // nothing found!
        if (collected) {
            return NULL;
        }
        DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes);
        gc_collect();
        collected = 1;
    }

    // found, ending at block i inclusive
found:
    // get starting and end blocks, both inclusive
    end_block = i;
    start_block = i - n_free + 1;

    // mark first block as used head
    ATB_FREE_TO_HEAD(start_block);

    // mark rest of blocks as used tail
    // TODO for a run of many blocks can make this more efficient
    for (machine_uint_t bl = start_block + 1; bl <= end_block; bl++) {
        ATB_FREE_TO_TAIL(bl);
    }

    // get pointer to first block
    void *ret_ptr = (void*)(gc_pool_start + start_block * WORDS_PER_BLOCK);
    DEBUG_printf("gc_alloc(%p)\n", ret_ptr);

    // zero out the additional bytes of the newly allocated blocks
    // This is needed because the blocks may have previously held pointers
    // to the heap and will not be set to something else if the caller
    // doesn't actually use the entire block.  As such they will continue
    // to point to the heap and may prevent other blocks from being reclaimed.
    memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes);

#if MICROPY_ENABLE_FINALISER
    if (has_finaliser) {
        // clear type pointer in case it is never set
        ((mp_obj_base_t*)ret_ptr)->type = MP_OBJ_NULL;
        // set mp_obj flag only if it has a finaliser
        FTB_SET(start_block);
    }
#endif

    return ret_ptr;
}
Beispiel #19
0
static obj_ptr _gc(obj_ptr env)
{
    gc_collect();
    return MKBOOL(1);
}
Beispiel #20
0
Datei: gc.c Projekt: hsk/docs
void gc_free() {
    gc_collect();
    assert(vm->heap_num==0);
    free(vm);
}
ats_ptr_type
ATS_2d0_2e2_2e10_2ccomp_2runtime_2GCATS1_2gcats1_2esats__gc_freeitmlst_generate (ats_int_type arg0) {
/* local vardec */
ATSlocal (ats_ptr_type, tmp13) ;
// ATSlocal_void (tmp14) ;
// ATSlocal_void (tmp15) ;
ATSlocal (ats_ptr_type, tmp16) ;
ATSlocal (ats_ptr_type, tmp17) ;
ATSlocal (ats_bool_type, tmp18) ;
// ATSlocal_void (tmp19) ;
// ATSlocal_void (tmp20) ;
// ATSlocal_void (tmp21) ;
// ATSlocal_void (tmp22) ;
// ATSlocal_void (tmp23) ;
ATSlocal (ats_ptr_type, tmp24) ;
ATSlocal (ats_bool_type, tmp25) ;
// ATSlocal_void (tmp26) ;
ATSlocal (ats_bool_type, tmp27) ;
ATSlocal (ats_int_type, tmp28) ;
// ATSlocal_void (tmp29) ;
// ATSlocal_void (tmp30) ;
// ATSlocal_void (tmp31) ;
// ATSlocal_void (tmp32) ;
// ATSlocal_void (tmp33) ;
// ATSlocal_void (tmp34) ;
// ATSlocal_void (tmp35) ;
// ATSlocal_void (tmp36) ;
// ATSlocal_void (tmp37) ;
// ATSlocal_void (tmp38) ;
// ATSlocal_void (tmp39) ;
// ATSlocal_void (tmp40) ;
// ATSlocal_void (tmp41) ;
// ATSlocal_void (tmp42) ;
ATSlocal (ats_ptr_type, tmp43) ;
ATSlocal (ats_bool_type, tmp44) ;
// ATSlocal_void (tmp45) ;
ATSlocal (ats_int_type, tmp46) ;
ATSlocal (ats_ptr_type, tmp47) ;
// ATSlocal_void (tmp48) ;
// ATSlocal_void (tmp49) ;
ATSlocal (ats_ptr_type, tmp50) ;
ATSlocal (ats_bool_type, tmp51) ;
// ATSlocal_void (tmp52) ;
// ATSlocal_void (tmp53) ;
// ATSlocal_void (tmp54) ;

__ats_lab_ATS_2d0_2e2_2e10_2ccomp_2runtime_2GCATS1_2gcats1_2esats__gc_freeitmlst_generate:
#line 110 "gcats1_collecting.dats"
/* tmp14 = */ the_sweeplst_lock_acquire_one (arg0) ;
#line 110 "gcats1_collecting.dats"
/* tmp15 = ats_selsin_mac(tmp14, atslab_1) */ ;
#line 111 "gcats1_collecting.dats"
tmp16 = the_sweeplst_array_get (arg0) ;
#line 113 "gcats1_collecting.dats"
tmp18 = chunklst_is_cons (tmp16) ;
#line 113 "gcats1_collecting.dats"
if (tmp18) {
#line 113 "gcats1_collecting.dats"
tmp17 = tmp16 ;
} else {
#line 114 "gcats1_collecting.dats"
/* tmp19 = */ the_sweeplst_lock_release_one (arg0) ;
#line 115 "gcats1_collecting.dats"
/* tmp20 = */ gc_main_lock_acquire () ;
#line 115 "gcats1_collecting.dats"
/* tmp21 = ats_selsin_mac(tmp20, atslab_1) */ ;
#line 116 "gcats1_collecting.dats"
/* tmp22 = */ the_sweeplst_lock_acquire_one (arg0) ;
#line 116 "gcats1_collecting.dats"
/* tmp23 = ats_selsin_mac(tmp22, atslab_1) */ ;
#line 118 "gcats1_collecting.dats"
tmp24 = the_sweeplst_array_get (arg0) ;
#line 120 "gcats1_collecting.dats"
tmp25 = chunklst_is_cons (tmp24) ;
#line 120 "gcats1_collecting.dats"
if (tmp25) {
#line 121 "gcats1_collecting.dats"
/* tmp26 = */ gc_main_lock_release () ;
#line 121 "gcats1_collecting.dats"
tmp17 = tmp24 ;
} else {
#line 124 "gcats1_collecting.dats"
tmp27 = the_chunk_count_limit_is_not_reached () ;
#line 126 "gcats1_collecting.dats"
if (tmp27) {
#line 127 "gcats1_collecting.dats"
tmp28 = atspre_asl_int_int1 (1, arg0) ;
#line 127 "gcats1_collecting.dats"
tmp17 = chunklst_create_release (arg0, tmp28) ;
} else {
#line 129 "gcats1_collecting.dats"
/* tmp29 = */ the_globalentrylst_lock_acquire () ;
#line 129 "gcats1_collecting.dats"
/* tmp30 = ats_selsin_mac(tmp29, atslab_1) */ ;
#line 130 "gcats1_collecting.dats"
/* tmp31 = */ the_manmemlst_lock_acquire () ;
#line 130 "gcats1_collecting.dats"
/* tmp32 = ats_selsin_mac(tmp31, atslab_1) */ ;
#line 131 "gcats1_collecting.dats"
/* tmp33 = */ the_threadinfolst_lock_acquire () ;
#line 131 "gcats1_collecting.dats"
/* tmp34 = ats_selsin_mac(tmp33, atslab_1) */ ;
#line 133 "gcats1_collecting.dats"
/* tmp35 = */ the_sweeplst_lock_acquire_rest (arg0) ;
#line 132 "gcats1_collecting.dats"
/* tmp36 = ats_selsin_mac(tmp35, atslab_1) */ ;
#line 135 "gcats1_collecting.dats"
/* tmp37 = */ gc_collect () ;
#line 139 "gcats1_collecting.dats"
/* tmp38 = */ the_sweeplst_lock_release_rest (arg0) ;
#line 138 "gcats1_collecting.dats"
/* tmp39 = ats_selsin_mac(tmp38, atslab_1) */ ;
#line 142 "gcats1_collecting.dats"
/* tmp40 = */ the_threadinfolst_lock_release () ;
#line 143 "gcats1_collecting.dats"
/* tmp41 = */ the_manmemlst_lock_release () ;
#line 144 "gcats1_collecting.dats"
/* tmp42 = */ the_globalentrylst_lock_release () ;
#line 145 "gcats1_collecting.dats"
tmp43 = the_sweeplst_array_get (arg0) ;
#line 152 "gcats1_collecting.dats"
tmp44 = chunklst_is_cons (tmp43) ;
#line 152 "gcats1_collecting.dats"
if (tmp44) {
#line 153 "gcats1_collecting.dats"
/* tmp45 = */ gc_main_lock_release () ;
#line 153 "gcats1_collecting.dats"
tmp17 = tmp43 ;
} else {
#line 155 "gcats1_collecting.dats"
tmp46 = atspre_asl_int_int1 (1, arg0) ;
#line 155 "gcats1_collecting.dats"
tmp17 = chunklst_create_release (arg0, tmp46) ;
} /* end of [if] */
} /* end of [if] */
} /* end of [if] */
} /* end of [if] */
#line 166 "gcats1_collecting.dats"
tmp47 = chunklst_sweep_next_get (tmp17) ;
#line 167 "gcats1_collecting.dats"
/* tmp48 = */ the_sweeplst_array_set (arg0, tmp47) ;
#line 168 "gcats1_collecting.dats"
/* tmp49 = */ the_sweeplst_lock_release_one (arg0) ;
#line 169 "gcats1_collecting.dats"
tmp50 = gc_chunk_threading (tmp17) ;
#line 176 "gcats1_collecting.dats"
tmp51 = freeitmlst_is_nil (tmp50) ;
#line 176 "gcats1_collecting.dats"
if (tmp51) {
#line 177 "gcats1_collecting.dats"
/* tmp52 = */ atspre_prerr_string (ATSstrcst("GC: Fatal Error")) ;
#line 178 "gcats1_collecting.dats"
/* tmp53 = */ atspre_prerr_string (ATSstrcst(": [gc_freeitmlst_generate]: the generated freeitmlst is nil")) ;
#line 179 "gcats1_collecting.dats"
/* tmp54 = */ atspre_prerr_newline () ;
#line 180 "gcats1_collecting.dats"
/* tmp13 = */ ats_exit (1) ;
} else {
#line 182 "gcats1_collecting.dats"
tmp13 = tmp50 ;
} /* end of [if] */
return (tmp13) ;
} /* end of [ATS_2d0_2e2_2e10_2ccomp_2runtime_2GCATS1_2gcats1_2esats__gc_freeitmlst_generate] */
Beispiel #22
0
// parses, compiles and executes the code in the lexer
// frees the lexer before returning
// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags) {
    int ret = 0;
    uint32_t start = 0;

    // by default a SystemExit exception returns 0
    pyexec_system_exit = 0;

    nlr_buf_t nlr;
    if (nlr_push(&nlr) == 0) {
        mp_obj_t module_fun;
        #if MICROPY_MODULE_FROZEN_MPY
        if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) {
            // source is a raw_code object, create the function
            module_fun = mp_make_function_from_raw_code(source, MP_OBJ_NULL, MP_OBJ_NULL);
        } else
        #endif
        {
            #if MICROPY_ENABLE_COMPILER
            mp_lexer_t *lex;
            if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) {
                const vstr_t *vstr = source;
                lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0);
            } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) {
                lex = mp_lexer_new_from_file(source);
            } else {
                lex = (mp_lexer_t*)source;
            }
            // source is a lexer, parse and compile the script
            qstr source_name = lex->source_name;
            mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
            module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL);
            #else
            mp_raise_msg(&mp_type_RuntimeError, "script compilation not supported");
            #endif
        }

        // execute code
        mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us
        start = mp_hal_ticks_ms();
        mp_call_function_0(module_fun);
        mp_hal_set_interrupt_char(-1); // disable interrupt
        nlr_pop();
        ret = 1;
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
            mp_hal_stdout_tx_strn("\x04", 1);
        }
    } else {
        // uncaught exception
        // FIXME it could be that an interrupt happens just before we disable it here
        mp_hal_set_interrupt_char(-1); // disable interrupt
        // print EOF after normal output
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
            mp_hal_stdout_tx_strn("\x04", 1);
        }
        // check for SystemExit
        if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) {
            // at the moment, the value of SystemExit is unused
            ret = pyexec_system_exit;
        } else {
            mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
            ret = 0;
        }
    }

    // display debugging info if wanted
    if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {
        mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly
        printf("took " UINT_FMT " ms\n", ticks);
        // qstr info
        {
            size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
            qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
            printf("qstr:\n  n_pool=" UINT_FMT "\n  n_qstr=" UINT_FMT "\n  "
                   "n_str_data_bytes=" UINT_FMT "\n  n_total_bytes=" UINT_FMT "\n",
                   (unsigned)n_pool, (unsigned)n_qstr, (unsigned)n_str_data_bytes, (unsigned)n_total_bytes);
        }

        #if MICROPY_ENABLE_GC
        // run collection and print GC info
        gc_collect();
        gc_dump_info();
        #endif
    }

    if (exec_flags & EXEC_FLAG_PRINT_EOF) {
        mp_hal_stdout_tx_strn("\x04", 1);
    }

    return ret;
}
Beispiel #23
0
/* Here we don't know the size of the frame that overflowed.  If the 
   frame is larger than the nursery then we will loop forever.  This can
   be fixed, but that large a frame (or small a nursery) is not realistic.
   */
static void stack_overflow( young_heap_t *heap )
{
  gc_collect( heap->collector, 0, 0, GCTYPE_EVACUATE );
}
Beispiel #24
0
static void collect_if_no_room( young_heap_t *heap, int room )
{
  room = roundup_balign( room );
  if (free_space( heap ) < room)
    gc_collect( heap->collector, 0, room, GCTYPE_EVACUATE );
}
Beispiel #25
0
void *gc_alloc(size_t n_bytes, bool has_finaliser) {
    size_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
    DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks);

    // check if GC is locked
    if (MP_STATE_MEM(gc_lock_depth) > 0) {
        return NULL;
    }

    // check for 0 allocation
    if (n_blocks == 0) {
        return NULL;
    }

    size_t i;
    size_t end_block;
    size_t start_block;
    size_t n_free = 0;
    int collected = !MP_STATE_MEM(gc_auto_collect_enabled);
    for (;;) {

        // look for a run of n_blocks available blocks
        for (i = MP_STATE_MEM(gc_last_free_atb_index); i < MP_STATE_MEM(gc_alloc_table_byte_len); i++) {
            byte a = MP_STATE_MEM(gc_alloc_table_start)[i];
            if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }
            if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }
            if (ATB_2_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 2; goto found; } } else { n_free = 0; }
            if (ATB_3_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 3; goto found; } } else { n_free = 0; }
        }

        // nothing found!
        if (collected) {
            return NULL;
        }
        DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes);
        gc_collect();
        collected = 1;
    }

    // found, ending at block i inclusive
found:
    // get starting and end blocks, both inclusive
    end_block = i;
    start_block = i - n_free + 1;

    // Set last free ATB index to block after last block we found, for start of
    // next scan.  To reduce fragmentation, we only do this if we were looking
    // for a single free block, which guarantees that there are no free blocks
    // before this one.  Also, whenever we free or shink a block we must check
    // if this index needs adjusting (see gc_realloc and gc_free).
    if (n_free == 1) {
        MP_STATE_MEM(gc_last_free_atb_index) = (i + 1) / BLOCKS_PER_ATB;
    }

    // mark first block as used head
    ATB_FREE_TO_HEAD(start_block);

    // mark rest of blocks as used tail
    // TODO for a run of many blocks can make this more efficient
    for (size_t bl = start_block + 1; bl <= end_block; bl++) {
        ATB_FREE_TO_TAIL(bl);
    }

    // get pointer to first block
    void *ret_ptr = (void*)(MP_STATE_MEM(gc_pool_start) + start_block * BYTES_PER_BLOCK);
    DEBUG_printf("gc_alloc(%p)\n", ret_ptr);

    // Zero out all the bytes of the newly allocated blocks.
    // This is needed because the blocks may have previously held pointers
    // to the heap and will not be set to something else if the caller
    // doesn't actually use the entire block.  As such they will continue
    // to point to the heap and may prevent other blocks from being reclaimed.
    memset((byte*)ret_ptr, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK);

    #if MICROPY_ENABLE_FINALISER
    if (has_finaliser) {
        // clear type pointer in case it is never set
        ((mp_obj_base_t*)ret_ptr)->type = NULL;
        // set mp_obj flag only if it has a finaliser
        FTB_SET(start_block);
    }
    #else
    (void)has_finaliser;
    #endif

    #if EXTENSIVE_HEAP_PROFILING
    gc_dump_alloc_table();
    #endif

    return ret_ptr;
}
Beispiel #26
0
void irom_close(void *stream_data)  {
    pb_context_t *ctx = (pb_context_t *)stream_data;
    m_del_obj(pb_context_t, ctx);
    gc_collect();
}
Beispiel #27
0
// TODO: this doesn't belong here
STATIC mp_obj_t pyb_gc(void) {
    gc_collect();
    return mp_const_none;
}
Beispiel #28
0
// parses, compiles and executes the code in the lexer
// frees the lexer before returning
// EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output
// EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, int exec_flags) {
    int ret = 0;

    mp_parse_error_kind_t parse_error_kind;
    mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_error_kind);
    qstr source_name = mp_lexer_source_name(lex);

    // check for parse error
    if (pn == MP_PARSE_NODE_NULL) {
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
            stdout_tx_strn("\x04", 1);
        }
        mp_parse_show_exception(lex, parse_error_kind);
        mp_lexer_free(lex);
        goto finish;
    }

    mp_lexer_free(lex);

    mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL);

    // check for compile error
    if (mp_obj_is_exception_instance(module_fun)) {
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
            stdout_tx_strn("\x04", 1);
        }
        mp_obj_print_exception(module_fun);
        goto finish;
    }

    // execute code
    nlr_buf_t nlr;
    uint32_t start = HAL_GetTick();
    if (nlr_push(&nlr) == 0) {
        mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us
        mp_call_function_0(module_fun);
        mp_hal_set_interrupt_char(-1); // disable interrupt
        nlr_pop();
        ret = 1;
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
            stdout_tx_strn("\x04", 1);
        }
    } else {
        // uncaught exception
        // FIXME it could be that an interrupt happens just before we disable it here
        mp_hal_set_interrupt_char(-1); // disable interrupt
        // print EOF after normal output
        if (exec_flags & EXEC_FLAG_PRINT_EOF) {
            stdout_tx_strn("\x04", 1);
        }
        // check for SystemExit
        if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) {
            // at the moment, the value of SystemExit is unused
            ret = PYEXEC_FORCED_EXIT;
        } else {
            mp_obj_print_exception((mp_obj_t)nlr.ret_val);
            ret = 0;
        }
    }

    // display debugging info if wanted
    if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {
        mp_uint_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
        printf("took " UINT_FMT " ms\n", ticks);
        gc_collect();
        // qstr info
        {
            mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
            qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
            printf("qstr:\n  n_pool=" UINT_FMT "\n  n_qstr=" UINT_FMT "\n  n_str_data_bytes=" UINT_FMT "\n  n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
        }

        // GC info
        {
            gc_info_t info;
            gc_info(&info);
            printf("GC:\n");
            printf("  " UINT_FMT " total\n", info.total);
            printf("  " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
            printf("  1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
        }
    }

finish:
    if (exec_flags & EXEC_FLAG_PRINT_EOF) {
        stdout_tx_strn("\x04", 1);
    }

    return ret;
}
Beispiel #29
0
sexpr_t* eval(sexpr_t* sexpr, sexpr_t** env, sexpr_list_t* roots, error_t** error)
{
    if(sexpr == NULL) {
        return interp.nil_sym;
    }

    /* printf("[eval]\n"); */
    /* print_sexpr(sexpr); */
    /* printf("\n"); */
    roots = cons_to_roots_list(roots, sexpr);
    gc_collect(roots);
    
    if(ATOM(sexpr)) {
        if(SYM(sexpr)) {
            if(interp.t_sym == sexpr) {
                return interp.t_sym;
            }
            if(interp.nil_sym == sexpr) {
                return interp.nil_sym;
            }
            sexpr_t* val = assoc(sexpr, *env);
            if(val == NULL) {
                *error = mk_error("Undefined symbol", SYM_VAL(sexpr));
            }

            return val;
        }
        if(INT(sexpr)) {
            return sexpr;
        }
    } else if(ATOM(CAR(sexpr))) {
        if(SYM(CAR(sexpr))) {
            // quote
            if(interp.quote_sym == CAR(sexpr)) {
                if(CDR(sexpr) == NULL) {
                    *error = mk_error("Missing quote argument", "");
                    return NULL;
                }
                if(CDR(CDR(sexpr)) != NULL) {
                    *error = mk_error("Too many arguments for quote", "");
                    return NULL;
                }
                return CAR(CDR(sexpr));
            }
            // atom
            if(interp.atom_sym == CAR(sexpr)) {
                if(ATOM(eval(CAR(CDR(sexpr)), env, roots, error))) {
                    return interp.t_sym;
                }
                return interp.nil_sym;
            }
            // eq
            if(interp.eq_sym == CAR(sexpr)) {
                // TODO check nb args
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                roots = cons_to_roots_list(roots, e1);
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(INT(e1) && INT(e2)) {
                    if(INT_VAL(e1) == INT_VAL(e2)) {
                        return interp.t_sym;
                    }
                    return interp.nil_sym;
                }
                if(e1 == e2) {
                    return interp.t_sym;
                }
                return interp.nil_sym;
            }
            // if
            if(interp.if_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(e1 == interp.nil_sym) {
                    return eval(CAR(CDR(CDR(CDR(sexpr)))), env, roots, error);
                } else {
                    return eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                }
            }
            // car
            if(interp.car_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(e1 == interp.nil_sym) {
                    return interp.nil_sym;
                }
                return CAR(e1);
            }
            // cdr
            if(interp.cdr_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);

                if(*error != NULL) {
                    return NULL;
                }
                if(e1 == interp.nil_sym) {
                    return interp.nil_sym;
                }
                sexpr_t *res = CDR(e1);
                if(res == NULL) {
                    return interp.nil_sym;
                }
                return res;
            }
            // +
            if(interp.plus_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                roots = cons_to_roots_list(roots, e1); 
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(INT(e1) && INT(e2)) {
                    return mk_int(INT_VAL(e1) + INT_VAL(e2));
                }

                *error = mk_error("Arguments for '+' are not integers", "");
                return NULL;
            }
            // -
            if(interp.minus_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                roots = cons_to_roots_list(roots, e1);
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(INT(e1) && INT(e2)) {
                    return mk_int(INT_VAL(e1) - INT_VAL(e2));
                }

                *error = mk_error("Arguments for '-' are not integers", "");
                return NULL;
            }
            if(interp.mul_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                roots = cons_to_roots_list(roots, sexpr); 
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                if(INT(e1) && INT(e2)) {
                    return mk_int(INT_VAL(e1) * INT_VAL(e2));
                }

                *error = mk_error("Arguments for '*' are not integers", "");
                return NULL;
            }
            // cons
            if(interp.cons_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                roots = cons_to_roots_list(roots, e1);
                sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                return mk_cons(e1 == interp.nil_sym ? NULL : e1, e2 == interp.nil_sym ? NULL : e2);
            }
            // def
            if(interp.def_sym == CAR(sexpr)) {
                sexpr_t* arg = CAR(CDR(CDR(sexpr)));
                roots = cons_to_roots_list(roots, arg);
                sexpr_t* val = eval(arg, env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                
                *env = mk_cons(mk_cons(intern(SYM_VAL(CAR(CDR(sexpr)))), val), *env);
                return val;
            }
            // print
            if(interp.print_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }
                print_sexpr(e1);
                printf("\n");

                return e1;
            }
            // fn
            if(interp.fn_sym == CAR(sexpr)) {
                return mk_fn(sexpr, *env);
            }
            // macro
            if(interp.macro_sym == CAR(sexpr)) {
                return mk_macro(sexpr);
            }
            //eval
            if(interp.eval_sym == CAR(sexpr)) {
                sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                roots = cons_to_roots_list(roots, e1);
                return eval(e1, env, roots, error);
            }
            // else resolves first variable

            sexpr_t* fn = eval(CAR(sexpr), env, roots, error);
            if(*error != NULL) {
                return NULL;
            }

            // eval fn
            if(FN(fn)) {
                sexpr_t* fn_code = CAR(CDR(CDR(CAR(fn))));
                sexpr_t* captured_env = CDR(fn);
                sexpr_t* arguments = eval_list(CDR(sexpr), env, roots, error);
                if(*error != NULL) {
                    return NULL;
                }

                sexpr_t* pairs = pair(CAR(CDR(CAR(fn))), arguments);
                sexpr_t* eval_env = append(pairs, captured_env);

                // append the function itself to the env, roots, for recursive calls
                eval_env = mk_cons(mk_cons(CAR(sexpr), fn), eval_env);
                
                /* printf("fn code=\n"); */
                /* print_sexpr(fn_code); */
                /* printf("\n"); */
                roots = cons_to_roots_list(roots, eval_env);
                return eval(fn_code, &eval_env, roots, error);
            }

            // eval macro
            if(MACRO(fn)) {
                sexpr_t* macro_code = CAR(CDR(CDR(CAR(fn))));
                sexpr_t* pairs = pair(CAR(CDR(CAR(fn))), CDR(sexpr));
                sexpr_t* eval_env = append(pairs, *env);

                roots = cons_to_roots_list(roots, eval_env);
                sexpr_t* transformed_code = eval(macro_code, &eval_env, roots, error);

                if(*error != NULL) {
                    return NULL;
                }

                return eval(transformed_code, env, roots, error);
            }
            
            // else primitives
            sexpr_t* arguments = eval_list(CDR(sexpr), env, roots, error);
            if(*error != NULL) {
                return NULL;
            }
            sexpr_t* to_eval = mk_cons(fn, arguments);
            return eval(to_eval, env, roots, error);
        }
    } else if(CAR(CAR(sexpr)) == interp.fn_sym) {
        // executes an anonymous function

        sexpr_t* fn = CAR(sexpr);
        sexpr_t* fn_code = CAR(CDR(CDR(fn)));
        sexpr_t* arguments = eval_list(CDR(sexpr), env, roots, error);
        if(*error != NULL) {
            return NULL;
        }
        
        sexpr_t* l = pair(CAR(CDR(fn)), arguments);
        l = append(l, *env);

        roots = cons_to_roots_list(roots, l);
        return eval(fn_code, &l, roots, error);
    }

    print_sexpr(sexpr);
    printf("\n");
    *error = mk_error("Invalid expression", "");

    return NULL;
}
Beispiel #30
0
void _System_fullGC(pVMObject object, pVMFrame frame) {
    SEND(frame, pop);
    gc_collect();
    SEND(frame, push, true_object);
}