From 1bc62b27ef66fc2fea1d4d83648ea0176708d83e Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 2 May 2013 17:55:07 +0100 Subject: [PATCH] First draft of keyword arguments. mainly checking in in order to try working with git fusion on this branch. Copied from Perforce Change: 181538 ServerID: perforce.ravenbrook.com --- mps/.p4ignore | 5 + mps/code/arena.c | 5 +- mps/code/arenacl.c | 31 +++++- mps/code/arenacv.c | 2 +- mps/code/arenavm.c | 19 +++- mps/code/arg.c | 126 +++++++++++++++++++++++++ mps/code/mpm.h | 12 ++- mps/code/mpmtypes.h | 7 +- mps/code/mps.c | 1 + mps/code/mps.h | 33 +++++++ mps/code/mps.xcodeproj/project.pbxproj | 4 + mps/code/mpsacl.h | 3 + mps/code/mpsi.c | 43 +++++++-- mps/code/vmix.c | 7 +- 14 files changed, 276 insertions(+), 22 deletions(-) create mode 100644 mps/.p4ignore create mode 100644 mps/code/arg.c 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();