<commit_before>/***********************************************************************
**
**  REBOL [R3] Language Interpreter and Run-time Environment
**
**  Copyright 2012 REBOL Technologies
**  REBOL is a trademark of REBOL Technologies
**
**  Licensed under the Apache License, Version 2.0 (the "License");
**  you may not use this file except in compliance with the License.
**  You may obtain a copy of the License at
**
**  http://www.apache.org/licenses/LICENSE-2.0
**
**  Unless required by applicable law or agreed to in writing, software
**  distributed under the License is distributed on an "AS IS" BASIS,
**  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
**  See the License for the specific language governing permissions and
**  limitations under the License.
**
************************************************************************
**
**  Module:  m-gc.c
**  Summary: main memory garbage collection
**  Section: memory
**  Author:  <NAME>, <NAME>, HostileFork
**  Notes:
**    WARNING WARNING WARNING
**    This is highly tuned code that should only be modified by experts
**    who fully understand its design. It is very easy to create odd
**    side effects so please be careful and extensively test all changes!
**
**	  The process consists of two stages:
**
**		MARK -	Mark all series and gobs ("collectible values")
*				that can be found in:
**
**				Root Block: special structures and buffers
**				Task Block: special structures and buffers per task
**				Data Stack: current state of evaluation
**				Safe Series: saves the last N allocations
**
**				Mark is recursive until we reach the terminals, or
**				until we hit values already marked.
**
**		SWEEP - Free all collectible values that were not marked.
**
**	  GC protection methods:
**
**		KEEP flag - protects an individual series from GC, but
**			does not protect its contents (if it holds values).
**			Reserved for non-block system series.
**
**		Root_Context - protects all series listed. This list is
**			used by Sweep as the root of the in-use memory tree.
**			Reserved for important system series only.
**
**		Task_Context - protects all series listed. This list is
**			the same as Root, but per the current task context.
**
**		Save_Series - protects temporary series. Used with the
**			SAVE_SERIES and UNSAVE_SERIES macros. Throws and errors
**			must roll back this series to avoid "stuck" memory.
**
**		Safe_Series - protects last MAX_SAFE_SERIES series from GC.
**			Can only be used if no deeply allocating functions are
**			called within the scope of its protection. Not affected
**			by throws and errors.
**
**		Data_Stack - all values in the data stack that are below
**			the TOP (DSP) are automatically protected. This is a
**			common protection method used by native functions.
**
**		DISABLE_GC - macro that turns off GC. A quick way to avoid
**			GC, but must only be used for well-behaved sections
**			or could cause substantial memory growth.
**
**		DONE flag - do not scan the series; it has no links.
**
***********************************************************************/

#include "sys-core.h"
#include "reb-evtypes.h"

#ifdef REB_API
extern REBOL_HOST_LIB *Host_Lib;
#endif

//-- For Serious Debugging:
#ifdef WATCH_GC_VALUE
REBSER *Watcher = 0;
REBVAL *WatchVar = 0;
REBVAL *GC_Break_Point(REBVAL *val) {return val;}
REBVAL *N_watch(REBFRM *frame, REBVAL **inter_block)
{
	WatchVar = Get_Word(FRM_ARG1(frame));
	Watcher = VAL_SERIES(WatchVar);
	SET_INTEGER(FRM_ARG1(frame), 0);
	return Nothing;
}
#endif

// This can be put below
#ifdef WATCH_GC_VALUE
			if (Watcher && ser == Watcher)
				GC_Break_Point(val);

		// for (n = 0; n < depth * 2; n++) Prin_Str(" ");
		// Mark_Count++;
		// Print("Mark: %s %x", TYPE_NAME(val), val);
#endif

static void Mark_Series(REBSER *series, REBCNT depth);
static void Mark_Value(REBVAL *val, REBCNT depth);

/***********************************************************************
**
*/	static void Mark_Gob(REBGOB *gob, REBCNT depth)
/*
***********************************************************************/
{
	REBGOB **pane;
	REBCNT i;

	if (IS_GOB_MARK(gob)) return;

	MARK_GOB(gob);

	if (GOB_PANE(gob)) {
		MARK_SERIES(GOB_PANE(gob));
		pane = GOB_HEAD(gob);
		for (i = 0; i < GOB_TAIL(gob); i++, pane++) {
			Mark_Gob(*pane, depth);
		}
	}

	if (GOB_PARENT(gob)) Mark_Gob(GOB_PARENT(gob), depth);

	if (GOB_CONTENT(gob)) {
		if (GOB_TYPE(gob) >= GOBT_IMAGE && GOB_TYPE(gob) <= GOBT_STRING) {
			MARK_SERIES(GOB_CONTENT(gob));
		} else if (GOB_TYPE(gob) >= GOBT_DRAW && GOB_TYPE(gob) <= GOBT_EFFECT) {
			CHECK_MARK(GOB_CONTENT(gob), depth);
		}
	}

	if (GOB_DATA(gob) && GOB_DTYPE(gob) && GOB_DTYPE(gob) != GOBD_INTEGER) {
		CHECK_MARK(GOB_DATA(gob), depth);
	}
}

