-- Event Logging Common Definitions
*
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* $Id$
*
* .sources: mps.design.telemetry
@@ -56,7 +56,8 @@ ENUM_DECLARE(EventKind)
enum EventDefinitionsEnum {
EVENT_LIST(EVENT_ENUM, X)
- EventEnumWarningSuppressor /* suppress comma-at-end-of-enum warning */
+ /* suppress comma-at-end-of-enum warning */
+ EventEnumWarningSuppressor = USHRT_MAX
};
@@ -89,7 +90,11 @@ typedef Word EventFW; /* word */
typedef unsigned EventFU; /* unsigned integer */
typedef char EventFS[EventStringLengthMAX + sizeof('\0')]; /* string */
typedef double EventFD; /* double */
-typedef int EventFB; /* boolean */
+/* EventFB must be unsigned (even though Bool is a typedef for int)
+ * because it used as the type of a bitfield with width 1, and we need
+ * the legals values of the field to be 0 and 1 (not 0 and -1 which
+ * would be the case for int : 1). */
+typedef unsigned EventFB; /* Boolean */
/* Event packing bitfield specifiers */
#define EventFP_BITFIELD
@@ -133,7 +138,7 @@ typedef union EventUnion {
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/eventsql.c b/mps/code/eventsql.c
index 46bfa688a9b..e1c9ea22381 100644
--- a/mps/code/eventsql.c
+++ b/mps/code/eventsql.c
@@ -102,7 +102,7 @@ typedef sqlite3_int64 int64;
* and for reporting errors.
*/
-unsigned int verbosity = 0;
+static unsigned int verbosity = 0;
#define LOG_ALWAYS 0
#define LOG_OFTEN 1
@@ -533,7 +533,7 @@ static void logFileCompleted(sqlite3 *db,
/* An array of table-creation statement strings. */
-const char *createStatements[] = {
+static const char *createStatements[] = {
"CREATE TABLE IF NOT EXISTS event_kind (name TEXT,"
" description TEXT,"
" enum INTEGER PRIMARY KEY)",
@@ -571,7 +571,7 @@ static void makeTables(sqlite3 *db)
}
}
-const char *glueTables[] = {
+static const char *glueTables[] = {
"event_kind",
"event_type",
"event_param",
diff --git a/mps/code/eventtxt.c b/mps/code/eventtxt.c
index 5b7f7ab1312..4c50ac994f9 100644
--- a/mps/code/eventtxt.c
+++ b/mps/code/eventtxt.c
@@ -29,15 +29,20 @@
* $Id$
*/
+#include "mps.h"
+#include "mpsavm.h"
+#include "mpscmvff.h"
+#include "check.h"
#include "config.h"
#include "eventdef.h"
#include "eventcom.h"
#include "table.h"
#include "testlib.h" /* for ulongest_t and associated print formats */
+#include
#include
-#include
-#include
+#include /* exit, EXIT_FAILURE, EXIT_SUCCESS */
+#include /* strcpy, strlen */
static const char *prog; /* program name */
static const char *logFileName = NULL;
@@ -106,15 +111,19 @@ static void parseArgs(int argc, char *argv[])
static void *tableAlloc(void *closure, size_t size)
{
- UNUSED(closure);
- return malloc(size);
+ mps_pool_t pool = closure;
+ mps_addr_t p;
+ mps_res_t res;
+ res = mps_alloc(&p, pool, size);
+ if (res != MPS_RES_OK)
+ everror("allocation failed: %d", res);
+ return p;
}
static void tableFree(void *closure, void *p, size_t size)
{
- UNUSED(closure);
- UNUSED(size);
- free(p);
+ mps_pool_t pool = closure;
+ mps_free(pool, p, size);
}
/* Printing routines */
@@ -171,7 +180,7 @@ static double parseDouble(char **pInOut)
#define MAX_STRING_LENGTH 1024
-char strBuf[MAX_STRING_LENGTH];
+static char strBuf[MAX_STRING_LENGTH];
static char *parseString(char **pInOut)
{
@@ -215,21 +224,21 @@ static Table internTable; /* dictionary of intern ids to strings */
static Table labelTable; /* dictionary of addrs to intern ids */
-static void createTables(void)
+static void createTables(mps_pool_t pool)
{
Res res;
/* MPS intern IDs are serials from zero up, so we can use -1
* and -2 as specials. */
res = TableCreate(&internTable,
(size_t)1<<4,
- tableAlloc, tableFree, NULL,
+ tableAlloc, tableFree, pool,
(Word)-1, (Word)-2);
if (res != ResOK)
everror("Couldn't make intern table.");
/* We assume that 0 and 1 are invalid as Addrs. */
res = TableCreate(&labelTable, (size_t)1<<7,
- tableAlloc, tableFree, NULL,
+ tableAlloc, tableFree, pool,
0, 1);
if (res != ResOK)
everror("Couldn't make label table.");
@@ -238,19 +247,19 @@ static void createTables(void)
/* recordIntern -- record an interned string in the table. a copy of
* the string from the parsed buffer into a newly-allocated block. */
-static void recordIntern(char *p)
+static void recordIntern(mps_pool_t pool, char *p)
{
ulongest_t stringId;
char *string;
- char *copy;
+ mps_addr_t copy;
size_t len;
Res res;
stringId = parseHex(&p);
string = parseString(&p);
len = strlen(string);
- copy = malloc(len+1);
- if (copy == NULL)
+ res = mps_alloc(©, pool, len + 1);
+ if (res != MPS_RES_OK)
everror("Couldn't allocate space for a string.");
(void)strcpy(copy, string);
res = TableDefine(internTable, (Word)stringId, (void *)copy);
@@ -258,12 +267,55 @@ static void recordIntern(char *p)
everror("Couldn't create an intern mapping.");
}
-/* recordLabel records a label (an association between an address and
- * a string ID). Note that the event log may have been generated on a
- * platform with addresses larger than Word on the current platform.
- * If that happens then we are scuppered because our Table code uses
- * Word as the key type: there's nothing we can do except detect this
- * bad case (see also the EventInit handling and warning code).
+/* Over time there may be multiple labels associated with an address,
+ * so we keep a list, recording for each label the clock when the
+ * association was made. This means that printAddr can select the
+ * label that was in force at the time of the event.
+ */
+
+typedef struct LabelStruct *Label;
+typedef struct LabelStruct {
+ ulongest_t clock; /* clock of this label */
+ ulongest_t id; /* string id of this label */
+} LabelStruct;
+
+typedef struct LabelListStruct *LabelList;
+typedef struct LabelListStruct {
+ size_t n; /* number of labels in array */
+ Label labels; /* labels, sorted in order by clock */
+} LabelListStruct;
+
+/* labelFind returns the index of the first entry in list with a clock
+ * value that's greater than 'clock', or list->n if there is no such
+ * label. The list is assumed to be sorted.
+ */
+
+static size_t labelFind(LabelList list, ulongest_t clock)
+{
+ size_t low = 0, high = list->n;
+ while (low < high) {
+ size_t mid = (low + high) / 2;
+ assert(NONNEGATIVE(mid) && mid < list->n);
+ if (list->labels[mid].clock > clock) {
+ high = mid;
+ } else {
+ low = mid + 1;
+ }
+ }
+ assert(NONNEGATIVE(low) && low <= list->n);
+ assert(low == list->n || list->labels[low].clock > clock);
+ return low;
+}
+
+/* recordLabel records a label: an association (made at the time given
+ * by 'clock') between an address and a string ID. These are encoded
+ * as two hexadecimal numbers in the string pointed to by 'p'.
+ *
+ * Note that the event log may have been generated on a platform with
+ * addresses larger than Word on the current platform. If that happens
+ * then we are scuppered because our Table code uses Word as the key
+ * type: there's nothing we can do except detect this bad case (see
+ * also the EventInit handling and warning code).
*
* We can and do handle the case where string IDs (which are Words on
* the MPS platform) are larger than void* on the current platform.
@@ -274,25 +326,50 @@ static void recordIntern(char *p)
* probably a bad idea and maybe doomed to failure.
*/
-static void recordLabel(char *p)
+static void recordLabel(mps_pool_t pool, ulongest_t clock, char *p)
{
ulongest_t address;
- ulongest_t *stringIdP;
+ LabelList list;
+ Label newlabels;
+ mps_addr_t tmp;
+ size_t pos;
Res res;
-
+
address = parseHex(&p);
if (address > (Word)-1) {
(void)printf("label address too large!");
return;
}
-
- stringIdP = malloc(sizeof(ulongest_t));
- if (stringIdP == NULL)
- everror("Can't allocate space for a string's ID");
- *stringIdP = parseHex(&p);
- res = TableDefine(labelTable, (Word)address, (void *)stringIdP);
+
+ if (TableLookup(&tmp, labelTable, address)) {
+ list = tmp;
+ } else {
+ /* First label for this address */
+ res = mps_alloc(&tmp, pool, sizeof(LabelListStruct));
+ if (res != MPS_RES_OK)
+ everror("Can't allocate space for a label list");
+ list = tmp;
+ list->n = 0;
+ res = TableDefine(labelTable, (Word)address, list);
+ if (res != ResOK)
+ everror("Couldn't create a label mapping.");
+ }
+
+ res = mps_alloc(&tmp, pool, sizeof(LabelStruct) * (list->n + 1));
if (res != ResOK)
- everror("Couldn't create an intern mapping.");
+ everror("Couldn't allocate space for list of labels.");
+ newlabels = tmp;
+
+ pos = labelFind(list, clock);
+ memcpy(newlabels, list->labels, sizeof(LabelStruct) * pos);
+ newlabels[pos].clock = clock;
+ newlabels[pos].id = parseHex(&p);
+ memcpy(newlabels + pos + 1, list->labels + pos,
+ sizeof(LabelStruct) * (list->n - pos));
+ if (list->n > 0)
+ mps_free(pool, list->labels, sizeof(LabelStruct) * list->n);
+ list->labels = newlabels;
+ ++ list->n;
}
/* output code */
@@ -308,20 +385,23 @@ static int hexWordWidth = (MPS_WORD_WIDTH+3)/4;
/* printAddr -- output a ulongest_t in hex, with the interned string
* if the value is in the label table */
-static void printAddr(ulongest_t addr, const char *ident)
+static void printAddr(ulongest_t clock, ulongest_t addr, const char *ident)
{
- ulongest_t label;
- void *alias;
+ void *tmp;
printf("%s:%0*" PRIXLONGEST, ident, hexWordWidth, addr);
- if (TableLookup(&alias, labelTable, addr)) {
- label = *(ulongest_t*)alias;
- putchar('[');
- if (TableLookup(&alias, internTable, label))
- printStr((char *)alias);
- else
- printf("unknown label %" PRIuLONGEST, label);
- putchar(']');
+ if (TableLookup(&tmp, labelTable, addr)) {
+ LabelList list = tmp;
+ size_t pos = labelFind(list, clock);
+ if (pos > 0) {
+ ulongest_t id = list->labels[pos - 1].id;
+ putchar('[');
+ if (TableLookup(&tmp, internTable, id))
+ printStr((char *)tmp);
+ else
+ printf("unknown label %" PRIXLONGEST, id);
+ putchar(']');
+ }
}
putchar(' ');
}
@@ -332,7 +412,7 @@ static void printAddr(ulongest_t addr, const char *ident)
#define processParamA(ident) \
val_hex = parseHex(&p); \
- printAddr(val_hex, #ident);
+ printAddr(clock, val_hex, #ident);
#define processParamP processParamA
#define processParamW processParamA
@@ -375,7 +455,7 @@ static const char *eventName[EventCodeMAX+EventCodeMAX];
/* readLog -- read and parse log. Returns the number of events written. */
-static void readLog(FILE *input)
+static void readLog(mps_pool_t pool, FILE *input)
{
int i;
@@ -415,9 +495,9 @@ static void readLog(FILE *input)
/* for a few particular codes, we do local processing. */
if (code == EventInternCode) {
- recordIntern(q);
+ recordIntern(pool, q);
} else if (code == EventLabelCode) {
- recordLabel(q);
+ recordLabel(pool, clock, q);
} else if (code == EventEventInitCode) {
ulongest_t major, median, minor, maxCode, maxNameLen, wordWidth, clocksPerSec;
major = parseHex(&q); /* EVENT_VERSION_MAJOR */
@@ -476,6 +556,9 @@ static void readLog(FILE *input)
int main(int argc, char *argv[])
{
+ mps_arena_t arena;
+ mps_pool_t pool;
+ mps_res_t res;
FILE *input;
parseArgs(argc, argv);
@@ -488,8 +571,20 @@ int main(int argc, char *argv[])
everror("unable to open %s", logFileName);
}
- createTables();
- readLog(input);
+ res = mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none);
+ if (res != MPS_RES_OK)
+ everror("failed to create arena: %d", res);
+
+ res = mps_pool_create_k(&pool, arena, mps_class_mvff(), mps_args_none);
+ if (res != MPS_RES_OK)
+ everror("failed to create pool: %d", res);
+
+ createTables(pool);
+ readLog(pool, input);
+
+ mps_pool_destroy(pool);
+ mps_arena_destroy(arena);
+
(void)fclose(input);
return 0;
}
diff --git a/mps/code/exposet0.c b/mps/code/exposet0.c
index f471dd2a3bc..21f2567cbaa 100644
--- a/mps/code/exposet0.c
+++ b/mps/code/exposet0.c
@@ -72,12 +72,6 @@ static void report(mps_arena_t arena)
printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
mps_message_discard(arena, message);
-
- if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024)
- /* When condemned size is larger than could happen in a gen 2
- * collection (discounting ramps, natch), guess that was a dynamic
- * collection, and reset the commit limit, so it doesn't run out. */
- die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit");
}
}
diff --git a/mps/code/fbmtest.c b/mps/code/fbmtest.c
index 9f3754b3496..231d02482a7 100644
--- a/mps/code/fbmtest.c
+++ b/mps/code/fbmtest.c
@@ -560,7 +560,7 @@ extern int main(int argc, char *argv[])
Align align;
testlib_init(argc, argv);
- align = (1 << rnd() % 4) * MPS_PF_ALIGN;
+ align = sizeof(void *) << (rnd() % 4);
NAllocateTried = NAllocateSucceeded = NDeallocateTried =
NDeallocateSucceeded = 0;
diff --git a/mps/code/finaltest.c b/mps/code/finaltest.c
index 02c1448d137..f449d7e1acf 100644
--- a/mps/code/finaltest.c
+++ b/mps/code/finaltest.c
@@ -6,6 +6,20 @@
*
* DESIGN
*
+ * .mode: This test has two modes.
+ *
+ * .mode.park: In this mode, we use the arena's default generation
+ * chain, leave the arena parked and call mps_arena_collect. This
+ * tests that the default generation chain works and that all segments
+ * get condemned via TraceStartCollectAll. (See job003771 item 4.)
+ *
+ * .mode.poll: In this mode, we use our own generation chain (with
+ * small generations), allocate into generation 1, unclamp the arena,
+ * and provoke collection by allocating. This tests that custom
+ * generation chains work, and that segments get condemned via
+ * TracePoll even if there is no allocation into generation 0 of the
+ * chain. (See job003771 item 5.)
+ *
* DEPENDENCIES
*
* This test uses the dylan object format, but the reliance on this
@@ -16,6 +30,7 @@
* This code was created by first copying
*/
+#include "mpm.h"
#include "testlib.h"
#include "mpslib.h"
#include "mps.h"
@@ -30,10 +45,15 @@
#include /* fflush, printf, stdout */
+enum {
+ ModePARK, /* .mode.park */
+ ModePOLL /* .mode.poll */
+};
+
#define testArenaSIZE ((size_t)16<<20)
#define rootCOUNT 20
-#define maxtreeDEPTH 10
+#define maxtreeDEPTH 9
#define collectionCOUNT 10
@@ -126,17 +146,21 @@ static mps_addr_t test_awl_find_dependent(mps_addr_t addr)
static void *root[rootCOUNT];
-static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap,
+static void test_trees(int mode, const char *name, mps_arena_t arena,
+ mps_ap_t ap,
mps_word_t (*make)(mps_word_t, mps_ap_t),
void (*reg)(mps_word_t, mps_arena_t))
{
size_t collections = 0;
size_t finals = 0;
size_t i;
+ int object_alloc;
object_count = 0;
printf("Making some %s finalized trees of objects.\n", name);
+ mps_arena_park(arena);
+
/* make some trees */
for(i = 0; i < rootCOUNT; ++i) {
root[i] = (void *)(*make)(maxtreeDEPTH, ap);
@@ -151,10 +175,23 @@ static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap,
while (finals < object_count && collections < collectionCOUNT) {
mps_word_t final_this_time = 0;
- printf("Collecting...");
- (void)fflush(stdout);
- die(mps_arena_collect(arena), "collect");
- printf(" Done.\n");
+ switch (mode) {
+ default:
+ case ModePARK:
+ printf("Collecting...");
+ (void)fflush(stdout);
+ die(mps_arena_collect(arena), "collect");
+ printf(" Done.\n");
+ break;
+ case ModePOLL:
+ mps_arena_release(arena);
+ printf("Allocating...");
+ (void)fflush(stdout);
+ object_alloc = 0;
+ while (object_alloc < 1000 && !mps_message_poll(arena))
+ (void)DYLAN_INT(object_alloc++);
+ break;
+ }
++ collections;
while (mps_message_poll(arena)) {
mps_message_t message;
@@ -167,12 +204,17 @@ static void test_trees(const char *name, mps_arena_t arena, mps_ap_t ap,
}
finals += final_this_time;
printf("%"PRIuLONGEST" objects finalized: total %"PRIuLONGEST
- " of %"PRIuLONGEST"\n", final_this_time, finals, object_count);
+ " of %"PRIuLONGEST"\n", (ulongest_t)final_this_time,
+ (ulongest_t)finals, (ulongest_t)object_count);
}
- cdie(finals == object_count, "Not all objects were finalized.");
+ if (finals != object_count)
+ error("Not all objects were finalized for %s in mode %s.",
+ BufferOfAP(ap)->pool->class->name,
+ mode == ModePOLL ? "POLL" : "PARK");
}
-static void *test(mps_arena_t arena, mps_class_t pool_class)
+static void test_pool(int mode, mps_arena_t arena, mps_chain_t chain,
+ mps_class_t pool_class)
{
mps_ap_t ap;
mps_fmt_t fmt;
@@ -181,10 +223,13 @@ static void *test(mps_arena_t arena, mps_class_t pool_class)
die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n");
MPS_ARGS_BEGIN(args) {
- /* Allocate into generation 0 so that they get finalized quickly. */
- MPS_ARGS_ADD(args, MPS_KEY_GEN, 0);
MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt);
- MPS_ARGS_ADD(args, MPS_KEY_AWL_FIND_DEPENDENT, test_awl_find_dependent);
+ if (mode == ModePOLL) {
+ MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain);
+ MPS_ARGS_ADD(args, MPS_KEY_GEN, 1);
+ }
+ if (pool_class == mps_class_awl())
+ MPS_ARGS_ADD(args, MPS_KEY_AWL_FIND_DEPENDENT, test_awl_find_dependent);
die(mps_pool_create_k(&pool, arena, pool_class, args),
"pool_create\n");
} MPS_ARGS_END(args);
@@ -193,19 +238,25 @@ static void *test(mps_arena_t arena, mps_class_t pool_class)
"root_create\n");
die(mps_ap_create(&ap, pool, mps_rank_exact()), "ap_create\n");
- mps_message_type_enable(arena, mps_message_type_finalization());
-
- mps_arena_park(arena);
-
- test_trees("numbered", arena, ap, make_numbered_tree, register_numbered_tree);
- test_trees("indirect", arena, ap, make_indirect_tree, register_indirect_tree);
+ test_trees(mode, "numbered", arena, ap, make_numbered_tree,
+ register_numbered_tree);
+ test_trees(mode, "indirect", arena, ap, make_indirect_tree,
+ register_indirect_tree);
mps_ap_destroy(ap);
mps_root_destroy(mps_root);
mps_pool_destroy(pool);
mps_fmt_destroy(fmt);
+}
- return NULL;
+
+static void test_mode(int mode, mps_arena_t arena, mps_chain_t chain)
+{
+ test_pool(mode, arena, chain, mps_class_amc());
+ test_pool(mode, arena, chain, mps_class_amcz());
+ test_pool(mode, arena, chain, mps_class_ams());
+ /* test_pool(mode, arena, chain, mps_class_lo()); TODO: job003773 */
+ /* test_pool(mode, arena, chain, mps_class_awl()); TODO: job003772 */
}
@@ -213,19 +264,27 @@ int main(int argc, char *argv[])
{
mps_arena_t arena;
mps_thr_t thread;
+ mps_chain_t chain;
+ mps_gen_param_s params[2];
+ size_t gens = 2;
+ size_t i;
testlib_init(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
+ mps_message_type_enable(arena, mps_message_type_finalization());
die(mps_thread_reg(&thread, arena), "thread_reg\n");
+ for (i = 0; i < gens; ++i) {
+ params[i].mps_capacity = 1;
+ params[i].mps_mortality = 0.5;
+ }
+ die(mps_chain_create(&chain, arena, gens, params), "chain_create\n");
- test(arena, mps_class_amc());
- test(arena, mps_class_amcz());
- test(arena, mps_class_ams());
- test(arena, mps_class_awl());
- /* TODO: test(arena, mps_class_lo()); */
+ test_mode(ModePOLL, arena, chain);
+ test_mode(ModePARK, arena, NULL);
+ mps_chain_destroy(chain);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
diff --git a/mps/code/fmtscheme.c b/mps/code/fmtscheme.c
index 5299c8f3525..11900130a71 100644
--- a/mps/code/fmtscheme.c
+++ b/mps/code/fmtscheme.c
@@ -12,14 +12,8 @@
/* special objects */
-obj_t obj_empty; /* (), the empty list */
-obj_t obj_eof; /* end of file */
-obj_t obj_error; /* error indicator */
-obj_t obj_true; /* #t, boolean true */
-obj_t obj_false; /* #f, boolean false */
-obj_t obj_undefined; /* undefined result indicator */
-obj_t obj_tail; /* tail recursion indicator */
-obj_t obj_deleted; /* deleted key in hashtable */
+static obj_t obj_true; /* #t, boolean true */
+static obj_t obj_false; /* #f, boolean false */
/* MPS globals */
diff --git a/mps/code/fotest.c b/mps/code/fotest.c
index 9dab6650ede..2e63d4e121b 100644
--- a/mps/code/fotest.c
+++ b/mps/code/fotest.c
@@ -171,7 +171,7 @@ int main(int argc, char *argv[])
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
- alignment = (1 << (rnd() % 4)) * MPS_PF_ALIGN;
+ alignment = sizeof(void *) << (rnd() % 4);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, (64 + rnd() % 64) * 1024);
MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, (1 + rnd() % 8) * 8);
@@ -190,7 +190,7 @@ int main(int argc, char *argv[])
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
- alignment = (1 << (rnd() % 4)) * MPS_PF_ALIGN;
+ alignment = sizeof(void *) << (rnd() % 4);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, alignment);
MPS_ARGS_ADD(args, MPS_KEY_MIN_SIZE, (1 + rnd() % 4) * 4);
diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c
index 80c68d7f711..2a18d1a7d10 100644
--- a/mps/code/gcbench.c
+++ b/mps/code/gcbench.c
@@ -318,8 +318,8 @@ int main(int argc, char *argv[]) {
double mort = 0.0;
cap = (size_t)strtoul(optarg, &p, 10);
switch(toupper(*p)) {
- case 'G': cap *= 1024; /* fall through */
- case 'M': cap *= 1024; /* fall through */
+ case 'G': cap <<= 20; p++; break;
+ case 'M': cap <<= 10; p++; break;
case 'K': p++; break;
default: cap = 0; break;
}
@@ -340,9 +340,9 @@ int main(int argc, char *argv[]) {
char *p;
arenasize = (unsigned)strtoul(optarg, &p, 10);
switch(toupper(*p)) {
- case 'G': arenasize *= 1024;
- case 'M': arenasize *= 1024;
- case 'K': arenasize *= 1024; break;
+ case 'G': arenasize <<= 30; break;
+ case 'M': arenasize <<= 20; break;
+ case 'K': arenasize <<= 10; break;
case '\0': break;
default:
fprintf(stderr, "Bad arena size %s\n", optarg);
diff --git a/mps/code/global.c b/mps/code/global.c
index 24cd0a81013..812f90dad3d 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -393,25 +393,7 @@ void GlobalsFinish(Globals arenaGlobals)
Arena arena;
Rank rank;
- /* Check that the tear-down is complete: that the client has
- * destroyed all data structures associated with the arena. We do
- * this *before* calling AVERT(Globals, arenaGlobals) because the
- * AVERT will crash if there are any remaining data structures, and
- * it is politer to assert than to crash. (The crash would happen
- * because by this point in the code the control pool has been
- * destroyed and so the address space containing all these rings has
- * potentially been unmapped, and so RingCheck dereferences a
- * pointer into that unmapped memory.) See job000652. */
arena = GlobalsArena(arenaGlobals);
- AVER(RingIsSingle(&arena->formatRing));
- AVER(RingIsSingle(&arena->chainRing));
- AVER(RingIsSingle(&arena->messageRing));
- AVER(RingIsSingle(&arena->threadRing));
- for(rank = 0; rank < RankLIMIT; ++rank)
- AVER(RingIsSingle(&arena->greyRing[rank]));
- AVER(RingIsSingle(&arenaGlobals->poolRing));
- AVER(RingIsSingle(&arenaGlobals->rootRing));
-
AVERT(Globals, arenaGlobals);
STATISTIC_STAT(EVENT2(ArenaWriteFaults, arena,
@@ -441,6 +423,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
TraceId ti;
Trace trace;
Chain defaultChain;
+ Rank rank;
AVERT(Globals, arenaGlobals);
@@ -495,6 +478,31 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
arena->finalPool = NULL;
PoolDestroy(pool);
}
+
+ /* Check that the tear-down is complete: that the client has
+ * destroyed all data structures associated with the arena. We do
+ * this here rather than in GlobalsFinish because by the time that
+ * is called, the control pool has been destroyed and so the address
+ * space containing all these rings has potentially been unmapped,
+ * and so RingCheck dereferences a pointer into that unmapped memory
+ * and we get a crash instead of an assertion. See job000652.
+ */
+ AVER(RingIsSingle(&arena->formatRing));
+ AVER(RingIsSingle(&arena->chainRing));
+ AVER(RingIsSingle(&arena->messageRing));
+ AVER(RingIsSingle(&arena->threadRing));
+ AVER(RingIsSingle(&arenaGlobals->rootRing));
+ for(rank = 0; rank < RankLIMIT; ++rank)
+ AVER(RingIsSingle(&arena->greyRing[rank]));
+
+ /* At this point the following pools still exist:
+ * 0. arena->freeCBSBlockPoolStruct
+ * 1. arena->reservoirStruct
+ * 2. arena->controlPoolStruct
+ * 3. arena->controlPoolStruct.blockPoolStruct
+ * 4. arena->controlPoolStruct.spanPoolStruct
+ */
+ AVER(RingLength(&arenaGlobals->poolRing) == 5);
}
@@ -595,6 +603,7 @@ void ArenaLeaveRecursive(Arena arena)
* version. The format is platform-specific. We won't necessarily
* publish this. */
+extern MutatorFaultContext mps_exception_info;
MutatorFaultContext mps_exception_info = NULL;
@@ -1101,7 +1110,7 @@ void ArenaSetEmergency(Arena arena, Bool emergency)
AVERT(Arena, arena);
AVERT(Bool, emergency);
- EVENT2(ArenaSetEmergency, arena, emergency);
+ EVENT2(ArenaSetEmergency, arena, BOOLOF(emergency));
arena->emergency = emergency;
}
diff --git a/mps/code/ll.gmk b/mps/code/ll.gmk
index dc2595c511f..55e4b6cff5d 100644
--- a/mps/code/ll.gmk
+++ b/mps/code/ll.gmk
@@ -10,17 +10,20 @@
# common makefile fragment () requires.
CC = clang
-CFLAGSDEBUG = -O -g3
+CFLAGSDEBUG = -O0 -g3
CFLAGSOPT = -O2 -g3
CFLAGSCOMPILER := \
-pedantic \
-Waggregate-return \
-Wall \
-Wcast-qual \
+ -Wconversion \
+ -Wduplicate-enum \
-Werror \
-Wextra \
-Winline \
-Wmissing-prototypes \
+ -Wmissing-variable-declarations \
-Wnested-externs \
-Wno-extended-offsetof \
-Wpointer-arith \
diff --git a/mps/code/lockcov.c b/mps/code/lockcov.c
index a7289dca9ce..75ded6f202a 100644
--- a/mps/code/lockcov.c
+++ b/mps/code/lockcov.c
@@ -4,21 +4,37 @@
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*/
+#include "mps.h"
+#include "mpsavm.h"
+#include "mpscmfs.h"
#include "mpm.h"
#include "testlib.h"
#include "mpslib.h"
#include /* printf */
-#include /* free, malloc */
int main(int argc, char *argv[])
{
- Lock a = malloc(LockSize());
- Lock b = malloc(LockSize());
+ mps_arena_t arena;
+ mps_pool_t pool;
+ mps_addr_t p;
+ Lock a, b;
testlib_init(argc, argv);
+ die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none),
+ "arena_create");
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, LockSize());
+ die(mps_pool_create_k(&pool, arena, mps_class_mfs(), args), "pool_create");
+ } MPS_ARGS_END(args);
+
+ die(mps_alloc(&p, pool, LockSize()), "alloc a");
+ a = p;
+ die(mps_alloc(&p, pool, LockSize()), "alloc b");
+ b = p;
+
Insist(a != NULL);
Insist(b != NULL);
@@ -46,8 +62,11 @@ int main(int argc, char *argv[])
LockReleaseMPM(a);
LockFinish(a);
LockReleaseGlobalRecursive();
- free(a);
- free(b);
+
+ mps_free(pool, a, LockSize());
+ mps_free(pool, b, LockSize());
+ mps_pool_destroy(pool);
+ mps_arena_destroy(arena);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;
diff --git a/mps/code/lockut.c b/mps/code/lockut.c
index ec22369bc13..e93bdea6815 100644
--- a/mps/code/lockut.c
+++ b/mps/code/lockut.c
@@ -4,18 +4,20 @@
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*/
+#include "mps.h"
+#include "mpsavm.h"
+#include "mpscmfs.h"
#include "mpm.h"
#include "testlib.h"
#include "testthr.h"
#include /* printf */
-#include /* malloc */
#define nTHREADS 4
static Lock lock;
-unsigned long shared, tmp;
+static unsigned long shared, tmp;
static void incR(unsigned long i)
@@ -63,12 +65,23 @@ static void *thread0(void *p)
int main(int argc, char *argv[])
{
+ mps_arena_t arena;
+ mps_pool_t pool;
+ mps_addr_t p;
testthr_t t[10];
unsigned i;
testlib_init(argc, argv);
- lock = malloc(LockSize());
+ die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none),
+ "arena_create");
+ MPS_ARGS_BEGIN(args) {
+ MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, LockSize());
+ die(mps_pool_create_k(&pool, arena, mps_class_mfs(), args), "pool_create");
+ } MPS_ARGS_END(args);
+
+ die(mps_alloc(&p, pool, LockSize()), "alloc");
+ lock = p;
Insist(lock != NULL);
LockInit(lock);
@@ -86,6 +99,10 @@ int main(int argc, char *argv[])
LockFinish(lock);
+ mps_free(pool, lock, LockSize());
+ mps_pool_destroy(pool);
+ mps_arena_destroy(arena);
+
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;
}
diff --git a/mps/code/locus.c b/mps/code/locus.c
index a704c8b820b..6e6e22128b7 100644
--- a/mps/code/locus.c
+++ b/mps/code/locus.c
@@ -287,13 +287,21 @@ Res ChainAlloc(Seg *segReturn, Chain chain, Serial genNr, SegClass class,
double ChainDeferral(Chain chain)
{
+ double time = DBL_MAX;
+ size_t i;
+
AVERT(Chain, chain);
- if (chain->activeTraces != TraceSetEMPTY)
- return DBL_MAX;
- else
- return chain->gens[0].capacity * 1024.0
- - (double)GenDescNewSize(&chain->gens[0]);
+ if (chain->activeTraces == TraceSetEMPTY) {
+ for (i = 0; i < chain->genCount; ++i) {
+ double genTime = chain->gens[i].capacity * 1024.0
+ - (double)GenDescNewSize(&chain->gens[i]);
+ if (genTime < time)
+ time = genTime;
+ }
+ }
+
+ return time;
}
@@ -306,7 +314,7 @@ double ChainDeferral(Chain chain)
Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace)
{
Res res;
- Serial topCondemnedGenSerial, currGenSerial;
+ size_t topCondemnedGen, i;
GenDesc gen;
ZoneSet condemnedSet = ZoneSetEMPTY;
Size condemnedSize = 0, survivorSize = 0, genNewSize, genTotalSize;
@@ -314,33 +322,39 @@ Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace)
AVERT(Chain, chain);
AVERT(Trace, trace);
- /* Find lowest gen within its capacity, set topCondemnedGenSerial to the */
- /* preceeding one. */
- currGenSerial = 0;
- gen = &chain->gens[0];
- AVERT(GenDesc, gen);
- genNewSize = GenDescNewSize(gen);
- do { /* At this point, we've decided to collect currGenSerial. */
- topCondemnedGenSerial = currGenSerial;
+ /* Find the highest generation that's over capacity. We will condemn
+ * this and all lower generations in the chain. */
+ topCondemnedGen = chain->genCount;
+ for (;;) {
+ /* It's an error to call this function unless some generation is
+ * over capacity as reported by ChainDeferral. */
+ AVER(topCondemnedGen > 0);
+ if (topCondemnedGen == 0)
+ return ResFAIL;
+ -- topCondemnedGen;
+ gen = &chain->gens[topCondemnedGen];
+ AVERT(GenDesc, gen);
+ genNewSize = GenDescNewSize(gen);
+ if (genNewSize >= gen->capacity * (Size)1024)
+ break;
+ }
+
+ /* At this point, we've decided to condemn topCondemnedGen and all
+ * lower generations. */
+ for (i = 0; i <= topCondemnedGen; ++i) {
+ gen = &chain->gens[i];
+ AVERT(GenDesc, gen);
condemnedSet = ZoneSetUnion(condemnedSet, gen->zones);
genTotalSize = GenDescTotalSize(gen);
+ genNewSize = GenDescNewSize(gen);
condemnedSize += genTotalSize;
survivorSize += (Size)(genNewSize * (1.0 - gen->mortality))
/* predict survivors will survive again */
+ (genTotalSize - genNewSize);
-
- /* is there another one to consider? */
- currGenSerial += 1;
- if (currGenSerial >= chain->genCount)
- break; /* reached the top */
- gen = &chain->gens[currGenSerial];
- AVERT(GenDesc, gen);
- genNewSize = GenDescNewSize(gen);
- } while (genNewSize >= gen->capacity * (Size)1024);
+ }
AVER(condemnedSet != ZoneSetEMPTY || condemnedSize == 0);
- EVENT3(ChainCondemnAuto, chain, topCondemnedGenSerial, chain->genCount);
- UNUSED(topCondemnedGenSerial); /* only used for EVENT */
+ EVENT3(ChainCondemnAuto, chain, topCondemnedGen, chain->genCount);
/* Condemn everything in these zones. */
if (condemnedSet != ZoneSetEMPTY) {
@@ -354,41 +368,6 @@ Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace)
}
-/* ChainCondemnAll -- condemn everything in the chain */
-
-Res ChainCondemnAll(Chain chain, Trace trace)
-{
- Ring node, nextNode;
- Bool haveWhiteSegs = FALSE;
- Res res;
-
- /* Condemn every segment in every pool using this chain. */
- /* Finds the pools by iterating over the PoolGens in gen 0. */
- RING_FOR(node, &chain->gens[0].locusRing, nextNode) {
- PoolGen nursery = RING_ELT(PoolGen, genRing, node);
- Pool pool = nursery->pool;
- Ring segNode, nextSegNode;
-
- AVERT(Pool, pool);
- AVER(PoolHasAttr(pool, AttrGC));
- RING_FOR(segNode, PoolSegRing(pool), nextSegNode) {
- Seg seg = SegOfPoolRing(segNode);
-
- res = TraceAddWhite(trace, seg);
- if (res != ResOK)
- goto failBegin;
- haveWhiteSegs = TRUE;
- }
- }
-
- return ResOK;
-
-failBegin:
- AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */
- return res;
-}
-
-
/* ChainStartGC -- called to notify start of GC for this chain */
void ChainStartGC(Chain chain, Trace trace)
@@ -416,9 +395,11 @@ void ChainEndGC(Chain chain, Trace trace)
Res PoolGenInit(PoolGen gen, Chain chain, Serial nr, Pool pool)
{
/* Can't check gen, because it's not been initialized. */
+ AVER(gen != NULL);
AVERT(Chain, chain);
AVER(nr <= chain->genCount);
AVERT(Pool, pool);
+ AVER(PoolHasAttr(pool, AttrGC));
gen->nr = nr;
gen->pool = pool;
diff --git a/mps/code/meter.h b/mps/code/meter.h
index 7a7f8266e87..f1731400e42 100644
--- a/mps/code/meter.h
+++ b/mps/code/meter.h
@@ -1,7 +1,7 @@
/* meter.h: METER INTERFACE
*
* $Id$
- * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .sources: mps.design.metrics.
*
@@ -45,9 +45,12 @@ extern void MeterEmit(Meter meter);
#define METER_ACC(meter, delta) \
STATISTIC(MeterAccumulate(&(meter), delta))
#if defined(STATISTICS)
-#define METER_WRITE(meter, stream) MeterWrite(&(meter), stream)
+#define METER_WRITE(meter, stream) BEGIN \
+ Res _res = MeterWrite(&(meter), (stream)); \
+ if (_res != ResOK) return _res; \
+ END
#elif defined(STATISTICS_NONE)
-#define METER_WRITE(meter, stream) (ResOK)
+#define METER_WRITE(meter, stream) NOOP
#else
#error "No statistics configured."
#endif
@@ -59,7 +62,7 @@ extern void MeterEmit(Meter meter);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2013 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/misc.h b/mps/code/misc.h
index 6ba4be5f49d..fed416157dd 100644
--- a/mps/code/misc.h
+++ b/mps/code/misc.h
@@ -1,7 +1,7 @@
/* misc.h: MISCELLANEOUS DEFINITIONS
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2001 Global Graphics Software.
*
* Small general things which are useful for C but aren't part of the
@@ -50,6 +50,7 @@ typedef const struct SrcIdStruct {
#define SRCID(id, scmid) \
static SrcIdStruct id ## FileSrcIdStruct = \
{__FILE__, (scmid), __DATE__, __TIME__}; \
+ extern SrcId id ## SrcId; \
SrcId id ## SrcId = &id ## FileSrcIdStruct
@@ -170,6 +171,16 @@ typedef const struct SrcIdStruct {
((type *)(void *)((char *)(p) - offsetof(type, field)))
+/* BITFIELD -- coerce a value into a bitfield
+ *
+ * This coerces value to the given width and type in a way that avoids
+ * warnings from gcc -Wconversion about possible loss of data.
+ */
+
+#define BITFIELD(type, value, width) ((type)value & (((type)1 << (width)) - 1))
+#define BOOLOF(v) BITFIELD(unsigned, (v), 1)
+
+
/* Bit Sets -- sets of integers in [0,N-1].
*
* Can be used on any unsigned integral type, ty. These definitions
@@ -191,6 +202,7 @@ typedef const struct SrcIdStruct {
#define BS_SUB(s1, s2) BS_SUPER((s2), (s1))
#define BS_IS_SINGLE(s) ( ((s) != 0) && (((s) & ((s)-1)) == 0) )
#define BS_SYM_DIFF(s1, s2) ((s1) ^ (s2))
+#define BS_BITFIELD(ty, s) BITFIELD(ty ## Set, (s), ty ## LIMIT)
#endif /* misc_h */
@@ -198,7 +210,7 @@ typedef const struct SrcIdStruct {
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/mpm.c b/mps/code/mpm.c
index f544acca401..a46fdf5fb10 100644
--- a/mps/code/mpm.c
+++ b/mps/code/mpm.c
@@ -174,16 +174,16 @@ Word (WordAlignDown)(Word word, Align alignment)
/* SizeIsP2 -- test whether a size is a power of two */
-Bool SizeIsP2(Size size)
+Bool (SizeIsP2)(Size size)
{
- return WordIsP2((Word)size);
+ return SizeIsP2(size);
}
/* WordIsP2 -- tests whether a word is a power of two */
-Bool WordIsP2(Word word)
+Bool (WordIsP2)(Word word)
{
- return word > 0 && (word & (word - 1)) == 0;
+ return WordIsP2(word);
}
diff --git a/mps/code/mpm.h b/mps/code/mpm.h
index 8ed0d6aa608..e6a0da4e834 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -143,11 +143,13 @@ extern Bool ResIsAllocFailure(Res res);
* SizeFloorLog2 returns the floor of the logarithm in base 2 of size.
* size can be any positive non-zero value. */
-extern Bool SizeIsP2(Size size);
+extern Bool (SizeIsP2)(Size size);
+#define SizeIsP2(size) WordIsP2((Word)size)
extern Shift SizeLog2(Size size);
extern Shift SizeFloorLog2(Size size);
-extern Bool WordIsP2(Word word);
+extern Bool (WordIsP2)(Word word);
+#define WordIsP2(word) ((word) > 0 && ((word) & ((word) - 1)) == 0)
/* Formatted Output -- see , */
@@ -712,10 +714,10 @@ extern Addr (SegLimit)(Seg seg);
#define SegSummary(seg) (((GCSeg)(seg))->summary)
-#define SegSetPM(seg, mode) ((void)((seg)->pm = (mode)))
-#define SegSetSM(seg, mode) ((void)((seg)->sm = (mode)))
-#define SegSetDepth(seg, d) ((void)((seg)->depth = (d)))
-#define SegSetNailed(seg, ts) ((void)((seg)->nailed = (ts)))
+#define SegSetPM(seg, mode) ((void)((seg)->pm = BS_BITFIELD(Access, (mode))))
+#define SegSetSM(seg, mode) ((void)((seg)->sm = BS_BITFIELD(Access, (mode))))
+#define SegSetDepth(seg, d) ((void)((seg)->depth = BITFIELD(unsigned, (d), ShieldDepthWIDTH)))
+#define SegSetNailed(seg, ts) ((void)((seg)->nailed = BS_BITFIELD(Trace, (ts))))
/* Buffer Interface -- see */
@@ -927,8 +929,6 @@ extern void (ShieldFlush)(Arena arena);
extern void ProtSetup(void);
extern void ProtSet(Addr base, Addr limit, AccessSet mode);
-extern void ProtTramp(void **resultReturn, void *(*f)(void *, size_t),
- void *p, size_t s);
extern void ProtSync(Arena arena);
extern Bool ProtCanStepInstruction(MutatorFaultContext context);
extern Res ProtStepInstruction(MutatorFaultContext context);
diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h
index 85e95a78ec1..5d38f3a3319 100644
--- a/mps/code/mpmst.h
+++ b/mps/code/mpmst.h
@@ -1,7 +1,7 @@
/* mpmst.h: MEMORY POOL MANAGER DATA STRUCTURES
*
* $Id$
- * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2001 Global Graphics Software.
*
* .design: This header file crosses module boundaries. The relevant
@@ -275,8 +275,8 @@ typedef struct SegStruct { /* segment structure */
RingStruct poolRing; /* link in list of segs in pool */
Addr limit; /* limit of segment */
unsigned depth : ShieldDepthWIDTH; /* see */
- AccessSet pm : AccessSetWIDTH; /* protection mode, */
- AccessSet sm : AccessSetWIDTH; /* shield mode, */
+ AccessSet pm : AccessLIMIT; /* protection mode, */
+ AccessSet sm : AccessLIMIT; /* shield mode, */
TraceSet grey : TraceLIMIT; /* traces for which seg is grey */
TraceSet white : TraceLIMIT; /* traces for which seg is white */
TraceSet nailed : TraceLIMIT; /* traces for which seg has nailed objects */
@@ -738,7 +738,7 @@ typedef struct AllocPatternStruct {
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2013 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index 693a2262247..e22e77d8f69 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -271,7 +271,7 @@ typedef struct TraceMessageStruct *TraceMessage; /* trace end */
#define AccessSetEMPTY ((AccessSet)0) /* */
#define AccessREAD ((AccessSet)(1<<0))
#define AccessWRITE ((AccessSet)(1<<1))
-#define AccessSetWIDTH (2)
+#define AccessLIMIT (2)
#define RefSetEMPTY BS_EMPTY(RefSet)
#define RefSetUNIV BS_UNIV(RefSet)
#define ZoneSetEMPTY BS_EMPTY(ZoneSet)
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 3df0913df83..45ffff50166 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -1380,7 +1380,7 @@ void (mps_tramp)(void **r_o,
AVER(FUNCHECK(f));
/* Can't check p and s as they are interpreted by the client */
- ProtTramp(r_o, f, p, s);
+ *r_o = (*f)(p, s);
}
diff --git a/mps/code/mpsw3.h b/mps/code/mpsw3.h
deleted file mode 100644
index f32b7a09831..00000000000
--- a/mps/code/mpsw3.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* mpsw3.h: RAVENBROOK MEMORY POOL SYSTEM C INTERFACE, WINDOWS PART
- *
- * $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
- *
- * .readership: customers, MPS developers.
- * .sources: .
- */
-
-#ifndef mpsw3_h
-#define mpsw3_h
-
-#include "mps.h" /* needed for mps_tramp_t */
-#include "mpswin.h" /* needed for SEH filter */
-
-
-extern LONG mps_SEH_filter(LPEXCEPTION_POINTERS, void **, size_t *);
-extern void mps_SEH_handler(void *, size_t);
-
-
-#define mps_tramp(r_o, f, p, s) \
- MPS_BEGIN \
- void **_r_o = (r_o); \
- mps_tramp_t _f = (f); \
- void *_p = (p); \
- size_t _s = (s); \
- void *_hp = NULL; size_t _hs = 0; \
- __try { \
- *_r_o = (*_f)(_p, _s); \
- } __except(mps_SEH_filter(GetExceptionInformation(), \
- &_hp, &_hs)) { \
- mps_SEH_handler(_hp, _hs); \
- } \
- MPS_END
-
-
-#endif /* mpsw3_h */
-
-
-/* C. COPYRIGHT AND LICENSE
- *
- * Copyright (C) 2001-2002 Ravenbrook Limited .
- * All rights reserved. This is an open source license. Contact
- * Ravenbrook for commercial licensing options.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. Redistributions in any form must be accompanied by information on how
- * to obtain complete source code for this software and any accompanying
- * software that uses this software. The source code must either be
- * included in the distribution or be available for no more than the cost
- * of distribution plus a nominal fee, and must be freely redistributable
- * under reasonable conditions. For an executable file, complete source
- * code means the source code for all modules it contains. It does not
- * include source code for modules or files that typically accompany the
- * major components of the operating system on which the executable file
- * runs.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
diff --git a/mps/code/nailboard.c b/mps/code/nailboard.c
index 8744514662b..852c98949e7 100644
--- a/mps/code/nailboard.c
+++ b/mps/code/nailboard.c
@@ -30,26 +30,36 @@ static Count nailboardLevels(Count nails)
}
+/* nailboardNails -- return the total number of nails in the board */
+
+static Count nailboardNails(Nailboard board)
+{
+ return RangeSize(&board->range) >> board->alignShift;
+}
+
+
/* nailboardLevelBits -- return the number of bits in the bit table
* for the given level.
*/
-static Count nailboardLevelBits(Nailboard board, Index level)
+static Count nailboardLevelBits(Count nails, Index level)
{
- /* Use <= rather than < because of .check.levels. */
- AVER(level <= board->levels);
- return RangeSize(&board->range) >> (board->alignShift + level * LEVEL_SHIFT);
+ Shift shift = (Shift)(level * LEVEL_SHIFT);
+ return (nails + ((Count)1 << shift) - 1) >> shift;
}
Bool NailboardCheck(Nailboard board)
{
Index i;
+ Count nails;
CHECKS(Nailboard, board);
CHECKL(RangeCheck(&board->range));
CHECKL(0 < board->levels);
- CHECKL(board->levels == nailboardLevels(nailboardLevelBits(board, 0)));
- CHECKL(nailboardLevelBits(board, board->levels - 1) != 0);
- CHECKL(nailboardLevelBits(board, board->levels) == 0); /* .check.levels */
+ nails = nailboardNails(board);
+ CHECKL(board->levels == nailboardLevels(nails));
+ CHECKL(nails == nailboardLevelBits(nails, 0));
+ CHECKL(nailboardLevelBits(nails, board->levels - 1) != 0);
+ CHECKL(nailboardLevelBits(nails, board->levels) == 1);
CHECKL(BoolCheck(board->newNails));
for (i = 0; i < board->levels; ++i) {
CHECKL(board->level[i] != NULL);
@@ -80,8 +90,7 @@ static Size nailboardSize(Count nails, Count levels)
Size size;
size = nailboardStructSize(levels);
for (i = 0; i < levels; ++i) {
- size += BTSize(nails);
- nails >>= LEVEL_SHIFT;
+ size += BTSize(nailboardLevelBits(nails, i));
}
return size;
}
@@ -130,11 +139,11 @@ Res NailboardCreate(Nailboard *boardReturn, Arena arena, Align alignment,
p = PointerAdd(p, nailboardStructSize(levels));
for (i = 0; i < levels; ++i) {
- AVER(nails > 0);
+ Count levelBits = nailboardLevelBits(nails, i);
+ AVER(levelBits > 0);
board->level[i] = p;
- BTResRange(board->level[i], 0, nails);
- p = PointerAdd(p, BTSize(nails));
- nails >>= LEVEL_SHIFT;
+ BTResRange(board->level[i], 0, levelBits);
+ p = PointerAdd(p, BTSize(levelBits));
}
board->sig = NailboardSig;
@@ -154,7 +163,7 @@ void NailboardDestroy(Nailboard board, Arena arena)
AVERT(Nailboard, board);
AVERT(Arena, arena);
- nails = nailboardLevelBits(board, 0);
+ nails = nailboardNails(board);
size = nailboardSize(nails, board->levels);
board->sig = SigInvalid;
@@ -191,8 +200,10 @@ Bool (NailboardNewNails)(Nailboard board)
static Index nailboardIndex(Nailboard board, Index level, Addr addr)
{
- return AddrOffset(RangeBase(&board->range), addr)
+ Index i = AddrOffset(RangeBase(&board->range), addr)
>> (board->alignShift + level * LEVEL_SHIFT);
+ AVER_CRITICAL(i < nailboardLevelBits(nailboardNails(board), level));
+ return i;
}
@@ -414,7 +425,7 @@ Res NailboardDescribe(Nailboard board, mps_lib_FILE *stream)
return res;
for(i = 0; i < board->levels; ++i) {
- Count levelNails = nailboardLevelBits(board, i);
+ Count levelNails = nailboardLevelBits(nailboardNails(board), i);
Count resetNails = BTCountResRange(board->level[i], 0, levelNails);
res = WriteF(stream, " Level $U ($U bits, $U set): ",
i, levelNails, levelNails - resetNails, NULL);
diff --git a/mps/code/poolams.c b/mps/code/poolams.c
index c67a2efd684..65b2dcf754f 100644
--- a/mps/code/poolams.c
+++ b/mps/code/poolams.c
@@ -74,6 +74,11 @@ Bool AMSSegCheck(AMSSeg amsseg)
CHECKD_NOSIG(BT, amsseg->nongreyTable);
CHECKD_NOSIG(BT, amsseg->nonwhiteTable);
+ /* If tables are shared, they mustn't both be in use. */
+ CHECKL(!(amsseg->ams->shareAllocTable
+ && amsseg->allocTableInUse
+ && amsseg->colourTablesInUse));
+
return TRUE;
}
@@ -167,6 +172,15 @@ static Res amsCreateTables(AMS ams, BT *allocReturn,
goto failWhite;
}
+#if defined(AVER_AND_CHECK)
+ /* Invalidate the colour tables in checking varieties. The algorithm
+ * is designed not to depend on the initial values of these tables,
+ * so by invalidating them we get some checking of this.
+ */
+ BTResRange(nongreyTable, 0, length);
+ BTSetRange(nonwhiteTable, 0, length);
+#endif
+
*allocReturn = allocTable;
*nongreyReturn = nongreyTable;
*nonwhiteReturn = nonwhiteTable;
@@ -1023,7 +1037,20 @@ static void AMSBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
AVER(limitIndex <= amsseg->firstFree);
if (limitIndex == amsseg->firstFree) /* is it at the end? */ {
amsseg->firstFree = initIndex;
- } else { /* start using allocTable */
+ } else if (ams->shareAllocTable && amsseg->colourTablesInUse) {
+ /* The nonwhiteTable is shared with allocTable and in use, so we
+ * mustn't start using allocTable. In this case we know: 1. the
+ * segment has been condemned (because colour tables are turned
+ * on in AMSCondemn); 2. the segment has not yet been reclaimed
+ * (because colour tables are turned off in AMSReclaim); 3. the
+ * unused portion of the buffer is black (see AMSCondemn). So we
+ * need to whiten the unused portion of the buffer. The
+ * allocTable will be turned back on (if necessary) in
+ * AMSReclaim, when we know that the nonwhite grains are exactly
+ * the allocated grains.
+ */
+ } else {
+ /* start using allocTable */
amsseg->allocTableInUse = TRUE;
BTSetRange(amsseg->allocTable, 0, amsseg->firstFree);
if (amsseg->firstFree < amsseg->grains)
@@ -1415,16 +1442,20 @@ static Res AMSFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
/* doing that here (this can be called from RootScan, during flip). */
clientRef = *refIO;
+ AVER_CRITICAL(SegBase(seg) <= clientRef);
+ AVER_CRITICAL(clientRef < SegLimit(seg)); /* see .ref-limit */
base = AddrSub((Addr)clientRef, format->headerSize);
/* can get an ambiguous reference too close to the base of the
* segment, so when we subtract the header we are not in the
* segment any longer. This isn't a real reference,
* so we can just skip it. */
if (base < SegBase(seg)) {
- return ResOK;
+ AVER_CRITICAL(ss->rank == RankAMBIG);
+ return ResOK;
}
i = AMS_ADDR_INDEX(seg, base);
+ AVER_CRITICAL(i < amsseg->grains);
AVER_CRITICAL(!AMS_IS_INVALID_COLOUR(seg, i));
ss->wasMarked = TRUE;
@@ -1584,12 +1615,13 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg)
/* preservedInPlaceCount is updated on fix */
trace->preservedInPlaceSize += (grains - amsseg->free) << ams->grainShift;
+ /* Ensure consistency of segment even if are just about to free it */
+ amsseg->colourTablesInUse = FALSE;
+ SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace));
+
if (amsseg->free == grains && SegBuffer(seg) == NULL) {
/* No survivors */
SegFree(seg);
- } else {
- amsseg->colourTablesInUse = FALSE;
- SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace));
}
}
diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c
index 6332a91b7cd..cbece0b41fe 100644
--- a/mps/code/poolawl.c
+++ b/mps/code/poolawl.c
@@ -305,10 +305,14 @@ DEFINE_SEG_CLASS(AWLSegClass, class)
* it's possible to tweak them in a debugger.
*/
+extern Count AWLSegSALimit;
Count AWLSegSALimit = AWL_SEG_SA_LIMIT;
+extern Bool AWLHaveSegSALimit;
Bool AWLHaveSegSALimit = AWL_HAVE_SEG_SA_LIMIT;
+extern Count AWLTotalSALimit;
Count AWLTotalSALimit = AWL_TOTAL_SA_LIMIT;
+extern Bool AWLHaveTotalSALimit;
Bool AWLHaveTotalSALimit = AWL_HAVE_TOTAL_SA_LIMIT;
@@ -558,6 +562,7 @@ static Res AWLInit(Pool pool, ArgList args)
AVERT(Format, format);
pool->format = format;
+ pool->alignment = format->alignment;
AVER(FUNCHECK(findDependent));
awl->findDependent = findDependent;
@@ -570,7 +575,7 @@ static Res AWLInit(Pool pool, ArgList args)
if (res != ResOK)
goto failGenInit;
- awl->alignShift = SizeLog2(pool->alignment);
+ awl->alignShift = SizeLog2(PoolAlignment(pool));
awl->size = (Size)0;
awl->succAccesses = 0;
@@ -937,7 +942,7 @@ static Res awlScanSinglePass(Bool *anyScannedReturn,
i = awlIndexOfAddr(base, awl, p);
if (!BTGet(awlseg->alloc, i)) {
- p = AddrAdd(p, pool->alignment);
+ p = AddrAdd(p, PoolAlignment(pool));
continue;
}
hp = AddrAdd(p, format->headerSize);
@@ -954,7 +959,8 @@ static Res awlScanSinglePass(Bool *anyScannedReturn,
}
objectLimit = AddrSub(objectLimit, format->headerSize);
AVER(p < objectLimit);
- p = AddrAlignUp(objectLimit, pool->alignment);
+ AVER(AddrIsAligned(objectLimit, PoolAlignment(pool)));
+ p = objectLimit;
}
AVER(p == limit);
@@ -1051,7 +1057,7 @@ static Res AWLFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
switch(ss->rank) {
case RankAMBIG:
/* not a real pointer if not aligned or not allocated */
- if (!AddrIsAligned(base, pool->alignment) || !BTGet(awlseg->alloc, i))
+ if (!AddrIsAligned(base, sizeof(void *)) || !BTGet(awlseg->alloc, i))
return ResOK;
/* falls through */
case RankEXACT:
@@ -1125,7 +1131,7 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg)
}
q = format->skip(AddrAdd(p, format->headerSize));
q = AddrSub(q, format->headerSize);
- q = AddrAlignUp(q, pool->alignment);
+ AVER(AddrIsAligned(q, PoolAlignment(pool)));
j = awlIndexOfAddr(base, awl, q);
AVER(j <= awlseg->grains);
if(BTGet(awlseg->mark, i)) {
@@ -1243,13 +1249,13 @@ static void AWLWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
i = awlIndexOfAddr(base, awl, object);
if (!BTGet(awlseg->alloc, i)) {
/* This grain is free */
- object = AddrAdd(object, pool->alignment);
+ object = AddrAdd(object, PoolAlignment(pool));
continue;
}
object = AddrAdd(object, format->headerSize);
next = format->skip(object);
next = AddrSub(next, format->headerSize);
- next = AddrAlignUp(next, pool->alignment);
+ AVER(AddrIsAligned(next, PoolAlignment(pool)));
if (BTGet(awlseg->mark, i) && BTGet(awlseg->scanned, i))
(*f)(object, pool->format, pool, p, s);
object = next;
diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c
index fbb125a71f2..139b3f5c872 100644
--- a/mps/code/poolmfs.c
+++ b/mps/code/poolmfs.c
@@ -136,7 +136,7 @@ static Res MFSInit(Pool pool, ArgList args)
mfs->sig = MFSSig;
AVERT(MFS, mfs);
- EVENT5(PoolInitMFS, pool, arena, extendBy, extendSelf, unitSize);
+ EVENT5(PoolInitMFS, pool, arena, extendBy, BOOLOF(extendSelf), unitSize);
return ResOK;
}
diff --git a/mps/code/poolmv.h b/mps/code/poolmv.h
index 098cd3eaa2e..8e6885254bc 100644
--- a/mps/code/poolmv.h
+++ b/mps/code/poolmv.h
@@ -1,41 +1,16 @@
/* poolmv.h: MANUAL VARIABLE POOL
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* .purpose: This is the interface to the manual-variable pool class.
*
- * .mv: Manual-variable pools manage variably-sized blocks of memory in a
- * flexible manner. They have higher overheads than a fixed-size pool.
+ * .mv: Manual-variable pools manage variably-sized blocks of memory
+ * in a flexible manner. They have higher overheads than a fixed-size
+ * pool.
*
- * .init: This class adds the following arguments to PoolCreate:
- *
- * Size extendBy
- *
- * extendBy is the default number of bytes reserved by the pool at a time.
- * A large size will make allocation cheaper but have a higher resource
- * overhead. A typical value might be 65536. See note 2.
- *
- * Size avgSize
- *
- * avgSize is an estimate of the average size of an allocation, and is used
- * to choose the size of internal tables. An accurate estimate will
- * improve the efficiency of the pool. A low estimate will make the pool
- * less space efficient. A high estimate will make the pool less time
- * efficient. A typical value might be 32. avgSize must not be less than
- * extendBy.
- *
- * Size maxSize
- *
- * maxSize is an estimate of the maximum total size that the pool will
- * reach. Setting this parameter does not actually contrain the pool, but
- * an accurate estimate will improve the efficiency of the pool. maxSize
- * must not be less than extendBy.
- *
- * Notes
- * 2. The documentation could suggest a segment size according to the
- * distribution of allocation size requests. richard 1994-11-08
+ * .design: See
*/
#ifndef poolmv_h
@@ -59,7 +34,7 @@ extern Bool MVCheck(MV mv);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c
index b2903481b45..f6d85b1b134 100644
--- a/mps/code/poolmv2.c
+++ b/mps/code/poolmv2.c
@@ -78,7 +78,6 @@ typedef struct MVTStruct
Bool abqOverflow; /* ABQ dropped some candidates */
/* .* */
Bool splinter; /* Saved splinter */
- Seg splinterSeg; /* Saved splinter seg */
Addr splinterBase; /* Saved splinter base */
Addr splinterLimit; /* Saved splinter size */
@@ -133,7 +132,7 @@ typedef struct MVTStruct
DEFINE_POOL_CLASS(MVTPoolClass, this)
{
- INHERIT_CLASS(this, AbstractSegBufPoolClass);
+ INHERIT_CLASS(this, AbstractBufferPoolClass);
this->name = "MVT";
this->size = sizeof(MVTStruct);
this->offset = offsetof(MVTStruct, poolStruct);
@@ -292,7 +291,6 @@ static Res MVTInit(Pool pool, ArgList args)
mvt->maxSize = maxSize;
mvt->fragLimit = fragLimit;
mvt->splinter = FALSE;
- mvt->splinterSeg = NULL;
mvt->splinterBase = (Addr)0;
mvt->splinterLimit = (Addr)0;
@@ -378,9 +376,7 @@ static Bool MVTCheck(MVT mvt)
if (mvt->splinter) {
CHECKL(AddrOffset(mvt->splinterBase, mvt->splinterLimit) >=
mvt->minSize);
- CHECKD(Seg, mvt->splinterSeg);
- CHECKL(mvt->splinterBase >= SegBase(mvt->splinterSeg));
- CHECKL(mvt->splinterLimit <= SegLimit(mvt->splinterSeg));
+ CHECKL(mvt->splinterBase < mvt->splinterLimit);
}
CHECKL(mvt->size == mvt->allocated + mvt->available +
mvt->unavailable);
@@ -951,7 +947,6 @@ static void MVTBufferEmpty(Pool pool, Buffer buffer,
}
mvt->splinter = TRUE;
- mvt->splinterSeg = BufferSeg(buffer);
mvt->splinterBase = base;
mvt->splinterLimit = limit;
}
@@ -998,8 +993,6 @@ static void MVTFree(Pool pool, Addr base, Size size)
AVER(mvt->size == mvt->allocated + mvt->available +
mvt->unavailable);
METER_ACC(mvt->exceptionReturns, SegSize(seg));
- if (SegBuffer(seg) != NULL)
- BufferDetach(SegBuffer(seg), MVT2Pool(mvt));
MVTSegFree(mvt, seg);
return;
}
@@ -1031,7 +1024,6 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream)
" availLimit: $U \n", (WriteFU)mvt->availLimit,
" abqOverflow: $S \n", mvt->abqOverflow?"TRUE":"FALSE",
" splinter: $S \n", mvt->splinter?"TRUE":"FALSE",
- " splinterSeg: $P \n", (WriteFP)mvt->splinterSeg,
" splinterBase: $A \n", (WriteFA)mvt->splinterBase,
" splinterLimit: $A \n", (WriteFU)mvt->splinterLimit,
" size: $U \n", (WriteFU)mvt->size,
@@ -1050,68 +1042,37 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream)
res = FreelistDescribe(MVTFreelist(mvt), stream);
if(res != ResOK) return res;
- res = METER_WRITE(mvt->segAllocs, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->segFrees, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->bufferFills, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->bufferEmpties, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->poolFrees, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->poolSize, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->poolAllocated, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->poolAvailable, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->poolUnavailable, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->poolUtilization, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->finds, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->overflows, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->underflows, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->refills, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->refillPushes, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->returns, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->perfectFits, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->firstFits, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->secondFits, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->failures, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->emergencyContingencies, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->fragLimitContingencies, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->contingencySearches, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->contingencyHardSearches, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->splinters, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->splintersUsed, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->splintersDropped, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->sawdust, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->exceptions, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->exceptionSplinters, stream);
- if (res != ResOK) return res;
- res = METER_WRITE(mvt->exceptionReturns, stream);
- if (res != ResOK) return res;
+ METER_WRITE(mvt->segAllocs, stream);
+ METER_WRITE(mvt->segFrees, stream);
+ METER_WRITE(mvt->bufferFills, stream);
+ METER_WRITE(mvt->bufferEmpties, stream);
+ METER_WRITE(mvt->poolFrees, stream);
+ METER_WRITE(mvt->poolSize, stream);
+ METER_WRITE(mvt->poolAllocated, stream);
+ METER_WRITE(mvt->poolAvailable, stream);
+ METER_WRITE(mvt->poolUnavailable, stream);
+ METER_WRITE(mvt->poolUtilization, stream);
+ METER_WRITE(mvt->finds, stream);
+ METER_WRITE(mvt->overflows, stream);
+ METER_WRITE(mvt->underflows, stream);
+ METER_WRITE(mvt->refills, stream);
+ METER_WRITE(mvt->refillPushes, stream);
+ METER_WRITE(mvt->returns, stream);
+ METER_WRITE(mvt->perfectFits, stream);
+ METER_WRITE(mvt->firstFits, stream);
+ METER_WRITE(mvt->secondFits, stream);
+ METER_WRITE(mvt->failures, stream);
+ METER_WRITE(mvt->emergencyContingencies, stream);
+ METER_WRITE(mvt->fragLimitContingencies, stream);
+ METER_WRITE(mvt->contingencySearches, stream);
+ METER_WRITE(mvt->contingencyHardSearches, stream);
+ METER_WRITE(mvt->splinters, stream);
+ METER_WRITE(mvt->splintersUsed, stream);
+ METER_WRITE(mvt->splintersDropped, stream);
+ METER_WRITE(mvt->sawdust, stream);
+ METER_WRITE(mvt->exceptions, stream);
+ METER_WRITE(mvt->exceptionSplinters, stream);
+ METER_WRITE(mvt->exceptionReturns, stream);
res = WriteF(stream, "}\n", NULL);
return res;
@@ -1189,7 +1150,7 @@ static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size,
{
/* Can't use plain old SegClass here because we need to call
* SegBuffer() in MVTFree(). */
- Res res = SegAlloc(segReturn, GCSegClassGet(),
+ Res res = SegAlloc(segReturn, SegClassGet(),
SegPrefDefault(), size, MVT2Pool(mvt), withReservoirPermit,
argsNone);
@@ -1213,7 +1174,6 @@ static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size,
*/
static void MVTSegFree(MVT mvt, Seg seg)
{
- Buffer buffer;
Size size;
size = SegSize(seg);
@@ -1223,16 +1183,6 @@ static void MVTSegFree(MVT mvt, Seg seg)
mvt->size -= size;
mvt->availLimit = mvt->size * mvt->fragLimit / 100;
AVER(mvt->size == mvt->allocated + mvt->available + mvt->unavailable);
-
- /* If the client program allocates the exactly the entire buffer then
- frees the allocated memory then we'll try to free the segment with
- the buffer still attached. It's safe, but we must detach the buffer
- first. See job003520 and job003672. */
- buffer = SegBuffer(seg);
- if (buffer != NULL) {
- AVER(BufferAP(buffer)->init == SegLimit(seg));
- BufferDetach(buffer, MVT2Pool(mvt));
- }
SegFree(seg);
METER_ACC(mvt->segFrees, size);
diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c
index 201d2047104..4971550c76a 100644
--- a/mps/code/poolmvff.c
+++ b/mps/code/poolmvff.c
@@ -610,7 +610,7 @@ static Res MVFFInit(Pool pool, ArgList args)
mvff->sig = MVFFSig;
AVERT(MVFF, mvff);
EVENT8(PoolInitMVFF, pool, arena, extendBy, avgSize, align,
- slotHigh, arenaHigh, firstFit);
+ BOOLOF(slotHigh), BOOLOF(arenaHigh), BOOLOF(firstFit));
return ResOK;
failInit:
diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c
index 6a36ae7db2b..5b5d150b8cc 100644
--- a/mps/code/prmci3li.c
+++ b/mps/code/prmci3li.c
@@ -36,27 +36,34 @@ SRCID(prmci3li, "$Id$");
MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
{
+ MRef gregs;
+
+ AVER(mfc != NULL);
AVER(NONNEGATIVE(regnum));
AVER(regnum <= 7);
+ AVER(mfc->ucontext != NULL);
+
+ /* TODO: The current arrangement of the fix operation (taking a Ref *)
+ forces us to pun these registers (actually `int` on LII3GC). We can
+ suppress the warning by casting through `void *` and this might make
+ it safe, but does it really? RB 2012-09-10 */
+ AVER(sizeof(void *) == sizeof(*mfc->ucontext->uc_mcontext.gregs));
+ gregs = (void *)mfc->ucontext->uc_mcontext.gregs;
/* .source.i486 */
/* .assume.regref */
/* The register numbers (REG_EAX etc.) are defined in
but only if _GNU_SOURCE is defined: see .feature.li in
config.h. */
- /* TODO: The current arrangement of the fix operation (taking a Ref *)
- forces us to pun these registers (actually `int` on LII3GC). We can
- suppress the warning my casting through `char *` and this might make
- it safe, but does it really? RB 2012-09-10 */
switch (regnum) {
- case 0: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EAX]);
- case 1: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_ECX]);
- case 2: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EDX]);
- case 3: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EBX]);
- case 4: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_ESP]);
- case 5: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EBP]);
- case 6: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_ESI]);
- case 7: return (MRef)((char *)&mfc->ucontext->uc_mcontext.gregs[REG_EDI]);
+ case 0: return &gregs[REG_EAX];
+ case 1: return &gregs[REG_ECX];
+ case 2: return &gregs[REG_EDX];
+ case 3: return &gregs[REG_EBX];
+ case 4: return &gregs[REG_ESP];
+ case 5: return &gregs[REG_EBP];
+ case 6: return &gregs[REG_ESI];
+ case 7: return &gregs[REG_EDI];
default:
NOTREACHED;
return NULL; /* Avoids compiler warning. */
diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c
index 786145fc084..eafeff61540 100644
--- a/mps/code/prmci3xc.c
+++ b/mps/code/prmci3xc.c
@@ -34,8 +34,13 @@ SRCID(prmci3li, "$Id$");
MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
{
+ THREAD_STATE_S *threadState;
+
+ AVER(mfc != NULL);
AVER(NONNEGATIVE(regnum));
AVER(regnum <= 7);
+ AVER(mfc->threadState != NULL);
+ threadState = mfc->threadState;
/* .source.i486 */
/* .assume.regref */
@@ -44,17 +49,17 @@ MRef Prmci3AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
config.h. */
/* TODO: The current arrangement of the fix operation (taking a Ref *)
forces us to pun these registers (actually `int` on LII3GC). We can
- suppress the warning my casting through `char *` and this might make
+ suppress the warning by casting through `void *` and this might make
it safe, but does it really? RB 2012-09-10 */
switch (regnum) {
- case 0: return (MRef)((char *)&mfc->threadState->__eax);
- case 1: return (MRef)((char *)&mfc->threadState->__ecx);
- case 2: return (MRef)((char *)&mfc->threadState->__edx);
- case 3: return (MRef)((char *)&mfc->threadState->__ebx);
- case 4: return (MRef)((char *)&mfc->threadState->__esp);
- case 5: return (MRef)((char *)&mfc->threadState->__ebp);
- case 6: return (MRef)((char *)&mfc->threadState->__esi);
- case 7: return (MRef)((char *)&mfc->threadState->__edi);
+ case 0: return (void *)&threadState->__eax;
+ case 1: return (void *)&threadState->__ecx;
+ case 2: return (void *)&threadState->__edx;
+ case 3: return (void *)&threadState->__ebx;
+ case 4: return (void *)&threadState->__esp;
+ case 5: return (void *)&threadState->__ebp;
+ case 6: return (void *)&threadState->__esi;
+ case 7: return (void *)&threadState->__edi;
default:
NOTREACHED;
return NULL; /* Avoids compiler warning. */
diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c
index 2f8bf9afc62..c00c1359014 100644
--- a/mps/code/prmci6li.c
+++ b/mps/code/prmci6li.c
@@ -33,12 +33,19 @@ SRCID(prmci6li, "$Id$");
MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
{
- Word *gregs;
+ MRef gregs;
+ AVER(mfc != NULL);
AVER(NONNEGATIVE(regnum));
AVER(regnum <= 15);
+ AVER(mfc->ucontext != NULL);
- gregs = (Word *)&mfc->ucontext->uc_mcontext.gregs;
+ /* TODO: The current arrangement of the fix operation (taking a Ref *)
+ forces us to pun these registers (actually `int` on LII6GC). We can
+ suppress the warning by casting through `void *` and this might make
+ it safe, but does it really? RB 2012-09-10 */
+ AVER(sizeof(void *) == sizeof(*mfc->ucontext->uc_mcontext.gregs));
+ gregs = (void *)mfc->ucontext->uc_mcontext.gregs;
/* .assume.regref */
/* The register numbers (REG_RAX etc.) are defined in
diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c
index 02ccb840b6c..131447cd0cc 100644
--- a/mps/code/prmci6xc.c
+++ b/mps/code/prmci6xc.c
@@ -31,33 +31,38 @@ SRCID(prmci6li, "$Id$");
MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum)
{
+ THREAD_STATE_S *threadState;
+
+ AVER(mfc != NULL);
AVER(NONNEGATIVE(regnum));
AVER(regnum <= 15);
+ AVER(mfc->threadState != NULL);
+ threadState = mfc->threadState;
/* .assume.regref */
/* The register numbers (REG_RAX etc.) are defined in
but only if _XOPEN_SOURCE is defined: see .feature.xc in
config.h. */
/* MRef (a Word *) is not compatible with pointers to the register
- types (actually a __uint64_t). To avoid aliasing optimization
- problems, The registers are cast through (char *) */
+ types (actually a __uint64_t). To avoid aliasing optimization
+ problems, the registers are cast through (void *). */
switch (regnum) {
- case 0: return (MRef)((char *)&mfc->threadState->__rax);
- case 1: return (MRef)((char *)&mfc->threadState->__rcx);
- case 2: return (MRef)((char *)&mfc->threadState->__rdx);
- case 3: return (MRef)((char *)&mfc->threadState->__rbx);
- case 4: return (MRef)((char *)&mfc->threadState->__rsp);
- case 5: return (MRef)((char *)&mfc->threadState->__rbp);
- case 6: return (MRef)((char *)&mfc->threadState->__rsi);
- case 7: return (MRef)((char *)&mfc->threadState->__rdi);
- case 8: return (MRef)((char *)&mfc->threadState->__r8);
- case 9: return (MRef)((char *)&mfc->threadState->__r9);
- case 10: return (MRef)((char *)&mfc->threadState->__r10);
- case 11: return (MRef)((char *)&mfc->threadState->__r11);
- case 12: return (MRef)((char *)&mfc->threadState->__r12);
- case 13: return (MRef)((char *)&mfc->threadState->__r13);
- case 14: return (MRef)((char *)&mfc->threadState->__r14);
- case 15: return (MRef)((char *)&mfc->threadState->__r15);
+ case 0: return (void *)&threadState->__rax;
+ case 1: return (void *)&threadState->__rcx;
+ case 2: return (void *)&threadState->__rdx;
+ case 3: return (void *)&threadState->__rbx;
+ case 4: return (void *)&threadState->__rsp;
+ case 5: return (void *)&threadState->__rbp;
+ case 6: return (void *)&threadState->__rsi;
+ case 7: return (void *)&threadState->__rdi;
+ case 8: return (void *)&threadState->__r8;
+ case 9: return (void *)&threadState->__r9;
+ case 10: return (void *)&threadState->__r10;
+ case 11: return (void *)&threadState->__r11;
+ case 12: return (void *)&threadState->__r12;
+ case 13: return (void *)&threadState->__r13;
+ case 14: return (void *)&threadState->__r14;
+ case 15: return (void *)&threadState->__r15;
default:
NOTREACHED;
return NULL; /* Avoids compiler warning. */
diff --git a/mps/code/protan.c b/mps/code/protan.c
index 86afa645e63..0e8abf8ac7e 100644
--- a/mps/code/protan.c
+++ b/mps/code/protan.c
@@ -1,7 +1,7 @@
/* protan.c: ANSI MEMORY PROTECTION
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
*
* DESIGN
@@ -63,22 +63,9 @@ void ProtSync(Arena arena)
}
-/* ProtTramp -- protection trampoline */
-
-void ProtTramp(void **rReturn, void *(*f)(void *, size_t),
- void *p, size_t s)
-{
- AVER(rReturn != NULL);
- AVER(FUNCHECK(f));
- /* Can't check p and s as they are interpreted by the client */
-
- *(rReturn) = (*(f))(p, s);
-}
-
-
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/protix.c b/mps/code/protix.c
index e79972af9e6..5b310333e84 100644
--- a/mps/code/protix.c
+++ b/mps/code/protix.c
@@ -1,7 +1,7 @@
/* protix.c: PROTECTION FOR UNIX
*
* $Id$
- * Copyright (c) 2001,2007 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* Somewhat generic across different Unix systems. Shared between
* Darwin (OS X), FreeBSD, and Linux.
@@ -111,28 +111,9 @@ void ProtSync(Arena arena)
}
-/* ProtTramp -- protection trampoline
- *
- * The protection trampoline is trivial under Unix, as there is
- * nothing that needs to be done in the dynamic context of the mutator in
- * order to catch faults. (Contrast this with Win32 Structured Exception
- * Handling.)
- */
-
-void ProtTramp(void **resultReturn, void *(*f)(void *, size_t),
- void *p, size_t s)
-{
- AVER(resultReturn != NULL);
- AVER(FUNCHECK(f));
- /* Can't check p and s as they are interpreted by the client */
-
- *resultReturn = (*f)(p, s);
-}
-
-
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2007 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/protw3.c b/mps/code/protw3.c
index 1f76f0a4e80..4ff3e85da42 100644
--- a/mps/code/protw3.c
+++ b/mps/code/protw3.c
@@ -1,7 +1,7 @@
/* protw3.c: PROTECTION FOR WIN32
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
@@ -128,27 +128,9 @@ void ProtSync(Arena arena)
}
-/* ProtTramp -- wrap a mutator thread in a Structured Exception Handler filter
- *
- * This was the method by which we installed an exception handler on Windows
- * prior to MPS 1.111. Now we are using Vectored Exception Handlers, so this
- * is deprecated and just calls through to the mutator function.
- */
-
-void ProtTramp(void **resultReturn, void *(*f)(void *, size_t),
- void *p, size_t s)
-{
- AVER(resultReturn != NULL);
- AVER(FUNCHECK(f));
- /* Can't check p and s as they are interpreted by the client */
-
- *resultReturn = f(p, s);
-}
-
-
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/protxc.c b/mps/code/protxc.c
index 62ade6ed81b..7e8f230d061 100644
--- a/mps/code/protxc.c
+++ b/mps/code/protxc.c
@@ -240,7 +240,7 @@ static void protCatchOne(void)
different size" warnings in GCC, for the XCI3GC build. */
mfcStruct.address = (Addr)(Word)request.code[1];
AVER(sizeof(*mfcStruct.threadState) == sizeof(THREAD_STATE_S));
- mfcStruct.threadState = (THREAD_STATE_S *)request.old_state;
+ mfcStruct.threadState = (void *)request.old_state;
if (ArenaAccess(mfcStruct.address,
AccessREAD | AccessWRITE,
@@ -279,6 +279,7 @@ static void protCatchOne(void)
* handler won't cause a deadlock.
*/
+ATTRIBUTE_NORETURN
static void *protCatchThread(void *p) {
UNUSED(p);
for (;;)
diff --git a/mps/code/qs.c b/mps/code/qs.c
index 8fb31ee0aab..0a90f14f069 100644
--- a/mps/code/qs.c
+++ b/mps/code/qs.c
@@ -50,7 +50,7 @@ static mps_addr_t isMoved(mps_addr_t object);
static void copy(mps_addr_t object, mps_addr_t to);
static void pad(mps_addr_t base, size_t size);
-struct mps_fmt_A_s fmt_A_s =
+static struct mps_fmt_A_s fmt_A_s =
{
(mps_align_t)4,
scan, skip, copy,
diff --git a/mps/code/ring.c b/mps/code/ring.c
index ff60149ce40..54902ec3818 100644
--- a/mps/code/ring.c
+++ b/mps/code/ring.c
@@ -1,7 +1,7 @@
/* ring.c: RING IMPLEMENTATION
*
* $Id$
- * Copyright (c) 2001,2003 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .intro: This is a portable implementation of Rings.
*
@@ -52,6 +52,16 @@ Bool RingIsSingle(Ring ring)
return (ring->next == ring);
}
+Size RingLength(Ring ring)
+{
+ Size size = 0;
+ Ring node, next;
+ AVERT(Ring, ring);
+ RING_FOR(node, ring, next)
+ ++ size;
+ return size;
+}
+
/* RingInit -- initialize a ring node
*/
@@ -131,7 +141,7 @@ Ring (RingPrev)(Ring ring)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2003 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/ring.h b/mps/code/ring.h
index d5b64076f6c..cbde6afe814 100644
--- a/mps/code/ring.h
+++ b/mps/code/ring.h
@@ -1,7 +1,7 @@
/* ring.h: RING INTERFACE
*
* $Id$
- * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2001 Global Graphics Software.
*/
@@ -30,6 +30,7 @@ typedef struct RingStruct { /* double-ended queue structure */
extern Bool RingCheck(Ring ring);
extern Bool RingCheckSingle(Ring ring);
extern Bool RingIsSingle(Ring ring);
+extern Size RingLength(Ring ring);
/* .ring.init: */
extern void (RingInit)(Ring ring);
@@ -115,7 +116,7 @@ extern Ring (RingPrev)(Ring ring);
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2013 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/sac.c b/mps/code/sac.c
index 435988cf867..3caf9ab893f 100644
--- a/mps/code/sac.c
+++ b/mps/code/sac.c
@@ -48,18 +48,20 @@ static Bool SACCheck(SAC sac)
CHECKL(esac->_middle > 0);
/* check classes above middle */
prevSize = esac->_middle;
- for (j = sac->middleIndex + 1, i = 0;
- j <= sac->classesCount; ++j, i += 2) {
+ for (j = sac->middleIndex + 1, i = 0; j < sac->classesCount; ++j, i += 2) {
CHECKL(prevSize < esac->_freelists[i]._size);
b = sacFreeListBlockCheck(&(esac->_freelists[i]));
if (!b) return b;
prevSize = esac->_freelists[i]._size;
}
/* check overlarge class */
- CHECKL(esac->_freelists[i-2]._size == SizeMAX);
- CHECKL(esac->_freelists[i-2]._count == 0);
- CHECKL(esac->_freelists[i-2]._count_max == 0);
- CHECKL(esac->_freelists[i-2]._blocks == NULL);
+ CHECKL(prevSize < esac->_freelists[i]._size);
+ b = sacFreeListBlockCheck(&(esac->_freelists[i]));
+ if (!b) return b;
+ CHECKL(esac->_freelists[i]._size == SizeMAX);
+ CHECKL(esac->_freelists[i]._count == 0);
+ CHECKL(esac->_freelists[i]._count_max == 0);
+ CHECKL(esac->_freelists[i]._blocks == NULL);
/* check classes below middle */
prevSize = esac->_middle;
for (j = sac->middleIndex, i = 1; j > 0; --j, i += 2) {
@@ -69,6 +71,7 @@ static Bool SACCheck(SAC sac)
prevSize = esac->_freelists[i]._size;
}
/* check smallest class */
+ CHECKL(prevSize > esac->_freelists[i]._size);
CHECKL(esac->_freelists[i]._size == 0);
b = sacFreeListBlockCheck(&(esac->_freelists[i]));
return b;
diff --git a/mps/code/seg.c b/mps/code/seg.c
index 2fb680c7094..cfa224a8368 100644
--- a/mps/code/seg.c
+++ b/mps/code/seg.c
@@ -605,7 +605,7 @@ Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi,
if (ResOK != res)
goto failMerge;
- EVENT3(SegMerge, segLo, segHi, withReservoirPermit);
+ EVENT3(SegMerge, segLo, segHi, BOOLOF(withReservoirPermit));
/* Deallocate segHi object */
ControlFree(arena, segHi, class->size);
AVERT(Seg, segLo);
@@ -1212,7 +1212,7 @@ static void gcSegSetGreyInternal(Seg seg, TraceSet oldGrey, TraceSet grey)
/* Internal method. Parameters are checked by caller */
gcseg = SegGCSeg(seg);
arena = PoolArena(SegPool(seg));
- seg->grey = grey;
+ seg->grey = BS_BITFIELD(Trace, grey);
/* If the segment is now grey and wasn't before, add it to the */
/* appropriate grey list so that TraceFindGrey can locate it */
@@ -1325,11 +1325,11 @@ static void gcSegSetWhite(Seg seg, TraceSet white)
AVERT_CRITICAL(Tract, tract);
AVER_CRITICAL(TRACT_SEG(&trseg, tract) && (trseg == seg));
- TractSetWhite(tract, white);
+ TractSetWhite(tract, BS_BITFIELD(Trace, white));
}
AVER(addr == limit);
- seg->white = white;
+ seg->white = BS_BITFIELD(Trace, white);
}
@@ -1362,7 +1362,7 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet)
arena = PoolArena(SegPool(seg));
oldRankSet = seg->rankSet;
- seg->rankSet = rankSet;
+ seg->rankSet = BS_BITFIELD(Rank, rankSet);
if (oldRankSet == RankSetEMPTY) {
if (rankSet != RankSetEMPTY) {
@@ -1439,7 +1439,7 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary)
wasShielded = (seg->rankSet != RankSetEMPTY && gcseg->summary != RefSetUNIV);
willbeShielded = (rankSet != RankSetEMPTY && summary != RefSetUNIV);
- seg->rankSet = rankSet;
+ seg->rankSet = BS_BITFIELD(Rank, rankSet);
gcseg->summary = summary;
if (willbeShielded && !wasShielded) {
diff --git a/mps/code/steptest.c b/mps/code/steptest.c
index c1af5b01089..deee85fef2e 100644
--- a/mps/code/steptest.c
+++ b/mps/code/steptest.c
@@ -71,19 +71,19 @@ static mps_addr_t ambigRoots[ambigRootsCOUNT];
/* Things we want to measure. Times are all in microseconds. */
-double alloc_time; /* Time spent allocating */
-double max_alloc_time; /* Max time taken to allocate one object */
-double step_time; /* Time spent in mps_arena_step returning 1 */
-double max_step_time; /* Max time of mps_arena_step returning 1 */
-double no_step_time; /* Time spent in mps_arena_step returning 0 */
-double max_no_step_time; /* Max time of mps_arena_step returning 0 */
+static double alloc_time; /* Time spent allocating */
+static double max_alloc_time; /* Max time taken to allocate one object */
+static double step_time; /* Time spent in mps_arena_step returning 1 */
+static double max_step_time; /* Max time of mps_arena_step returning 1 */
+static double no_step_time; /* Time spent in mps_arena_step returning 0 */
+static double max_no_step_time; /* Max time of mps_arena_step returning 0 */
-double total_clock_time; /* Time spent reading the clock */
-long clock_reads; /* Number of times clock is read */
-long steps; /* # of mps_arena_step calls returning 1 */
-long no_steps; /* # of mps_arena_step calls returning 0 */
-size_t alloc_bytes; /* # of bytes allocated */
-long commit_failures; /* # of times mps_commit fails */
+static double total_clock_time; /* Time spent reading the clock */
+static long clock_reads; /* Number of times clock is read */
+static long steps; /* # of mps_arena_step calls returning 1 */
+static long no_steps; /* # of mps_arena_step calls returning 0 */
+static size_t alloc_bytes; /* # of bytes allocated */
+static long commit_failures; /* # of times mps_commit fails */
/* Operating-system dependent timing. Defines two functions, void
@@ -151,7 +151,7 @@ static double my_clock(void)
* on thrush.ravenbrook.com on 2002-06-28, clock_time goes from 5.43
* us near process start to 7.45 us later). */
-double clock_time; /* current estimate of time to read the clock */
+static double clock_time; /* current estimate of time to read the clock */
/* take at least this many microseconds to set the clock */
#define CLOCK_TIME_SET 10000
diff --git a/mps/code/testlib.h b/mps/code/testlib.h
index 0912373031d..9c197cae839 100644
--- a/mps/code/testlib.h
+++ b/mps/code/testlib.h
@@ -28,13 +28,10 @@
/* Suppress Pelles C warnings at warning level 2 */
-/* Some of these are also done in config.h. */
+/* This is also done in config.h. */
#ifdef MPS_BUILD_PC
-/* "Structured Exception Handling is not portable." (mps_tramp). */
-#pragma warn(disable: 2008)
-
/* "Unreachable code" (AVER, if condition is constantly true). */
#pragma warn(disable: 2154)
diff --git a/mps/code/trace.c b/mps/code/trace.c
index 924badcd541..bd2b871fb11 100644
--- a/mps/code/trace.c
+++ b/mps/code/trace.c
@@ -390,6 +390,7 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet)
Seg seg;
Arena arena;
Res res;
+ Bool haveWhiteSegs = FALSE;
AVERT(Trace, trace);
AVER(condemnedSet != ZoneSetEMPTY);
@@ -415,7 +416,8 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet)
{
res = TraceAddWhite(trace, seg);
if(res != ResOK)
- return res;
+ goto failBegin;
+ haveWhiteSegs = TRUE;
}
} while (SegNext(&seg, arena, seg));
}
@@ -426,6 +428,10 @@ Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet)
AVER(ZoneSetSuper(condemnedSet, trace->white));
return ResOK;
+
+failBegin:
+ AVER(!haveWhiteSegs); /* See .whiten.fail. */
+ return res;
}
@@ -797,10 +803,11 @@ void TraceDestroy(Trace trace)
(TraceStatReclaim, trace,
trace->reclaimCount, trace->reclaimSize));
+ EVENT1(TraceDestroy, trace);
+
trace->sig = SigInvalid;
trace->arena->busyTraces = TraceSetDel(trace->arena->busyTraces, trace);
trace->arena->flippedTraces = TraceSetDel(trace->arena->flippedTraces, trace);
- EVENT1(TraceDestroy, trace);
}
@@ -1502,21 +1509,31 @@ static Res traceCondemnAll(Trace trace)
{
Res res;
Arena arena;
- Ring chainNode, nextChainNode;
+ Ring poolNode, nextPoolNode, chainNode, nextChainNode;
Bool haveWhiteSegs = FALSE;
arena = trace->arena;
AVERT(Arena, arena);
- /* Condemn all the chains. */
- RING_FOR(chainNode, &arena->chainRing, nextChainNode) {
- Chain chain = RING_ELT(Chain, chainRing, chainNode);
- AVERT(Chain, chain);
- res = ChainCondemnAll(chain, trace);
- if(res != ResOK)
- goto failBegin;
- haveWhiteSegs = TRUE;
+ /* Condemn all segments in pools with the GC attribute. */
+ RING_FOR(poolNode, &ArenaGlobals(arena)->poolRing, nextPoolNode) {
+ Pool pool = RING_ELT(Pool, arenaRing, poolNode);
+ AVERT(Pool, pool);
+
+ if (PoolHasAttr(pool, AttrGC)) {
+ Ring segNode, nextSegNode;
+ RING_FOR(segNode, PoolSegRing(pool), nextSegNode) {
+ Seg seg = SegOfPoolRing(segNode);
+ AVERT(Seg, seg);
+
+ res = TraceAddWhite(trace, seg);
+ if (res != ResOK)
+ goto failBegin;
+ haveWhiteSegs = TRUE;
+ }
+ }
}
+
/* Notify all the chains. */
RING_FOR(chainNode, &arena->chainRing, nextChainNode) {
Chain chain = RING_ELT(Chain, chainRing, chainNode);
@@ -1526,7 +1543,14 @@ static Res traceCondemnAll(Trace trace)
return ResOK;
failBegin:
- AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */
+ /* .whiten.fail: If we successfully whitened one or more segments,
+ * but failed to whiten them all, then the white sets would now be
+ * inconsistent. This can't happen in practice (at time of writing)
+ * because all PoolWhiten methods always succeed. If we ever have a
+ * pool class that fails to whiten a segment, then this assertion
+ * will be triggered. In that case, we'll have to recover here by
+ * blackening the segments again. */
+ AVER(!haveWhiteSegs);
return res;
}
@@ -1569,7 +1593,7 @@ static void TraceStartPoolGen(Chain chain, GenDesc desc, Bool top, Index i)
Ring n, nn;
RING_FOR(n, &desc->locusRing, nn) {
PoolGen gen = RING_ELT(PoolGen, genRing, n);
- EVENT11(TraceStartPoolGen, chain, top, i, desc,
+ EVENT11(TraceStartPoolGen, chain, BOOLOF(top), i, desc,
desc->capacity, desc->mortality, desc->zones,
gen->pool, gen->nr, gen->totalSize,
gen->newSizeAtCreate);
diff --git a/mps/code/version.c b/mps/code/version.c
index 9f8d644e47a..4771c8a7c69 100644
--- a/mps/code/version.c
+++ b/mps/code/version.c
@@ -47,6 +47,7 @@ SRCID(version, "$Id$");
* (assuming we've made any substantial changes to the library this year).
*/
+extern char MPSCopyrightNotice[];
char MPSCopyrightNotice[] =
"Portions copyright (c) 2010-2014 Ravenbrook Limited and Global Graphics Software.";
@@ -59,6 +60,7 @@ char MPSCopyrightNotice[] =
* see also guide.mps.version.
*/
+extern char MPSVersionString[];
char MPSVersionString[] =
"@(#)Ravenbrook MPS, "
"product." MPS_PROD_STRING ", " MPS_RELEASE ", platform." MPS_PF_STRING
diff --git a/mps/code/vman.c b/mps/code/vman.c
index 2b4f0c3ecb2..2e68118e27d 100644
--- a/mps/code/vman.c
+++ b/mps/code/vman.c
@@ -1,7 +1,7 @@
/* vman.c: ANSI VM: MALLOC-BASED PSEUDO MEMORY MAPPING
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
@@ -118,13 +118,13 @@ void VMDestroy(VM vm)
AVER(vm->mapped == (Size)0);
AVER(vm->reserved == AddrOffset(vm->base, vm->limit));
+ EVENT1(VMDestroy, vm);
+
memset((void *)vm->base, VMJunkBYTE, AddrOffset(vm->base, vm->limit));
free(vm->block);
vm->sig = SigInvalid;
- free(vm);
-
- EVENT1(VMDestroy, vm);
+ free(vm);
}
@@ -216,7 +216,7 @@ void VMUnmap(VM vm, Addr base, Addr limit)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/vmix.c b/mps/code/vmix.c
index 01a0919b820..0903a031a2c 100644
--- a/mps/code/vmix.c
+++ b/mps/code/vmix.c
@@ -1,7 +1,7 @@
/* vmix.c: VIRTUAL MEMORY MAPPING FOR UNIX (ISH)
*
* $Id$
- * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .purpose: This is the implementation of the virtual memory mapping
* interface (vm.h) for Unix-like operating systems. It was created
@@ -186,6 +186,8 @@ void VMDestroy(VM vm)
AVERT(VM, vm);
AVER(vm->mapped == (Size)0);
+ EVENT1(VMDestroy, vm);
+
/* This appears to be pretty pointless, since the descriptor */
/* page is about to vanish completely. However, munmap might fail */
/* for some reason, and this would ensure that it was still */
@@ -197,8 +199,6 @@ void VMDestroy(VM vm)
r = munmap((void *)vm,
(size_t)SizeAlignUp(sizeof(VMStruct), vm->align));
AVER(r == 0);
-
- EVENT1(VMDestroy, vm);
}
@@ -304,7 +304,7 @@ void VMUnmap(VM vm, Addr base, Addr limit)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2013 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/vmw3.c b/mps/code/vmw3.c
index e82f14ccd51..5be8153c73c 100644
--- a/mps/code/vmw3.c
+++ b/mps/code/vmw3.c
@@ -1,7 +1,7 @@
/* vmw3.c: VIRTUAL MEMORY MAPPING FOR WIN32
*
* $Id$
- * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
+ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* .design: See .
*
@@ -191,6 +191,8 @@ void VMDestroy(VM vm)
AVERT(VM, vm);
AVER(vm->mapped == 0);
+ EVENT1(VMDestroy, vm);
+
/* This appears to be pretty pointless, since the vm descriptor page
* is about to vanish completely. However, the VirtualFree might
* fail and it would be nice to have a dead sig there. */
@@ -201,7 +203,6 @@ void VMDestroy(VM vm)
b = VirtualFree((LPVOID)vm, (SIZE_T)0, MEM_RELEASE);
AVER(b != 0);
- EVENT1(VMDestroy, vm);
}
@@ -303,7 +304,7 @@ void VMUnmap(VM vm, Addr base, Addr limit)
/* C. COPYRIGHT AND LICENSE
*
- * Copyright (C) 2001-2002 Ravenbrook Limited .
+ * Copyright (C) 2001-2014 Ravenbrook Limited .
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
diff --git a/mps/code/walk.c b/mps/code/walk.c
index 3f7f67f99e1..4dd0d6b9e98 100644
--- a/mps/code/walk.c
+++ b/mps/code/walk.c
@@ -273,6 +273,20 @@ static Res rootWalk(Root root, void *p)
}
+/* rootWalkGrey -- make the root grey for the trace passed as p */
+
+static Res rootWalkGrey(Root root, void *p)
+{
+ Trace trace = p;
+
+ AVERT(Root, root);
+ AVERT(Trace, trace);
+
+ RootGrey(root, trace);
+ return ResOK;
+}
+
+
/* ArenaRootsWalk -- walks all the root in the arena */
static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f,
@@ -315,7 +329,7 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f,
}
/* Make the roots grey so that they are scanned */
- res = RootsIterate(arenaGlobals, (RootIterateFn)RootGrey, (void *)trace);
+ res = RootsIterate(arenaGlobals, rootWalkGrey, trace);
/* Make this trace look like any other trace. */
arena->flippedTraces = TraceSetAdd(arena->flippedTraces, trace);
@@ -330,6 +344,16 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f,
break;
}
+ /* Turn segments black again. */
+ if (SegFirst(&seg, arena)) {
+ do {
+ if (PoolHasAttr(SegPool(seg), AttrGC)) {
+ SegSetGrey(seg, TraceSetDel(SegGrey(seg), trace));
+ SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace));
+ }
+ } while (SegNext(&seg, arena, seg));
+ }
+
rootsStepClosureFinish(rsc);
/* Make this trace look like any other finished trace. */
trace->state = TraceFINISHED;
diff --git a/mps/design/prot.txt b/mps/design/prot.txt
index a56e53db096..0d30017fede 100644
--- a/mps/design/prot.txt
+++ b/mps/design/prot.txt
@@ -47,10 +47,6 @@ forbidden. A request to forbid read accesses (that is, ``AccessREAD``
is set) may also forbid write accesses, but read accesses will not be
forbidden unless ``AccessREAD`` is set.
-``void ProtTramp(void **resultReturn, void *(*f)(void *, size_t), void *p, size_t s)``
-
-_`.if.tramp`: [undocumented]
-
``void ProtSync(Space space)``
_`.if.sync`: ``ProtSync()`` is called to ensure that the actual
diff --git a/mps/design/protli.txt b/mps/design/protli.txt
index a5cc1d57a15..9b0958ac191 100644
--- a/mps/design/protli.txt
+++ b/mps/design/protli.txt
@@ -88,11 +88,6 @@ underlying object).
_`.fun.sync`: ``ProtSync()`` does nothing in this implementation as
``ProtSet()`` sets the protection without any delay.
-_`.fun.tramp`: The protection trampoline, ``ProtTramp()``, is trivial
-under Linux, as there is nothing that needs to be done in the dynamic
-context of the mutator in order to catch faults. (Contrast this with
-Win32 Structured Exception Handling.)
-
Threads
-------
diff --git a/mps/design/protsu.txt b/mps/design/protsu.txt
index 616d9134c88..1bd57e1004a 100644
--- a/mps/design/protsu.txt
+++ b/mps/design/protsu.txt
@@ -110,11 +110,6 @@ access that is compatible with the access of the underlying object).
_`.fun.sync`: ``ProtSync()``. This does nothing in this implementation
as ProtSet sets the protection without any delay.
-_`.fun.tramp`: ``ProtTramp()``. The protection trampoline is trivial
-under SunOS, as there is nothing that needs to be done in the dynamic
-context of the mutator in order to catch faults. (Contrast this with
-Win32 Structured Exception Handling.)
-
Document History
----------------
diff --git a/mps/design/range.txt b/mps/design/range.txt
index bf0f924430e..1b42d69ac22 100644
--- a/mps/design/range.txt
+++ b/mps/design/range.txt
@@ -51,7 +51,7 @@ between ``base`` (inclusive) and ``limit`` (exclusive). It must be the
case that ``base <= limit``. If ``base == limit`` then the range is
empty.
-``void RangeInitCopy(Range dest, Range src)``
+``void RangeCopy(Range dest, Range src)``
Initialize ``dest`` to be a copy of ``src``.
diff --git a/mps/design/type.txt b/mps/design/type.txt
index 6ce0da3c035..baee04ef3d2 100644
--- a/mps/design/type.txt
+++ b/mps/design/type.txt
@@ -151,6 +151,14 @@ compared ``w3i3mv\hi\amcss.exe`` running with and without the macro
for ``BoolCheck`` on the PC Aaron. "With" ran in 97.7% of the time
(averaged over 3 runs).
+_`.bool.bitfield`: When a Boolean needs to be stored in a bitfield,
+the type of the bitfield must be ``unsigned:1``, not ``Bool:1``.
+(That's because the two values of the type ``Bool:1`` are ``0`` and
+``-1``, which means that assigning ``TRUE`` would require a sign
+conversion.) To avoid warnings about loss of data from GCC with the
+``-Wconversion`` option, ``misc.h`` provides the ``BOOLOF`` macro for
+coercing a value to an unsigned single-bit field.
+
``typedef unsigned BufferMode``
@@ -235,7 +243,8 @@ objects.
``typedef Size Epoch``
_`.epoch`: An ``Epoch`` is a count of the number of flips that have
-occurred. It is used in the implementation of location dependencies.
+occurred, in which objects may have moved. It is used in the
+implementation of location dependencies.
``Epoch`` is converted to ``mps_word_t`` in the MPS C Interface, as a
field of ``mps_ld_s``.
@@ -351,7 +360,7 @@ references must be scanned in order to respect the properties of
references of the ranks. Therefore they are declared explicitly with
their integer values.
-.. note:: Could ``Rank`` be a ``short``?
+.. note:: Could ``Rank`` be an ``unsigned short`` or ``unsigned char``?
.. note::
@@ -459,30 +468,35 @@ create a valid registered constant root that contains any references.
become invalid; but you can't add them afterwards because the root is
supposed to be constant.)
-_`.rootmode.conv.c`: ``RootMode`` is converted to ``mps_rm_t`` in the MPS C
-Interface.
+_`.rootmode.conv.c`: ``RootMode`` is converted to ``mps_rm_t`` in the
+MPS C Interface.
``typedef int RootVar``
-_`.rootvar`: The type ``RootVar`` is the type of the
-discriminator for the union within ``RootStruct``.
+_`.rootvar`: The type ``RootVar`` is the type of the discriminator for
+the union within ``RootStruct``.
``typedef int SegPrefKind``
-_`.segprefkind`: The type ``SegPrefKind`` expresses a preference about
-where the arena should place a segment. It takes one of the following
+_`.segprefkind`: The type ``SegPrefKind`` expresses a preference for
+addresses within an address space. It takes one of the following
values:
================== ====================================================
Kind Description
================== ====================================================
-``SegPrefHigh`` Place the segment high in the address space.
-``SegPrefLow`` Place the segment low in the address space.
-``SegPrefZoneSet`` Place the segment in specified zones.
+``SegPrefHigh`` Prefer high addresses.
+``SegPrefLow`` Prefer low addresses.
+``SegPrefZoneSet`` Prefer addresses in specified zones.
================== ====================================================
+.. note::
+
+ The name is misleading as this is used to refer to address
+ preferences in general, not just addresses of segments.
+
``typedef unsigned Serial``
@@ -490,9 +504,8 @@ _`.serial`: A ``Serial`` is a number which is assigned to a structure
when it is initialized. The serial number is taken from a field in the
parent structure, which is incremented. Thus, every instance of a
structure has a unique "name" which is a path of structures from the
-global root. For example::
-
- space[3].pool[5].buffer[2]
+global root. For example, "the third arena's fifth pool's second
+buffer".
Why? Consistency checking, debugging, and logging. Not well thought
out.
@@ -509,6 +522,8 @@ right-hand operand of the ``<<`` or ``>>`` operators) is intended, to
make the code clear. It should also be used for structure fields which
have this use.
+.. note:: Could ``Shift`` be an ``unsigned short`` or ``unsigned char``?
+
``typedef unsigned long Sig``
@@ -640,7 +655,7 @@ _`.word.ops`: ``WordIsAligned()``, ``WordAlignUp()``,
``typedef Word ZoneSet``
_`.zoneset`: ``ZoneSet`` is a conservative approximation to a set of
-zone. See design.mps.refset_.
+zones. See design.mps.refset_.
Abstract types
diff --git a/mps/manual/source/design/.p4ignore b/mps/manual/source/design/.p4ignore
index 0e9be69cee0..2457ad19192 100644
--- a/mps/manual/source/design/.p4ignore
+++ b/mps/manual/source/design/.p4ignore
@@ -1,5 +1,6 @@
# The files in this directory are generated by the "mps" extension to Sphinx,
# except the index and the "old designs" index.
*.rst
+*.svg
!index.rst
!old.rst
diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py
index 57959f1ea0c..230594e9392 100644
--- a/mps/manual/source/extensions/mps/designs.py
+++ b/mps/manual/source/extensions/mps/designs.py
@@ -22,10 +22,11 @@ TYPES = '''
Arena Attr Bool BootBlock BT Buffer BufferMode Byte Chain Chunk
Clock Compare Count Epoch FindDelete Format FrameState Fun Globals
Index Land LD Lock Message MessageType MutatorFaultContext Page
- Pointer Pool PThreadext Range Rank RankSet Ref Res Reservoir Ring
- Root RootMode RootVar ScanState Seg SegBuf SegPref SegPrefKind
- Serial Shift Sig Size Space SplayNode SplayTree StackContext
- Thread Trace TraceId TraceSet ULongest VM Word ZoneSet
+ Pointer Pool PThreadext Range Rank RankSet Ref RefSet Res
+ Reservoir Ring Root RootMode RootVar ScanState Seg SegBuf SegPref
+ SegPrefKind Serial Shift Sig Size Space SplayNode SplayTree
+ StackContext Thread Trace TraceId TraceSet TraceStartWhy
+ TraceState ULongest VM Word ZoneSet
'''
diff --git a/mps/manual/source/pool/awl.rst b/mps/manual/source/pool/awl.rst
index 4128339227a..094335ba3b8 100644
--- a/mps/manual/source/pool/awl.rst
+++ b/mps/manual/source/pool/awl.rst
@@ -282,11 +282,10 @@ the format of objects allocated in it:
that it does not look like an aligned pointer.
"Aligned pointer" means a word whose numeric value (that is, its
- value when treated as an unsigned integer) is a multiple of the
- architecture's :term:`natural alignment` (see
- :c:macro:`MPS_PF_ALIGN`). If you're using a 32-bit architecture,
- that means that an aligned pointer is a multiple of 4 and its bottom
- two bits are both zero.
+ value when treated as an unsigned integer) is a multiple of the size
+ of a pointer. If you're using a 64-bit architecture, that means that
+ an aligned pointer is a multiple of 8 and its bottom three bits are
+ zero.
The bottom line is that references from an object in an AWL pool
must be untagged and aligned, and integers must be tagged with a
diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst
index 433525f7362..361cd41c0b5 100644
--- a/mps/manual/source/pool/mv.rst
+++ b/mps/manual/source/pool/mv.rst
@@ -75,17 +75,19 @@ MV interface
When creating an MV pool, :c:func:`mps_pool_create_k` may take
three :term:`keyword arguments`:
- * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the
- :term:`size` of segment that the pool will request from the
- :term:`arena`.
+ * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`,
+ default 65536) is the :term:`size` of segment that the pool will
+ request from the :term:`arena`.
- * :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32) is the
- predicted mean size of blocks that will be allocated from the
- pool.
+ * :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32)
+ is the predicted mean size of blocks that will be allocated from
+ the pool. This value must be smaller than, or equal to, the
+ value for :c:macro:`MPS_KEY_EXTEND_BY`.
- * :c:macro:`MPS_KEY_MAX_SIZE` (type :c:type:`size_t`, default 65536) is the
- predicted maximum size of blocks that will be allocated from the
- pool.
+ * :c:macro:`MPS_KEY_MAX_SIZE` (type :c:type:`size_t`,
+ default 65536) is the predicted maximum size of blocks that will
+ be allocated from the pool. This value must be larger than, or
+ equal to, the value for :c:macro:`MPS_KEY_EXTEND_BY`.
The mean and maximum sizes are *hints* to the MPS: the pool will be
less efficient if these are wrong, but nothing will break.
diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst
index 294b6545b91..18cc8ed72e9 100644
--- a/mps/manual/source/release.rst
+++ b/mps/manual/source/release.rst
@@ -27,6 +27,45 @@ New features
calling :c:func:`mps_pool_create_k`.
+Interface changes
+.................
+
+#. There is now a default value (currently 1 \ :term:`megabyte`) for
+ the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument to
+ :c:func:`mps_arena_create_k` when creating a virtual memory arena.
+ See :c:func:`mps_arena_class_vm`.
+
+
+Other changes
+.............
+
+#. The :ref:`pool-ams` pool class no longer triggers the assertion
+ ``!AMS_IS_INVALID_COLOUR(seg, i)`` under rare circumstances
+ (namely, detaching an :term:`allocation point` from a :term:`grey`
+ segment when :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` is
+ ``FALSE``). See job001549_.
+
+ .. _job001549: https://www.ravenbrook.com/project/mps/issue/job001549/
+
+#. :c:func:`mps_arena_roots_walk` no longer triggers an assertion
+ failure when run twice in succession. See job003496_.
+
+ .. _job003496: https://www.ravenbrook.com/project/mps/issue/job003496/
+
+#. The alignment of :ref:`pool-awl` pools is now configurable via the
+ object format, as documented, and is no longer always
+ :c:macro:`MPS_PF_ALIGN`. See job003745_.
+
+ .. _job003745: https://www.ravenbrook.com/project/mps/issue/job003745/
+
+#. :program:`mpseventtxt` now successfully processes a telemetry log
+ containing multiple labels associated with the same address. See
+ job003756_.
+
+ .. _job003756: https://www.ravenbrook.com/project/mps/issue/job003756/
+
+
+
.. _release-notes-1.113:
Release 1.113.0
diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst
index 5220ece4007..1925117cc84 100644
--- a/mps/manual/source/topic/arena.rst
+++ b/mps/manual/source/topic/arena.rst
@@ -233,18 +233,18 @@ Virtual memory arenas
more efficient.
When creating a virtual memory arena, :c:func:`mps_arena_create_k`
- requires one :term:`keyword argument`:
+ accepts one :term:`keyword argument` on all platforms:
- * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`). is the
- initial amount of virtual address space, in :term:`bytes (1)`,
- that the arena will reserve (this space is initially reserved so
- that the arena can subsequently use it without interference from
- other parts of the program, but most of it is not committed, so
- it doesn't require any RAM or backing store). The arena may
- allocate more virtual address space beyond this initial
- reservation as and when it deems it necessary. The MPS is most
- efficient if you reserve an address space that is several times
- larger than your peak memory usage.
+ * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`, default
+ 2\ :superscript:`20`) is the initial amount of virtual address
+ space, in :term:`bytes (1)`, that the arena will reserve (this
+ space is initially reserved so that the arena can subsequently
+ use it without interference from other parts of the program, but
+ most of it is not committed, so it doesn't require any RAM or
+ backing store). The arena may allocate more virtual address
+ space beyond this initial reservation as and when it deems it
+ necessary. The MPS is most efficient if you reserve an address
+ space that is several times larger than your peak memory usage.
.. note::
@@ -252,8 +252,8 @@ Virtual memory arenas
more times it has to extend its address space, the less
efficient garbage collection will become.
- An optional :term:`keyword argument` may be passed, but is
- only used on the Windows operating system:
+ A second optional :term:`keyword argument` may be passed, but it
+ only has any effect on the Windows operating system:
* :c:macro:`MPS_KEY_VMW3_TOP_DOWN` (type :c:type:`mps_bool_t`). If
true, the arena will allocate address space starting at the
@@ -273,8 +273,9 @@ Virtual memory arenas
If the MPS fails to allocate memory for the internal arena
structures, :c:func:`mps_arena_create_k` returns
- :c:macro:`MPS_RES_MEMORY`. Either ``size`` was far too small or
- the operating system refused to provide enough memory.
+ :c:macro:`MPS_RES_MEMORY`. Either :c:macro:`MPS_KEY_ARENA_SIZE`
+ was far too small or the operating system refused to provide
+ enough memory.
For example::
diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst
index 97ec2f73216..6b2e9452fc2 100644
--- a/mps/manual/source/topic/error.rst
+++ b/mps/manual/source/topic/error.rst
@@ -232,7 +232,7 @@ assertion that is listed here but for which you discovered a different
cause), please :ref:`let us know ` so that we can improve
this documentation.
-``arenavm.c: BTIsResRange(vmChunk->pageTableMapped, 0, chunk->pageTablePages)``
+``sa.c: BTIsResRange(sa->mapped, 0, sa->length)``
The client program called :c:func:`mps_arena_destroy` without
having destroyed all pools in that arena first. (The assertion is
@@ -283,14 +283,6 @@ this documentation.
point` instead.
-``poolams.c: !AMS_IS_INVALID_COLOUR(seg, i)``
-
- The client program failed to :term:`fix` a reference to an object
- in an :ref:`pool-ams` pool, violating the :term:`tri-colour
- invariant` that the MPS depends on for the correctness of its
- :term:`incremental garbage collection`.
-
-
``poolams.c: AMS_ALLOCED(seg, i)``
The client program tried to :term:`fix` a :term:`reference` to a
diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst
index 91ac7ae6462..b9bbdae61bb 100644
--- a/mps/manual/source/topic/format.rst
+++ b/mps/manual/source/topic/format.rst
@@ -468,22 +468,27 @@ Object format introspection
Each :term:`pool class` determines for which objects the stepper
function is called. Typically, all validly formatted objects are
- visited. During a :term:`trace` this will in general be only the
- :term:`black` objects, though the :ref:`pool-lo` pool, for
- example, will walk all objects since they are validly formatted
- whether they are black or :term:`white`. :term:`Padding objects`
- may be visited at the pool class's discretion: the :term:`client
- program` should handle this case.
-
- .. seealso::
-
- :ref:`topic-arena`.
+ visited. :term:`Padding objects` may be visited at the pool
+ class's discretion: the stepper function must handle this
+ case.
.. note::
This function is intended for heap analysis, tuning, and
debugging, not for frequent use in production.
+ .. warning::
+
+ If a garbage collection is currently in progress (that is, if
+ the arena is in the :term:`clamped ` or
+ :term:`unclamped state`), then only objects that are known to
+ be currently valid are visited.
+
+ For the most reliable results, ensure the arena is in the
+ :term:`parked state` by calling :c:func:`mps_arena_park`
+ before calling this function (and release it by calling
+ :c:func:`mps_arena_release` afterwards, if desired).
+
.. c:type:: void (*mps_formatted_objects_stepper_t)(mps_addr_t addr, mps_fmt_t fmt, mps_pool_t pool, void *p, size_t s)
@@ -515,10 +520,6 @@ Object format introspection
It must not access other memory managed by the MPS.
- .. seealso::
-
- :ref:`topic-arena`.
-
Obsolete interface
------------------
diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst
index f33de3516ce..a665aaf4b07 100644
--- a/mps/manual/source/topic/telemetry.rst
+++ b/mps/manual/source/topic/telemetry.rst
@@ -110,7 +110,7 @@ The MPS writes the telemetry to the log in an encoded form for speed.
It can be decoded using the :ref:`mpseventcnv `
and :ref:`mpseventtxt ` programs::
- (gdb) shell mpseventcnv | mpseventtxt | sort > mpsio.txt
+ (gdb) shell mpseventcnv | sort | mpseventtxt > mpsio.txt
The ``sort`` is useful because the events are not necessarily written
to the telemetry file in time order, but each event starts with a
diff --git a/mps/procedure/release-build.rst b/mps/procedure/release-build.rst
index bdce60df4ca..ee65b5f645d 100644
--- a/mps/procedure/release-build.rst
+++ b/mps/procedure/release-build.rst
@@ -47,7 +47,7 @@ All relative paths are relative to
1.111.0), where *VERSION* is the number of the version you’re
releasing, and *N* is the first unused release number (starting at
zero). Look in the index of releases (``release/index.html``) for
- existing release numbers for your version::
+ existing release numbers for your version. ::
VERSION=A.BBB
RELEASE=$VERSION.N
@@ -111,7 +111,7 @@ Run the script ``tool/release``, passing the options:
* ``-P mps`` — project name
* ``-b BRANCH`` — branch to make the release from: for example ``version/1.113``
* ``-C CHANGELEVEL`` — changelevel at which to make the release
-* ``-d "DESCRIPTION"`` — changelevel at which to make the release
+* ``-d "DESCRIPTION"`` — description of the release
* ``-y`` — yes, really make the release
If omitted, the project and branch are deduced from the current
@@ -231,8 +231,6 @@ A. References
Ravenbrook Limited; 2008-10-16;
http://info.ravenbrook.com/mail/2008/10/16/13-08-20/0.txt
-.. [Sphinx] "Sphinx: Python document generator"; http://sphinx-doc.org/
-
B. Document History
-------------------
diff --git a/mps/test/function/122.c b/mps/test/function/122.c
index 6f1465289cb..4ba0c0c6090 100644
--- a/mps/test/function/122.c
+++ b/mps/test/function/122.c
@@ -133,7 +133,7 @@ static void test(void)
die(allocrdumb(&a[0], aplo, 64, mps_rank_exact()), "alloc");
die(allocrdumb(&a[1], apamc, 64, mps_rank_exact()), "alloc");
die(allocrdumb(&a[3], apawl, 64, mps_rank_exact()), "alloc");
- a[2] = (mycell *)((int)a[3] | 4);
+ a[2] = (mycell *)((mps_word_t)a[3] | 4);
die(allocrdumb(&b[0], aplo, 64, mps_rank_exact()), "alloc");
die(allocrdumb(&b[1], apamc, 64, mps_rank_exact()), "alloc");
diff --git a/mps/test/function/40.c b/mps/test/function/40.c
index c57f8c62ba5..5257e1fcfc1 100644
--- a/mps/test/function/40.c
+++ b/mps/test/function/40.c
@@ -66,7 +66,7 @@ static void test(void)
comment("%i of 10.", i);
UC;
z[i] = allocone(ap, 1, 1);
- if (i % 8 == 0) { z[i] = (mycell *) ((int)z[i] + 4); } /* error to scan this! */
+ if (i % 8 == 0) { z[i] = (mycell *) ((mps_word_t)z[i] + 4); } /* error to scan this! */
}
for (i=0; i<1000; i++) {
diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing
index 64c72fe2982..fc00f37feb0 100644
--- a/mps/test/testsets/passing
+++ b/mps/test/testsets/passing
@@ -110,7 +110,7 @@ function/118.c
function/119.c
function/120.c
% function/121.c -- job003495
-% function/122.c -- job003496
+function/122.c
function/123.c
function/124.c
function/125.c
diff --git a/mps/tool/branch b/mps/tool/branch
index f60eccae235..5a3b4d8652d 100755
--- a/mps/tool/branch
+++ b/mps/tool/branch
@@ -46,10 +46,10 @@ CHILD_RE = r'(?:{}|{})$'.format(TASK_BRANCH_RE, VERSION_BRANCH_RE)
TASK_BRANCH_ENTRY = '''
- {child}
+ {date}/{task}
Changes
- {description}
- In development (diffs).
+ {desc_html}
+ Active (diffs).
'''
@@ -60,7 +60,7 @@ VERSION_BRANCH_ENTRY = '''
None.
{parent}/...@{changelevel}
- {description}
+ {desc_html}
base
@@ -154,13 +154,16 @@ def main(argv):
m = re.match(CHILD_RE, args.child)
if not m:
raise Error(fmt("Invalid child: {child}"))
- if args.customer != m.group(3):
+ if not args.task and args.customer != m.group(3):
raise Error(fmt("Customer mismatch between {parent} and {child}."))
args.date, args.task, _, args.version = m.groups()
if not args.description:
args.description = fmt("Branching {parent} to {child}.")
print(fmt("description={description}"))
+ args.desc_html = re.sub(r'\b(job\d{6})\b',
+ fmt(r'\1'),
+ args.description)
# Create the branch specification
args.branch = fmt('{project}/{child}')
diff --git a/mps/tool/p4-bisect b/mps/tool/p4-bisect
new file mode 100755
index 00000000000..2886d823c59
--- /dev/null
+++ b/mps/tool/p4-bisect
@@ -0,0 +1,176 @@
+#!/usr/bin/env python
+#
+#
+# Ravenbrook
+#
+#
+# P4-BISECT -- FIND CHANGE THAT INTRODUCED A BUG
+#
+# Gareth Rees, Ravenbrook Limited, 2014-04-14
+#
+#
+# 1. INTRODUCTION
+#
+# This script automates (or partly automates) the process of finding,
+# by binary search, the change that introduced a bug.
+#
+# The interface is modelled closely on git-bisect(1).
+
+import argparse
+from functools import partial
+import json
+from os import unlink
+import p4
+import subprocess
+import sys
+
+BISECT_FILE = '.p4-bisect'
+
+def error(msg):
+ sys.stderr.write(msg)
+ sys.stderr.write('\n')
+ exit(1)
+
+def sync(*filespecs):
+ try:
+ p4.do('sync', *filespecs)
+ except p4.Error as e:
+ if 'file(s) up-to-date' not in e.args[0]:
+ raise
+
+class State(object):
+ def __init__(self, **d):
+ self.filespec = d['filespec']
+ self.changes = d['changes']
+ if 'current' in d:
+ self.current = d['current']
+
+ @classmethod
+ def load(cls):
+ try:
+ with open(BISECT_FILE, 'r') as f:
+ return cls(**json.load(f))
+ except FileNotFoundError:
+ error("p4-bisect not in progress here.")
+
+ def save(self):
+ with open(BISECT_FILE, 'w') as f:
+ json.dump(vars(self), f)
+
+ def update(self):
+ n = len(self.changes)
+ if n == 0:
+ print("no changes remaining.".format(**vars(self)))
+ elif n == 1:
+ print("{} change remaining: {}.".format(n, self.changes[0]))
+ elif n == 2:
+ print("{} changes remaining: [{}, {}]."
+ .format(n, self.changes[0], self.changes[-1]))
+ else:
+ print("{} changes remaining: [{}, ..., {}]."
+ .format(n, self.changes[0], self.changes[-1]))
+ if n > 0:
+ self.current = self.changes[n // 2]
+ print("Syncing to changelevel {current}.".format(**vars(self)))
+ sync(*['{}@{}'.format(f, self.current) for f in self.filespec])
+ self.save()
+
+def help(parser, args):
+ parser.print_help()
+
+def start(args):
+ args.filespec = args.filespec or ['...']
+ changes = sorted(int(c['change']) for c in p4.run('changes', *args.filespec))
+ if not changes:
+ error("No changes for {}".format(' '.join(args.filespec)))
+ if args.good is None:
+ args.good = changes[0]
+ if args.bad is None:
+ args.bad = changes[-1]
+ state = State(filespec=args.filespec,
+ changes=[c for c in changes if args.good <= c <= args.bad])
+ state.update()
+
+def good(args):
+ state = State.load()
+ print("Change {current} good.".format(**vars(state)))
+ state.changes = [c for c in state.changes if c > state.current]
+ state.update()
+
+def bad(args):
+ state = State.load()
+ print("Change {current} bad.".format(**vars(state)))
+ state.changes = [c for c in state.changes if c < state.current]
+ state.update()
+
+def skip(args):
+ state = State.load()
+ print("Skipping change {current}.".format(**vars(state)))
+ state.changes.remove(state.current)
+ state.update()
+
+def reset(args):
+ state = State.load()
+ sync(*state.filespec)
+ unlink(BISECT_FILE)
+
+def run(args):
+ while True:
+ state = State.load()
+ if not state.changes:
+ break
+ result = subprocess.call([args.cmd] + args.args)
+ if result == 0:
+ good(None)
+ elif result == 125:
+ skip(None)
+ elif 0 < result < 128:
+ bad(None)
+ else:
+ exit(result)
+
+def main(argv):
+ parser = argparse.ArgumentParser(
+ prog='p4-bisect', epilog='For help on CMD, use p4-bisect CMD -h')
+ parser.set_defaults(func=partial(help, parser))
+ subparsers = parser.add_subparsers()
+ a = subparsers.add_parser
+
+ help_parser = a('help', help='show this help message')
+ help_parser.set_defaults(func=partial(help, parser))
+
+ start_parser = a('start', help='start a p4-bisect session')
+ aa = start_parser.add_argument
+ start_parser.add_argument('-f', '--filespec', action='append',
+ help='filespec(s) to search')
+ start_parser.add_argument('good', nargs='?', type=int,
+ help='known good changelevel')
+ start_parser.add_argument('bad', nargs='?', type=int,
+ help='known bad changelevel')
+ start_parser.set_defaults(func=start)
+
+ good_parser = a('good', help='declare current revision good')
+ good_parser.set_defaults(func=good)
+
+ bad_parser = a('bad', help='declare current revision bad')
+ bad_parser.set_defaults(func=bad)
+
+ skip_parser = a('skip', help='skip current revision')
+ skip_parser.set_defaults(func=skip)
+
+ reset_parser = a('reset', help='finish p4-bisect session')
+ reset_parser.set_defaults(func=reset)
+
+ run_parser = a('run', help='run p4-bisect session automatically')
+ run_parser.add_argument('cmd',
+ help='command that determines if current '
+ 'changelevel is good or bad')
+ run_parser.add_argument('args', nargs=argparse.REMAINDER,
+ help='arguments to pass to cmd')
+ run_parser.set_defaults(func=run)
+
+ args = parser.parse_args(argv[1:])
+ args.func(args)
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/mps/tool/testcases.txt b/mps/tool/testcases.txt
index ba49ae6f717..0c536f0a336 100644
--- a/mps/tool/testcases.txt
+++ b/mps/tool/testcases.txt
@@ -5,9 +5,9 @@ abqtest
airtest
amcss =P
amcsshe =P
-amcssth =B =P =T job003561, job003703
-amsss =B job001549
-amssshe =B job001549
+amcssth =P =T
+amsss =P
+amssshe =P
apss
arenacv
awlut
@@ -20,7 +20,7 @@ exposet0 =P
expt825
fbmtest
finalcv =P
-finaltest
+finaltest =P
fotest
gcbench =N benchmark
locbwcss
diff --git a/mps/tool/testopendylan b/mps/tool/testopendylan
index 9c18938ef1e..0c185ff2fd0 100755
--- a/mps/tool/testopendylan
+++ b/mps/tool/testopendylan
@@ -20,8 +20,21 @@
# 2. CONFIGURATION
-# MPS sources we are testing against
-MPS=$(cd -- "$(dirname "$0")/.." && pwd)
+# Check command-line argument
+GC=$1
+case "$GC" in
+ mps)
+ # MPS sources we are testing against
+ CONFIGURE=--with-gc-path=$(cd -- "$(dirname "$0")/.." && pwd)
+ ;;
+ boehm)
+ CONFIGURE=
+ ;;
+ *)
+ echo "Backend '$GC' not supported: choose mps or boehm."
+ exit 1
+esac
+
# OpenDylan version for bootstrapping
VERSION=2013.2
@@ -30,7 +43,7 @@ VERSION=2013.2
REMOTE=https://github.com/dylan-lang/opendylan.git
# Directory to put everything in
-TESTDIR="$PWD/.test"
+TESTDIR="$PWD/.test/$GC"
mkdir -p -- "$TESTDIR"
cd -- "$TESTDIR"
@@ -104,7 +117,7 @@ if [ -f "$REPO/Makefile" ]; then
else (
cd -- "$REPO" &&
./autogen.sh &&
- ./configure --with-mps="$MPS" --prefix="$PREFIX"
+ ./configure --with-gc="$GC" --prefix="$PREFIX" $CONFIGURE
) fi
(
cd -- "$REPO" &&
@@ -128,6 +141,9 @@ else (
#
# 2014-03-20 GDR Created based on [WELCOME].
#
+# 2014-04-14 GDR Updated configure args based on revised build
+# instructions [WELCOME].
+#
#
# C. COPYRIGHT AND LICENCE
#