diff --git a/mps/.p4ignore b/mps/.p4ignore
new file mode 100644
index 00000000000..04531d440b8
--- /dev/null
+++ b/mps/.p4ignore
@@ -0,0 +1,5 @@
+# Mac OS X Finder turds
+.DS_Store
+# Patch results
+*.orig
+*.rej
diff --git a/mps/code/arena.c b/mps/code/arena.c
index 1273502968d..904ed0701ac 100644
--- a/mps/code/arena.c
+++ b/mps/code/arena.c
@@ -205,15 +205,16 @@ failGlobalsInit:
}
-/* ArenaCreateV -- create the arena and call initializers */
+/* ArenaCreate -- create the arena and call initializers */
-Res ArenaCreateV(Arena *arenaReturn, ArenaClass class, va_list args)
+Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
{
Arena arena;
Res res;
AVER(arenaReturn != NULL);
AVERT(ArenaClass, class);
+ AVER(ArgListCheck(args));
/* We must initialise the event subsystem very early, because event logging
will start as soon as anything interesting happens and expect to write
diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c
index d76a6d9a485..bfe640bfc05 100644
--- a/mps/code/arenacl.c
+++ b/mps/code/arenacl.c
@@ -186,8 +186,7 @@ static void ClientChunkFinish(Chunk chunk)
* .arena.init: Once the arena has been allocated, we call ArenaInit
* to do the generic part of init.
*/
-static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class,
- va_list args)
+static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
{
Arena arena;
ClientArena clientArena;
@@ -196,11 +195,32 @@ static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class,
Addr base, limit, chunkBase;
Res res;
Chunk chunk;
-
- size = va_arg(args, Size);
- base = va_arg(args, Addr);
+ mps_arg_s arg;
+
AVER(arenaReturn != NULL);
AVER((ArenaClass)mps_arena_class_cl() == class);
+ AVER(ArgListCheck(args));
+
+ if (ArgPick(&arg, args, MPS_KEY_ARENA_SIZE)) {
+ size = arg.val.size;
+ if (ArgPick(&arg, args, MPS_KEY_ARENA_CL_ADDR))
+ base = arg.val.addr;
+ else {
+ res = ResPARAM;
+ goto failParam;
+ }
+ } else if (ArgPick(&arg, args, MPS_KEY_VARARGS)) {
+ if (ArgPick(&arg, args, MPS_KEY_ARENA_CL_ADDR)) {
+ res = ResPARAM;
+ goto failParam;
+ }
+ size = va_arg(arg.val.varargs, Size);
+ base = va_arg(arg.val.varargs, Addr);
+ } else {
+ res = ResPARAM;
+ goto failParam;
+ }
+
AVER(base != (Addr)0);
clArenaSize = SizeAlignUp(sizeof(ClientArenaStruct), MPS_PF_ALIGN);
@@ -243,6 +263,7 @@ static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class,
failChunkCreate:
ArenaFinish(arena);
+failParam:
return res;
}
diff --git a/mps/code/arenacv.c b/mps/code/arenacv.c
index 5055cf421a6..7228ea80ee7 100644
--- a/mps/code/arenacv.c
+++ b/mps/code/arenacv.c
@@ -340,7 +340,7 @@ static void testPageTable(ArenaClass class, ...)
va_list args;
va_start(args, class);
- die(ArenaCreateV(&arena, class, args), "ArenaCreate");
+ die(ArenaCreate(&arena, class, args), "ArenaCreate");
va_end(args);
die(PoolCreate(&pool, arena, PoolClassMV(),
diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c
index ca2188c04b1..b0c2d732dc1 100644
--- a/mps/code/arenavm.c
+++ b/mps/code/arenavm.c
@@ -445,7 +445,7 @@ static void VMChunkFinish(Chunk chunk)
* .arena.init: Once the arena has been allocated, we call ArenaInit
* to do the generic part of init.
*/
-static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, va_list args)
+static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
{
Size userSize; /* size requested by user */
Size chunkSize; /* size actually created */
@@ -456,15 +456,26 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, va_list args)
Index gen;
VM arenaVM;
Chunk chunk;
-
- userSize = va_arg(args, Size);
+ mps_arg_s arg;
+
AVER(arenaReturn != NULL);
AVER(class == VMArenaClassGet() || class == VMNZArenaClassGet());
+ AVER(ArgListCheck(args));
+
+ if (ArgPick(&arg, args, MPS_KEY_ARENA_SIZE))
+ userSize = arg.val.size;
+ else if (ArgPick(&arg, args, MPS_KEY_VARARGS))
+ userSize = va_arg(arg.val.varargs, Size);
+ else {
+ res = ResPARAM;
+ goto failVMCreate;
+ }
+
AVER(userSize > 0);
/* Create a VM to hold the arena and map it. */
vmArenaSize = SizeAlignUp(sizeof(VMArenaStruct), MPS_PF_ALIGN);
- res = VMCreate(&arenaVM, vmArenaSize);
+ res = VMCreate(&arenaVM, vmArenaSize, args);
if (res != ResOK)
goto failVMCreate;
res = VMMap(arenaVM, VMBase(arenaVM), VMLimit(arenaVM));
diff --git a/mps/code/arg.c b/mps/code/arg.c
new file mode 100644
index 00000000000..425bbf6c496
--- /dev/null
+++ b/mps/code/arg.c
@@ -0,0 +1,126 @@
+/* arg.c: ARGUMENT LISTS
+ *
+ * $Id: //info.ravenbrook.com/project/mps/custom/cet/main/code/bt.c#1 $
+ * Copyright (c) 2013 Ravenbrook Limited. See end of file for license.
+ */
+
+#include "config.h"
+#include "check.h"
+#include "mpm.h"
+
+SRCID(arg, "$Id$");
+
+#define KeySig ((Sig)0x519CE333) /* SIGnature KEYyy */
+typedef struct mps_key_s {
+ Sig sig;
+ const char *name;
+ Bool (*check)(Arg arg);
+} KeyStruct;
+
+
+static Bool ArgCheckCant(Arg arg) {
+ UNUSED(arg);
+ return TRUE;
+}
+
+const KeyStruct _mps_key_varargs = {KeySig, "VARARGS", ArgCheckCant};
+
+
+/* KeyCheck -- check the validity of an argument key */
+
+Bool KeyCheck(Key key)
+{
+ CHECKS(Key, key);
+ CHECKL(key->name != NULL);
+ CHECKL(FUNCHECK(key->check));
+ return TRUE;
+}
+
+
+Bool ArgCheck(Arg arg)
+{
+ CHECKL(arg != NULL);
+ CHECKD(Key, arg->key);
+ CHECKL(arg->key->check(arg));
+ return TRUE;
+}
+
+
+/* ArgCheck -- check the validity of an argument list */
+
+Bool ArgListCheck(ArgList args)
+{
+ Index i;
+ CHECKL(args != NULL);
+ /* FIXME: Maximum plausible length? */
+ for (i = 0; args[i].key != MPS_KEY_ARGS_END; ++i)
+ CHECKL(ArgCheck(&args[i]));
+ return TRUE;
+}
+
+
+Bool ArgPick(mps_arg_s *argOut, mps_arg_s args[], Key key) {
+ Index i;
+
+ AVER(argOut != NULL);
+ AVERT(Arg, args);
+ AVERT(Key, key);
+
+ for (i = 0; args[i].key != MPS_KEY_ARGS_END; ++i)
+ if (args[i].key == key)
+ goto found;
+ return FALSE;
+
+found:
+ *argOut = args[i];
+ for(;;) {
+ args[i] = args[i + 1];
+ if (args[i].key == MPS_KEY_ARGS_END)
+ break;
+ ++i;
+ }
+
+ return TRUE;
+}
+
+
+/* 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/mpm.h b/mps/code/mpm.h
index 049cbf65343..98e35b54189 100644
--- a/mps/code/mpm.h
+++ b/mps/code/mpm.h
@@ -130,6 +130,14 @@ extern int (AddrComp)(Addr a, Addr b, Size size);
extern Bool ResIsAllocFailure(Res res);
+/* Argument Lists */
+
+extern Bool KeyCheck(Key key);
+extern Bool ArgCheck(Arg arg);
+extern Bool ArgListCheck(ArgList args);
+extern Bool ArgPick(ArgStruct *argOut, ArgList args, Key key);
+
+
/* Logs and Powers
*
* SizeIsP2 returns TRUE if and only if size is a non-negative integer
@@ -485,7 +493,7 @@ extern AbstractArenaClass AbstractArenaClassGet(void);
extern Bool ArenaClassCheck(ArenaClass class);
extern Bool ArenaCheck(Arena arena);
-extern Res ArenaCreateV(Arena *arenaReturn, ArenaClass class, va_list args);
+extern Res ArenaCreate(Arena *arenaReturn, ArenaClass class, mps_arg_s args[]);
extern void ArenaDestroy(Arena arena);
extern Res ArenaInit(Arena arena, ArenaClass class);
extern void ArenaFinish(Arena arena);
@@ -966,7 +974,7 @@ extern Res RootsIterate(Globals arena, RootIterateFn f, void *p);
extern Align VMAlign(VM vm);
extern Bool VMCheck(VM vm);
-extern Res VMCreate(VM *VMReturn, Size size);
+extern Res VMCreate(VM *VMReturn, Size size, mps_arg_s args[]);
extern void VMDestroy(VM vm);
extern Addr VMBase(VM vm);
extern Addr VMLimit(VM vm);
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index f7cf9a023ea..8df2e91dbb0 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -44,6 +44,11 @@ typedef void *Pointer; /* */
typedef Word Clock; /* processor time */
typedef MPS_T_ULONGEST ULongest; /* */
+typedef mps_arg_s ArgStruct;
+typedef mps_arg_s *Arg;
+typedef mps_arg_s *ArgList;
+typedef mps_key_t Key;
+
typedef Word RefSet; /* design.mps.refset */
typedef Word ZoneSet; /* design.mps.refset */
typedef unsigned Rank;
@@ -109,7 +114,7 @@ typedef struct StackContextStruct *StackContext;
/* Arena*Method -- see */
typedef Res (*ArenaInitMethod)(Arena *arenaReturn,
- ArenaClass class, va_list args);
+ ArenaClass class, mps_arg_s args[]);
typedef void (*ArenaFinishMethod)(Arena arena);
typedef Size (*ArenaReservedMethod)(Arena arena);
typedef void (*ArenaSpareCommitExceededMethod)(Arena arena);
diff --git a/mps/code/mps.c b/mps/code/mps.c
index 1d1d93100d0..99cf42d5a33 100644
--- a/mps/code/mps.c
+++ b/mps/code/mps.c
@@ -70,6 +70,7 @@
#include "ss.c"
#include "version.c"
#include "table.c"
+#include "arg.c"
/* Additional pool classes */
diff --git a/mps/code/mps.h b/mps/code/mps.h
index 0c2cc9dbd53..0b450da9f5b 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -62,6 +62,7 @@ typedef struct mps_alloc_pattern_s
*mps_alloc_pattern_t; /* allocation patterns */
typedef struct mps_frame_s
*mps_frame_t; /* allocation frames */
+typedef const struct mps_key_s *mps_key_t; /* argument key */
/* Concrete Types */
@@ -91,6 +92,36 @@ enum {
MPS_RES_PARAM /* illegal user parameter value */
};
+/* Keyword argument lists */
+
+typedef struct mps_arg_s {
+ mps_key_t key;
+ union {
+ mps_bool_t b;
+ char c;
+ const char *string;
+ int i;
+ unsigned u;
+ long l;
+ unsigned long ul;
+ size_t size;
+ va_list varargs;
+ mps_addr_t addr;
+ } val;
+} mps_arg_s;
+
+#define MPS_KEY_ARGS_END NULL
+
+/* FIXME: This shouldn't be here */
+extern const struct mps_key_s _mps_key_vmw3_top_down;
+#define MPS_KEY_VMW3_TOP_DOWN (&_mps_key_vmw3_top_down)
+
+extern const struct mps_key_s _mps_key_varargs;
+#define MPS_KEY_VARARGS (&_mps_key_varargs)
+extern const struct mps_key_s _mps_key_arena_size;
+#define MPS_KEY_ARENA_SIZE (&_mps_key_arena_size)
+
+
/* Keep in sync with
* */
/* Not meant to be used by clients, they should use the macros below. */
@@ -272,6 +303,8 @@ extern mps_bool_t mps_arena_step(mps_arena_t, double, double);
extern mps_res_t mps_arena_create(mps_arena_t *, mps_arena_class_t, ...);
extern mps_res_t mps_arena_create_v(mps_arena_t *, mps_arena_class_t, va_list);
+extern mps_res_t mps_arena_create_args(mps_arena_t *, mps_arena_class_t,
+ mps_arg_s []);
extern void mps_arena_destroy(mps_arena_t);
extern size_t mps_arena_reserved(mps_arena_t);
diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj
index 375124a990f..134e873becc 100644
--- a/mps/code/mps.xcodeproj/project.pbxproj
+++ b/mps/code/mps.xcodeproj/project.pbxproj
@@ -182,6 +182,7 @@
3124CAFB156BE82000753214 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
3124CAFC156BE82900753214 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
3150AE53156ABA2500A6E22A /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
+ 317B3C2B1731830100F9A469 /* arg.c in Sources */ = {isa = PBXBuildFile; fileRef = 317B3C2A1731830100F9A469 /* arg.c */; };
31A47BA4156C1E130039B1C2 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; };
31D60007156D3C6200337B26 /* segsmss.c in Sources */ = {isa = PBXBuildFile; fileRef = 31D60006156D3C5F00337B26 /* segsmss.c */; };
31D60008156D3C7400337B26 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
@@ -1049,6 +1050,7 @@
3124CAE4156BE6D500753214 /* fmthe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmthe.c; sourceTree = ""; };
3124CAEB156BE7F300753214 /* amcss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = amcss; sourceTree = BUILT_PRODUCTS_DIR; };
3124CAF5156BE81100753214 /* amcss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amcss.c; sourceTree = ""; };
+ 317B3C2A1731830100F9A469 /* arg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arg.c; sourceTree = ""; };
31A47BA3156C1E130039B1C2 /* mps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mps.c; sourceTree = ""; };
31A47BA5156C1E5E0039B1C2 /* ssixi3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssixi3.c; sourceTree = ""; };
31D60006156D3C5F00337B26 /* segsmss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = segsmss.c; sourceTree = ""; };
@@ -1568,6 +1570,7 @@
31EEAC05156AB27B00714D05 /* arena.c */,
31EEAC06156AB27B00714D05 /* arenacl.c */,
31EEAC03156AB23A00714D05 /* arenavm.c */,
+ 317B3C2A1731830100F9A469 /* arg.c */,
31EEAC3F156AB32500714D05 /* boot.c */,
31EEAC27156AB2F200714D05 /* bt.c */,
31EEAC19156AB2B200714D05 /* buffer.c */,
@@ -2690,6 +2693,7 @@
buildActionMask = 2147483647;
files = (
31A47BA4156C1E130039B1C2 /* mps.c in Sources */,
+ 317B3C2B1731830100F9A469 /* arg.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/mps/code/mpsacl.h b/mps/code/mpsacl.h
index 62a8952ba83..ec7a21c027a 100644
--- a/mps/code/mpsacl.h
+++ b/mps/code/mpsacl.h
@@ -9,6 +9,9 @@
#include "mps.h"
+/* Client arena base address argument */
+extern const struct mps_key_s _mps_key_arena_cl_addr;
+#define MPS_KEY_ARENA_CL_ADDR (&_mps_key_arena_cl_addr)
extern mps_arena_class_t mps_arena_class_cl(void);
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 435b4fbc0c6..15f44a24ff1 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -52,6 +52,10 @@
#include "sac.h"
#include "chain.h"
+#include
+#include
+
+
SRCID(mpsi, "$Id$");
@@ -311,11 +315,14 @@ mps_res_t mps_arena_create(mps_arena_t *mps_arena_o,
mps_arena_class_t mps_arena_class, ...)
{
mps_res_t res;
- va_list args;
+ mps_arg_s args[2];
+
+ args[0].key = MPS_KEY_VARARGS;
+ va_start(args[0].val.varargs, mps_arena_class);
+ args[1].key = MPS_KEY_ARGS_END;
+ res = mps_arena_create_args(mps_arena_o, mps_arena_class, args);
+ va_end(args[0].val.varargs);
- va_start(args, mps_arena_class);
- res = mps_arena_create_v(mps_arena_o, mps_arena_class, args);
- va_end(args);
return res;
}
@@ -323,7 +330,25 @@ mps_res_t mps_arena_create(mps_arena_t *mps_arena_o,
/* mps_arena_create_v -- create an arena object */
mps_res_t mps_arena_create_v(mps_arena_t *mps_arena_o,
- mps_arena_class_t arena_class, va_list args)
+ mps_arena_class_t arena_class,
+ va_list varargs)
+{
+ mps_arg_s args[2];
+
+ args[0].key = MPS_KEY_VARARGS;
+ /* FIXME: va_copy not available in C89 */
+ memcpy(&args[0].val.varargs, &varargs, sizeof(va_list));
+ args[1].key = MPS_KEY_ARGS_END;
+
+ return mps_arena_create_args(mps_arena_o, arena_class, args);
+}
+
+
+/* mps_arena_create_arg -- create an arena object */
+
+mps_res_t mps_arena_create_args(mps_arena_t *mps_arena_o,
+ mps_arena_class_t arena_class,
+ mps_arg_s mps_args[])
{
Arena arena;
Res res;
@@ -334,15 +359,21 @@ mps_res_t mps_arena_create_v(mps_arena_t *mps_arena_o,
AVER(mps_arena_o != NULL);
- res = ArenaCreateV(&arena, arena_class, args);
+ res = ArenaCreate(&arena, arena_class, mps_args);
if (res != ResOK)
return res;
+ /* FIXME: Consider doing this
+ if (args[0].key != MPS_KEY_ARGS_END)
+ return MPS_RES_PARAM;
+ */
+
ArenaLeave(arena);
*mps_arena_o = (mps_arena_t)arena;
return MPS_RES_OK;
}
+
/* mps_arena_destroy -- destroy an arena object */
void mps_arena_destroy(mps_arena_t arena)
diff --git a/mps/code/vmix.c b/mps/code/vmix.c
index bc26b647dc8..f5b8aa681b3 100644
--- a/mps/code/vmix.c
+++ b/mps/code/vmix.c
@@ -98,9 +98,12 @@ Bool VMCheck(VM vm)
}
+Res VM
+
+
/* VMCreate -- reserve some virtual address space, and create a VM structure */
-Res VMCreate(VM *vmReturn, Size size)
+Res VMCreate(VM *vmReturn, Size size, mps_arg_s args[])
{
Align align;
VM vm;
@@ -109,6 +112,8 @@ Res VMCreate(VM *vmReturn, Size size)
Res res;
AVER(vmReturn != NULL);
+ AVERT(Arg, args);
+ UNUSED(args);
/* Find out the page size from the OS */
pagesize = getpagesize();