INLINE void _syx_memory_gc_mark (SyxOop object) { syx_varsize i; if (!SYX_IS_OBJECT (object) || SYX_OBJECT_IS_MARKED(object) || SYX_IS_NIL(syx_object_get_class (object))) return; SYX_OBJECT_IS_MARKED(object) = TRUE; _syx_memory_gc_mark (SYX_OBJECT(object)->klass); /* Only the used stack part of the process must be marked */ if (SYX_OOP_EQ (syx_object_get_class (object), syx_process_class)) { SyxOop stack = SYX_PROCESS_STACK (object); SyxInterpFrame *frame = SYX_OOP_CAST_POINTER (SYX_PROCESS_FRAME_POINTER (object)); syx_int32 offset = SYX_POINTERS_OFFSET (frame->stack, SYX_OBJECT_DATA (stack)); SYX_OBJECT_IS_MARKED(stack) = TRUE; /* First mark variables except the process stack */ for (i=0; i < SYX_VARS_PROCESS_STACK; i++) _syx_memory_gc_mark (SYX_OBJECT_VARS(object)[i]); /* Mark detached frames */ while (frame) { _syx_memory_gc_mark (frame->detached_frame); frame = frame->parent_frame; } /* Now mark the stack */ for (i=0; i < offset; i++) _syx_memory_gc_mark (SYX_OBJECT_DATA(stack)[i]); /* Mark variables after the process stack */ for (i=SYX_VARS_PROCESS_STACK+1; i < syx_object_vars_size (object); i++) _syx_memory_gc_mark (SYX_OBJECT_VARS(object)[i]); /* Process has no data */ return; } else { for (i=0; i < syx_object_vars_size (object); i++) _syx_memory_gc_mark (SYX_OBJECT_VARS(object)[i]); } if (SYX_OBJECT_HAS_REFS (object)) { for (i=0; i < SYX_OBJECT_DATA_SIZE (object); i++) _syx_memory_gc_mark (SYX_OBJECT_DATA(object)[i]); } }
/*! Enters a new MethodContext or BlockContext. \return FALSE if the context was syx_nil */ syx_bool syx_interp_enter_context (SyxOop process, SyxOop context) { SyxOop arguments; syx_bool reset_parent_frame = FALSE; SyxInterpState _state = SYX_INTERP_STATE_NEW; SyxInterpState *state; SyxInterpFrame *frame; if (SYX_IS_NIL (process) || SYX_IS_NIL (context)) return FALSE; if (SYX_OOP_EQ (process, _syx_interp_state.process)) state = &_syx_interp_state; else { state = &_state; frame = SYX_OOP_CAST_POINTER (SYX_PROCESS_FRAME_POINTER (process)); /* This is a new Process, reset the parent_frame once we created the frame */ if (SYX_IS_NIL (frame->method)) reset_parent_frame = TRUE; state->frame = frame; state->process = process; } arguments = SYX_CONTEXT_PART_ARGUMENTS (context); if (SYX_IS_NIL (arguments)) state->message_arguments_count = 0; else { state->message_arguments_count = SYX_OBJECT_DATA_SIZE (arguments); memcpy (state->message_arguments, SYX_OBJECT_DATA (arguments), state->message_arguments_count * sizeof (SyxOop)); } if (SYX_OOP_EQ (syx_object_get_class (context), syx_block_context_class)) _syx_interp_frame_prepare_new_closure (state, SYX_BLOCK_CONTEXT_CLOSURE (context)); else { state->message_receiver = SYX_METHOD_CONTEXT_RECEIVER (context); _syx_interp_frame_prepare_new (state, SYX_CONTEXT_PART_METHOD (context)); } if (reset_parent_frame) state->frame->stack_return_frame = state->frame->parent_frame = NULL; state->frame->this_context = context; SYX_CONTEXT_PART_FRAME_POINTER (context) = SYX_POINTER_CAST_OOP (state->frame); _syx_interp_save_process_state (state); return TRUE; }
/* Fetches and updates the execution state of the interpreter to be ready for next instructions */ static void _syx_interp_state_update (SyxInterpState *state, SyxInterpFrame *frame) { SyxOop bytecodes; SyxOop method = frame->method;; state->frame = frame; bytecodes = SYX_CODE_BYTECODES (method); state->arguments = &frame->local; state->temporaries = state->arguments + SYX_SMALL_INTEGER (SYX_CODE_ARGUMENTS_COUNT (method)); state->method_literals = SYX_OBJECT_DATA (SYX_CODE_LITERALS (method)); state->method_bytecodes = (syx_uint16 *)SYX_OBJECT_DATA (bytecodes); state->method_bytecodes_count = SYX_OBJECT_DATA_SIZE (bytecodes); }
/* Dump a single frame */ static void _syx_memory_write_frame (SyxObject *process, SyxInterpFrame *frame, SyxInterpFrame *upper_frame, FILE *image) { syx_int32 data; SyxInterpFrame *bottom_frame; if (!process) bottom_frame = NULL; else bottom_frame = (SyxInterpFrame *)SYX_OBJECT_DATA (process->vars[SYX_VARS_PROCESS_STACK]); _syx_memory_write (&frame->this_context, FALSE, 1, image); _syx_memory_write (&frame->detached_frame, FALSE, 1, image); _syx_memory_write_lazy_pointer (process, frame->parent_frame, image); _syx_memory_write_lazy_pointer (process, frame->outer_frame, image); _syx_memory_write_lazy_pointer (process, frame->stack_return_frame, image); _syx_memory_write (&frame->method, FALSE, 1, image); _syx_memory_write (&frame->closure, FALSE, 1, image); /* this is not a SmallInteger */ data = SYX_COMPAT_SWAP_32 (frame->next_instruction); fwrite (&data, sizeof (syx_int32), 1, image); /* the stack pointer should point inside the process stack itself */ if (process) _syx_memory_write (&process->vars[SYX_VARS_PROCESS_STACK], FALSE, 1, image); else { data = SYX_COMPAT_SWAP_32 (0); fwrite (&data, sizeof (syx_int32), 1, image); } data = SYX_COMPAT_SWAP_32 (SYX_POINTERS_OFFSET (frame->stack, bottom_frame)); fwrite (&data, sizeof (syx_int32), 1, image); _syx_memory_write (&frame->receiver, TRUE, 1, image); /* Store arguments, temporaries and local stack. Only copy arguments and temporaries for detached frames without following the stack pointer */ if (SYX_IS_NIL (frame->detached_frame)) { /* if no upper_frame is given, this frame is the top most frame of the process stack */ if (!upper_frame) data = SYX_POINTERS_OFFSET (frame->stack, &frame->local); else data = SYX_POINTERS_OFFSET (upper_frame, &frame->local); } else data = SYX_OBJECT_DATA_SIZE (frame->detached_frame) - SYX_POINTERS_OFFSET (&frame->local, frame); data = SYX_COMPAT_SWAP_32 (data); fwrite (&data, sizeof (syx_int32), 1, image); _syx_memory_write (&frame->local, TRUE, SYX_COMPAT_SWAP_32 (data), image); }
INLINE void _syx_memory_gc_mark (SyxOop object) { syx_varsize i; if (!SYX_IS_OBJECT (object) || SYX_OBJECT_IS_MARKED(object) || SYX_IS_NIL(syx_object_get_class (object))) return; SYX_OBJECT_IS_MARKED(object) = TRUE; _syx_memory_gc_mark (SYX_OBJECT(object)->klass); for (i=0; i < syx_object_vars_size (object); i++) _syx_memory_gc_mark (SYX_OBJECT_VARS(object)[i]); if (SYX_OBJECT_HAS_REFS (object)) { for (i=0; i < SYX_OBJECT_DATA_SIZE (object); i++) _syx_memory_gc_mark (SYX_OBJECT_DATA(object)[i]); } }
static syx_bool _syx_cold_parse_class (SyxLexer *lexer) { SyxToken token = syx_lexer_get_last_token (lexer); SyxOop superclass, subclass; syx_string subclass_name; syx_bool existing_class = TRUE; SyxOop inst_vars, class_vars; SyxLexer *inst_vars_lexer, *class_vars_lexer; syx_varsize super_inst_vars_size; syx_int32 i; if (token.type != SYX_TOKEN_NAME_CONST) { syx_error ("Expected a name constant\n"); syx_token_free (token); return FALSE; } if (!strcmp (token.value.string, "nil")) superclass = syx_nil; else superclass = syx_globals_at (token.value.string); token = syx_lexer_next_token (lexer); if (!(token.type == SYX_TOKEN_NAME_COLON && !strcmp (token.value.string, "subclass:"))) { syx_token_free (token); syx_error ("Expected #subclass:\n"); return FALSE; } syx_token_free (token); token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_SYM_CONST) { syx_token_free (token); syx_error ("Expected a symbol constant\n"); return FALSE; } subclass_name = syx_strdup (token.value.string); syx_token_free (token); subclass = syx_globals_at_if_absent (subclass_name, syx_nil); if (strcmp (subclass_name, "Object")) { if (SYX_IS_NIL (subclass)) existing_class = FALSE; else { existing_class = TRUE; if (SYX_OOP_NE (SYX_CLASS_SUPERCLASS(subclass), superclass)) { syx_array_remove (SYX_CLASS_SUBCLASSES (SYX_CLASS_SUPERCLASS (subclass)), subclass); SYX_CLASS_SUPERCLASS(subclass) = superclass; syx_array_add (SYX_CLASS_SUBCLASSES (superclass), subclass, TRUE); syx_array_remove (SYX_CLASS_SUBCLASSES (SYX_CLASS_SUPERCLASS(syx_object_get_class (subclass))), syx_object_get_class (subclass)); SYX_CLASS_SUPERCLASS(syx_object_get_class (subclass)) = syx_object_get_class (superclass); syx_array_add (SYX_CLASS_SUBCLASSES (syx_object_get_class (superclass)), syx_object_get_class (subclass), TRUE); } } } token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_NAME_COLON) { syx_token_free (token); syx_error ("Expected #instanceVariableNames:\n"); return FALSE; } syx_token_free (token); token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_STR_CONST) { syx_token_free (token); syx_error ("Expected a string as argument for #instanceVariableNames:\n"); return FALSE; } inst_vars_lexer = syx_lexer_new (token.value.string); token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_NAME_COLON) { syx_token_free (token); syx_error ("Expected #classVariableNames:\n"); return FALSE; } syx_token_free (token); token = syx_lexer_next_token (lexer); if (token.type != SYX_TOKEN_STR_CONST) { syx_token_free (token); syx_error ("Expected a string as argument for #classVariableNames:\n"); return FALSE; } class_vars_lexer = syx_lexer_new (token.value.string); token = syx_lexer_next_token (lexer); if (!_IS_EXL_MARK (token)) { syx_token_free (token); syx_error ("Class definition must terminate with an exlamation mark\n"); return FALSE; } syx_token_free (token); if (!existing_class) { subclass = syx_class_new (superclass); SYX_CLASS_NAME(subclass) = syx_symbol_new (subclass_name); syx_globals_at_put (SYX_CLASS_NAME(subclass), subclass); } syx_free (subclass_name); /* Parse instance variables */ inst_vars = _syx_cold_parse_vars (inst_vars_lexer, FALSE); syx_lexer_free (inst_vars_lexer, TRUE); /* Fetch superclass instanceSize */ if (SYX_IS_NIL (superclass)) super_inst_vars_size = 0; else super_inst_vars_size = SYX_SMALL_INTEGER (SYX_CLASS_INSTANCE_SIZE (superclass)); SYX_CLASS_INSTANCE_VARIABLES(subclass) = inst_vars; SYX_CLASS_INSTANCE_SIZE(subclass) = syx_small_integer_new (super_inst_vars_size + SYX_OBJECT_DATA_SIZE (inst_vars)); /* Now parse class variables */ class_vars = _syx_cold_parse_vars (class_vars_lexer, TRUE); syx_lexer_free (class_vars_lexer, TRUE); SYX_CLASS_CLASS_VARIABLES(subclass) = syx_dictionary_new (SYX_OBJECT_DATA_SIZE (class_vars) + 10); /* translate from array to dictionary */ for (i=0; i < SYX_OBJECT_DATA_SIZE(class_vars); i++) syx_dictionary_at_symbol_put (SYX_CLASS_CLASS_VARIABLES(subclass), SYX_OBJECT_DATA(class_vars)[i], syx_nil); /* get rid of this */ syx_object_free (class_vars); return TRUE; }