/***********************************************************************
**
*/	static void Mark_Struct_Field(REBSTU *stu, struct Struct_Field *field, REBCNT depth)
/*
***********************************************************************/
{
	if (field->type == STRUCT_TYPE_STRUCT) {
		int len = 0;
		REBSER *series = NULL;

		CHECK_MARK(field->fields, depth);
		CHECK_MARK(field->spec, depth);

		series = field->fields;
		for (len = 0; len < series->tail; len++) {
			Mark_Struct_Field (stu, (struct Struct_Field*)BLK_SKIP(series, len), depth + 1);
		}
	} else if (field->type == STRUCT_TYPE_REBVAL) {
		REBCNT i;
		for (i = 0; i < field->dimension; i ++) {
			REBVAL *data = (REBVAL*)SERIES_SKIP(STRUCT_DATA_BIN(stu),
												STRUCT_OFFSET(stu) + field->offset + i * field->size);
			Mark_Value(data, depth);
		}
	}

	/* ignore primitive datatypes */
}

/***********************************************************************
**
*/	static void Mark_Struct(REBSTU *stu, REBCNT depth)
/*
***********************************************************************/
{
	int len = 0;
	REBSER *series = NULL;
	CHECK_MARK(stu->spec, depth);
	CHECK_MARK(stu->fields, depth);
	CHECK_MARK(STRUCT_DATA_BIN(stu), depth);
	CHECK_MARK(stu->data, depth);

	series = stu->fields;
	for (len = 0; len < series->tail; len++) {
		struct Struct_Field *field = (struct Struct_Field*)BLK_SKIP(series, len);
		Mark_Struct_Field(stu, field, depth + 1);
	}
}

