- files can be reloaded and edited
- modules can be (re)loaded
- keyboard navigation
-- editor:
- - more efficient multi-line inserts
- - write "foo| " and put caret at | then select word element: selects
- space
- ui browser: show currently selected vocab & words
- keyboard-navigatable list gadget of some kind
- tuple= in dataflow view
- ui quick start doc
- auto-update browser and help when sources reload
- how do we refer to command shortcuts in the docs?
-- reliably clonable gadgets
- figure out if we need both set-model and set-model*
- if i do 10000 [ . ] each and then clear, the listener window is slow
- full-height nodes should really be full height
- editor should support stream output protocol
- double/triple click
- autoscroll
- - undo and redo
- transpose char/word/line
- - page up/down
- - search and replace
- drag scroll
+ - more efficient multi-line inserts
+ - write "foo| " and put caret at | then select word element: selects
+ space
- slider needs to be modelized
- fonts/ should go inside the .app -- we need multi-tier resource-path
- should be possible to drop an image file on the .app to run it
- own-selection violates ICCCM
- cocoa: windows are not updated while resizing
- grid slows down with 2000 lines
-- ui uses too much cpu time idling
- see if its possible to only repaint dirty regions
- x11 title bars are funny
- rollover is not updated on window focus changes
+ misc:
+- symbol redef is an xref false positive
- signal 4 on datastack underflow on mac intel??
- fix alien-callback/SEH bug on win32
- minor GC takes too long now, we should card mark code heap
dup word-primitive ' ,
dup word-def ' ,
dup word-props ' ,
+ f ' ,
0 ,
] { } make
word-tag word-tag [ emit-seq ] emit-object
{ "float>=" "math-internals" }
{ "(word)" "kernel-internals" }
{ "update-xt" "words" }
- { "compiled?" "words" }
{ "drop" "kernel" }
{ "2drop" "kernel" }
{ "3drop" "kernel" }
{ "word-props" "words" }
{ "set-word-props" "words" }
}
+ {
+ 7
+ object
+ { "compiled?" "words" }
+ f
+ }
} define-builtin
"ratio?" "math" create t "inline" set-word-prop
F_BLOCK *prev = NULL;
F_BLOCK *scan = heap->free_list;
+ size = align8(size);
+
while(scan)
{
CELL this_size = scan->size - sizeof(F_BLOCK);
if(compiled->finalized)
{
for(scan = words_start; scan < words_end; scan += CELLS)
- mark_and_sweep(get(scan));
+ recursive_mark(get(scan));
}
}
-void mark_and_sweep(CELL xt)
+void recursive_mark(CELL xt)
{
F_BLOCK *block = xt_to_block(xt);
if(block->status == B_MARKED)
return;
- else if(block->status == B_FREE)
- critical_error("Marking a free block",(CELL)block);
-
- block->status = B_MARKED;
+ else if(block->status == B_ALLOCATED)
+ block->status = B_MARKED;
+ else
+ critical_error("Marking the wrong block",(CELL)block);
F_COMPILED *compiled = xt_to_compiled(xt);
iterate_code_heap_step(compiled,collect_literals_step);
void init_code_heap(CELL size);
void iterate_code_heap(CODE_HEAP_ITERATOR iter);
void collect_literals(void);
-void mark_and_sweep(CELL xt);
+void recursive_mark(CELL xt);
void primitive_code_room(void);
void primitive_code_gc(void);
F_ARRAY *pair = untag_array(get(AREF(array,i)));
F_WORD *word = untag_word(get(AREF(pair,0)));
word->xt = to_cell(get(AREF(pair,1)));
+ word->compiledp = T;
}
/* perform relocation */
drepl(tag_fixnum(object_size(dpeek())));
}
-/* The number of cells from the start of the object which should be scanned by
-the GC. Some types have a binary payload at the end (string, word, DLL) which
-we ignore. */
-CELL binary_payload_start(CELL pointer)
-{
- switch(untag_header(get(pointer)))
- {
- /* these objects do not refer to other objects at all */
- case STRING_TYPE:
- case FLOAT_TYPE:
- case BYTE_ARRAY_TYPE:
- case BIGNUM_TYPE:
- return 0;
- /* these objects have some binary data at the end */
- case WORD_TYPE:
- return sizeof(F_WORD) - CELLS;
- case ALIEN_TYPE:
- case DLL_TYPE:
- return CELLS * 2;
- /* everything else consists entirely of pointers */
- default:
- return unaligned_object_size(pointer);
- }
-}
-
void primitive_data_room(void)
{
F_ARRAY *a = array(ARRAY_TYPE,gen_count,F);
return RETAG(copy_object_impl(pointer),tag);
}
-INLINE void collect_object(CELL scan)
+/* The number of cells from the start of the object which should be scanned by
+the GC. Some types have a binary payload at the end (string, word, DLL) which
+we ignore. */
+CELL binary_payload_start(CELL pointer)
+{
+ switch(untag_header(get(pointer)))
+ {
+ /* these objects do not refer to other objects at all */
+ case STRING_TYPE:
+ case FLOAT_TYPE:
+ case BYTE_ARRAY_TYPE:
+ case BIGNUM_TYPE:
+ return 0;
+ /* these objects have some binary data at the end */
+ case WORD_TYPE:
+ return sizeof(F_WORD) - CELLS;
+ case ALIEN_TYPE:
+ case DLL_TYPE:
+ return CELLS * 2;
+ /* everything else consists entirely of pointers */
+ default:
+ return unaligned_object_size(pointer);
+ }
+}
+
+/* Every object has a regular representation in the runtime, which makes GC
+much simpler. Every slot of the object until binary_payload_start is a pointer
+to some other object. */
+INLINE void collect_object(CELL start)
{
+ CELL scan = start;
CELL payload_start = binary_payload_start(scan);
CELL end = scan + payload_start;
copy_handle((CELL*)scan);
scan += CELLS;
}
+
+ /* It is odd to put this hook here, but this is the only special case
+ made for any type of object by the GC. If code GC is being performed,
+ compiled code blocks referenced by this word must be marked. */
+ if(collecting_code && object_type(start) == WORD_TYPE)
+ {
+ F_WORD *word = (F_WORD *)start;
+ if(word->compiledp != F)
+ recursive_mark(word->xt);
+ }
}
CELL collect_next(CELL scan)
fprintf(stderr,"*** %s GC (%ld minor, %ld cards)\n",
collecting_code ? "Code and data" : "Data",
minor_collections,cards_scanned);
+ fflush(stderr);
minor_collections = 0;
cards_scanned = 0;
}
CELL array;
} F_HASHTABLE;
+/* When a word is executed we jump to the value of the XT field. However this
+value is an unportable function pointer. Interpreted and primitive words will
+have their XT set to a value in the 'primitives' global (see primitives.c).
+Compiled words are marked as such and their XT, which point inside the code
+heap, are instead relocated on startup, and also considered a code GC root. */
typedef struct {
/* TAGGED header */
CELL header;
CELL def;
/* TAGGED property hash for library code */
CELL props;
+ /* TAGGED t or f, depending on if the word is compiled or not */
+ CELL compiledp;
/* UNTAGGED execution token: jump here to execute word */
CELL xt;
} F_WORD;
primitive_float_greatereq,
primitive_word,
primitive_update_xt,
- primitive_word_compiledp,
primitive_drop,
primitive_2drop,
primitive_3drop,
dpush(tag_object(hash));
}
-/* When a word is executed we jump to the value of the xt field. However this
- value is an unportable function pointer, so in the image we store a primitive
- number that indexes a list of xts. */
void update_xt(F_WORD* word)
{
+ word->compiledp = F;
word->xt = primitive_to_xt(to_fixnum(word->primitive));
}
word->primitive = tag_fixnum(0);
word->def = F;
word->props = F;
+ word->compiledp = F;
word->xt = (CELL)undefined;
dpush(tag_word(word));
}
update_xt(untag_word(dpop()));
}
-void primitive_word_compiledp(void)
-{
- F_WORD* word = untag_word(dpop());
- if(to_fixnum(word->primitive) != 1)
- box_boolean(false);
- else
- box_boolean(word->xt != (CELL)docol);
-}
-
void fixup_word(F_WORD* word)
{
/* If this is a compiled word, relocate the code pointer. Otherwise,
reset it based on the primitive number of the word. */
- if(code_relocation_base != 0
- && word->xt >= code_relocation_base
- && word->xt < code_relocation_base
- - compiling.base + compiling.limit)
+ if(word->compiledp != F)
code_fixup(&word->xt);
else
update_xt(word);
void update_xt(F_WORD* word);
void primitive_word(void);
void primitive_update_xt(void);
-void primitive_word_compiledp(void);
void fixup_word(F_WORD* word);
INLINE F_WRAPPER *untag_wrapper_fast(CELL tagged)