/***********************************************************************
**
*/	static void Mark_Routine(REBROT *rot, REBCNT depth)
/*
***********************************************************************/
{
	int len = 0;
	REBSER *series = NULL;
	CHECK_MARK(ROUTINE_SPEC(rot), depth);
	MARK_ROUTINE(ROUTINE_INFO(rot));

	CHECK_MARK(ROUTINE_FFI_ARGS(rot), depth);
	CHECK_MARK(ROUTINE_FFI_ARG_STRUCTS(rot), depth);
	CHECK_MARK(ROUTINE_EXTRA_MEM(rot), depth);

	if (IS_CALLBACK_ROUTINE(ROUTINE_INFO(rot))) {<commit_msg>Fix a typo that causes struct->fields corruption<commit_after>/***********************************************************************
**
**  REBOL [R3] Language Interpreter and Run-time Environment
**
**  Copyright 2012 REBOL Technologies
**  REBOL is a trademark of REBOL Technologies
**
**  Licensed under the Apache License, Version 2.0 (the "License");
**  you may not use this file except in compliance with the License.
**  You may obtain a copy of the License at
**
**  http://www.apache.org/licenses/LICENSE-2.0
**
**  Unless required by applicable law or agreed to in writing, software
**  distributed under the License is distributed on an "AS IS" BASIS,
**  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
**  See the License for the specific language governing permissions and
**  limitations under the License.
**
************************************************************************
**
**  Module:  m-gc.c
**  Summary: main memory garbage collection
**  Section: memory
**  Author:  <NAME>, <NAME>, HostileFork
**  Notes:
**    WARNING WARNING WARNING
**    This is highly tuned code that should only be modified by experts
**    who fully understand its design. It is very easy to create odd
**    side effects so please be careful and extensively test all changes!
**
**	  The process consists of two stages:
**
**		MARK -	Mark all series and gobs ("collectible values")
*				that can be found in:
**
**				Root Block: special structures and buffers
**				Task Block: special structures and buffers per task
**				Data Stack: current state of evaluation
**				Safe Series: saves the last N allocations
**
**				Mark is recursive until we reach the terminals, or
**				until we hit values already marked.
**
**		SWEEP - Free all collectible values that were not marked.
**
**	  GC protection methods:
**
**		KEEP flag - protects an individual series from GC, but
**			does not protect its contents (if it holds values).
**			Reserved for non-block system series.
**
**		Root_Context - protects all series listed. This list is
**			used by Sweep as the root of the in-use memory tree.
**			Reserved for important system series only.
**
**		Task_Context - protects all series listed. This list is
**			the same as Root, but per the current task context.
**
**		Save_Series - protects temporary series. Used with the
**			SAVE_SERIES and UNSAVE_SERIES macros. Throws and errors
**			must roll back this series to avoid "stuck" memory.
**
**		Safe_Series - protects last MAX_SAFE_SERIES series from GC.
**			Can only be used if no deeply allocating functions are
**			called within the scope of its protection. Not affected
**			by throws and errors.
**
**		Data_Stack - all values in the data stack that are below
**			the TOP (DSP) are automatically protected. This is a
**			common protection method used by native functions.
**
**		DISABLE_GC - macro that turns off GC. A quick way to avoid
**			GC, but must only be used for well-behaved sections
**			or could cause substantial memory growth.
**
**		DONE flag - do not scan the series; it has no links.
**
***********************************************************************/

#include "sys-core.h"
#include "reb-evtypes.h"

#ifdef REB_API
extern REBOL_HOST_LIB *Host_Lib;
#endif

//-- For Serious Debugging:
#ifdef WATCH_GC_VALUE
REBSER *Watcher = 0;
REBVAL *WatchVar = 0;
REBVAL *GC_Break_Point(REBVAL *val) {return val;}
REBVAL *N_watch(REBFRM *frame, REBVAL **inter_block)
{
	WatchVar = Get_Word(FRM_ARG1(frame));
	Watcher = VAL_SERIES(WatchVar);
	SET_INTEGER(FRM_ARG1(frame), 0);
	return Nothing;
}
#endif

// This can be put below
#ifdef WATCH_GC_VALUE
			if (Watcher && ser == Watcher)
				GC_Break_Point(val);

		// for (n = 0; n < depth * 2; n++) Prin_Str(" ");
		// Mark_Count++;
		// Print("Mark: %s %x", TYPE_NAME(val), val);
#endif

static void Mark_Series(REBSER *series, REBCNT depth);
static void Mark_Value(REBVAL *val, REBCNT depth);

/***********************************************************************
**
*/	static void Mark_Gob(REBGOB *gob, REBCNT depth)
/*
***********************************************************************/
{
	REBGOB **pane;
	REBCNT i;

	if (IS_GOB_MARK(gob)) return;

	MARK_GOB(gob);

	if (GOB_PANE(gob)) {
		MARK_SERIES(GOB_PANE(gob));
		pane = GOB_HEAD(gob);
		for (i = 0; i < GOB_TAIL(gob); i++, pane++) {
			Mark_Gob(*pane, depth);
		}
	}

	if (GOB_PARENT(gob)) Mark_Gob(GOB_PARENT(gob), depth);

	if (GOB_CONTENT(gob)) {
		if (GOB_TYPE(gob) >= GOBT_IMAGE && GOB_TYPE(gob) <= GOBT_STRING) {
			MARK_SERIES(GOB_CONTENT(gob));
		} else if (GOB_TYPE(gob) >= GOBT_DRAW && GOB_TYPE(gob) <= GOBT_EFFECT) {
			CHECK_MARK(GOB_CONTENT(gob), depth);
		}
	}

	if (GOB_DATA(gob) && GOB_DTYPE(gob) && GOB_DTYPE(gob) != GOBD_INTEGER) {
		CHECK_MARK(GOB_DATA(gob), depth);
	}
}

/***********************************************************************
**
*/	static void Mark_Struct_Field(REBSTU *stu, struct Struct_Field *field, REBCNT depth)
/*
***********************************************************************/
{
	if (field->type == STRUCT_TYPE_STRUCT) {
		int len = 0;
		REBSER *series = NULL;

		CHECK_MARK(field->fields, depth);
		CHECK_MARK(field->spec, depth);

		series = field->fields;
		for (len = 0; len < series->tail; len++) {
			Mark_Struct_Field (stu, (struct Struct_Field*)SERIES_SKIP(series, len), depth + 1);
		}
	} else if (field->type == STRUCT_TYPE_REBVAL) {
		REBCNT i;
		for (i = 0; i < field->dimension; i ++) {
			REBVAL *data = (REBVAL*)SERIES_SKIP(STRUCT_DATA_BIN(stu),
												STRUCT_OFFSET(stu) + field->offset + i * field->size);
			Mark_Value(data, depth);
		}
	}

	/* ignore primitive datatypes */
}

/***********************************************************************
**
*/	static void Mark_Struct(REBSTU *stu, REBCNT depth)
/*
***********************************************************************/
{
	int len = 0;
	REBSER *series = NULL;
	CHECK_MARK(stu->spec, depth);
	CHECK_MARK(stu->fields, depth);
	CHECK_MARK(STRUCT_DATA_BIN(stu), depth);
	CHECK_MARK(stu->data, depth);

	series = stu->fields;
	for (len = 0; len < series->tail; len++) {
		struct Struct_Field *field = (struct Struct_Field*)SERIES_SKIP(series, len);
		Mark_Struct_Field(stu, field, depth + 1);
	}
}

/***********************************************************************
**
*/	static void Mark_Routine(REBROT *rot, REBCNT depth)
/*
***********************************************************************/
{
	int len = 0;
	REBSER *series = NULL;
	CHECK_MARK(ROUTINE_SPEC(rot), depth);
	MARK_ROUTINE(ROUTINE_INFO(rot));

	CHECK_MARK(ROUTINE_FFI_ARGS(rot), depth);
	CHECK_MARK(ROUTINE_FFI_ARG_STRUCTS(rot), depth);
	CHECK_MARK(ROUTINE_EXTRA_MEM(rot), depth);

	if (IS_CALLBACK_ROUTINE(ROUTINE_INFO(rot))) {
{'fraction_non_alphanumeric': 0.22800385442146617, 'fraction_numerical': 0.0037061744866948338, 'mean_word_length': 4.66890756302521, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3659162', 'n_tokens_mistral': 4674, 'n_tokens_neox': 4367, 'n_words': 1326}