diff --git a/CHANGELOG_NEXT.md b/CHANGELOG_NEXT.md index a5e69e3c98..0b9eb24f72 100644 --- a/CHANGELOG_NEXT.md +++ b/CHANGELOG_NEXT.md @@ -109,6 +109,17 @@ This CHANGELOG describes the merged but unreleased changes. Please see [CHANGELO * Switch calling conventions based on the number of arguments to avoid limits on the number of arguments and to reduce stack usage. +* Values that reference counters reaching their maximum limit are immortalized to + prevent counter overflow. This can potentially cause memory leaks, but they + occur rarely and are a better choice than crashing. Since overflow is no longer + a concern, changing refCounter from int to uint16 reduces the size of 'Value_Header'. + +* Values often found at runtime, such as integers less than 100 are generate + staticaly and share. + +* Constant String, Int64, Bits64 and Double values are allocated statically as + imortal and shared. + #### Chez * Fixed CSE soundness bug that caused delayed expressions to sometimes be eagerly diff --git a/src/Compiler/RefC/RefC.idr b/src/Compiler/RefC/RefC.idr index 32199fe8bb..b155035ce0 100644 --- a/src/Compiler/RefC/RefC.idr +++ b/src/Compiler/RefC/RefC.idr @@ -142,23 +142,6 @@ cPrimType CharType = "Char" cPrimType DoubleType = "Double" cPrimType WorldType = "void" -cConstant : Constant -> String -cConstant (I x) = "idris2_mkInt64("++ showIntMin x ++")" -cConstant (I8 x) = "idris2_mkInt8(INT8_C("++ show x ++"))" -cConstant (I16 x) = "idris2_mkInt16(INT16_C("++ show x ++"))" -cConstant (I32 x) = "idris2_mkInt32(INT32_C("++ show x ++"))" -cConstant (I64 x) = "idris2_mkInt64("++ showInt64Min x ++")" -cConstant (BI x) = "(Value*)idris2_mkIntegerLiteral(\""++ show x ++"\")" -cConstant (B8 x) = "idris2_mkBits8(UINT8_C("++ show x ++"))" -cConstant (B16 x) = "idris2_mkBits16(UINT16_C("++ show x ++"))" -cConstant (B32 x) = "idris2_mkBits32(UINT32_C("++ show x ++"))" -cConstant (B64 x) = "idris2_mkBits64(UINT64_C("++ show x ++"))" -cConstant (Db x) = "idris2_mkDouble("++ show x ++")" -cConstant (Ch x) = "idris2_mkChar("++ escapeChar x ++")" -cConstant (Str x) = "(Value*)idris2_mkString("++ cStringQuoted x ++")" -cConstant (PrT t) = cPrimType t -cConstant WorldVal = "(Value*)NULL" - ||| Generate scheme for a primitive function. cOp : {0 arity : Nat} -> PrimFn arity -> Vect arity String -> String cOp (Neg ty) [x] = "idris2_negate_" ++ cPrimType ty ++ "(" ++ x ++ ")" @@ -211,6 +194,7 @@ data EnvTracker : Type where data FunctionDefinitions : Type where data IndentLevel : Type where data HeaderFiles : Type where +data ConstDef : Type where ReuseMap = SortedMap Name String Owned = SortedSet AVar @@ -457,6 +441,7 @@ mutual -> {auto e : Ref EnvTracker Env} -> {auto oft : Ref OutfileText Output} -> {auto il : Ref IndentLevel Nat} + -> {auto _ : Ref ConstDef (SortedMap Constant String)} -> Env -> String -> String -> List Int -> ANF -> TailPositionStatus -> Core () @@ -479,6 +464,7 @@ mutual -> {auto oft : Ref OutfileText Output} -> {auto il : Ref IndentLevel Nat} -> {auto e : Ref EnvTracker Env} + -> {auto _ : Ref ConstDef (SortedMap Constant String)} -> ANF -> TailPositionStatus -> Core String @@ -557,8 +543,8 @@ mutual "prim__void", "prim__os", "prim__codegen", "prim__onCollect", "prim__onCollectAny" ] case p of NS _ (UN (Basic pn)) => - unless (elem pn prims) $ throw $ InternalError $ "INTERNAL ERROR: Unknown primitive: " ++ cName p - _ => throw $ InternalError $ "INTERNAL ERROR: Unknown primitive: " ++ cName p + unless (elem pn prims) $ throw $ InternalError $ "[refc] Unknown primitive: " ++ cName p + _ => throw $ InternalError $ "[refc] Unknown primitive: " ++ cName p emit fc $ "// call to external primitive " ++ cName p pure $ "idris2_\{cName p}("++ showSep ", " (map varName args) ++")" @@ -635,7 +621,53 @@ mutual emit emptyFC "}" pure switchReturnVar - cStatementsFromANF (APrimVal fc c) _ = pure $ cConstant c + cStatementsFromANF (APrimVal fc (I x)) tailPosition = cStatementsFromANF (APrimVal fc (I64 $ cast x)) tailPosition + cStatementsFromANF (APrimVal fc c) _ = do + constdefs <- get ConstDef + case lookup c constdefs of + Just constid => constantName c constid -- the constant already booked. + Nothing => dyngen + where + constantName : Constant -> String -> Core String + constantName c n = case c of + I x => pure "((Value*)&idris2_constant_Int64_\{cCleanString $ show x})" + I64 x => pure "((Value*)&idris2_constant_Int64_\{cCleanString $ show x})" + B64 x => pure "((Value*)&idris2_constant_Bits64_\{show x})" + Db x => pure "((Value*)&idris2_constant_Double_\{cCleanString $ show x})" + Str x => pure "((Value*)&idris2_constant_String_\{n})" + _ => throw $ InternalError "[refc] Unsupported type of constant." + orStagen : Core String + orStagen = do + constdefs <- get ConstDef + constid <- case c of + Str _ => getNextCounter + _ => pure "" + -- booking the constant to generate later + put ConstDef $ insert c constid constdefs + constantName c constid + dyngen : Core String + dyngen = case c of + I8 x => pure "idris2_mkInt8(INT8_C(\{show x}))" + I16 x => pure "idris2_mkInt16(INT16_C(\{show x}))" + I32 x => pure "idris2_mkInt32(INT32_C(\{show x}))" + I64 x => if x >= 0 && x < 100 + then pure "(Value*)(&idris2_predefined_Int64[\{show x}])" + else orStagen + BI x => if x >= 0 && x < 100 + then pure "idris2_getPredefinedInteger(\{show x})" + else pure "idris2_mkIntegerLiteral(\"\{show x}\")" + B8 x => pure "idris2_mkBits8(UINT8_C(\{show x}))" + B16 x => pure "idris2_mkBits16(UINT16_C(\{show x}))" + B32 x => pure "idris2_mkBits32(UINT32_C(\{show x}))" + B64 x => if x >= 0 && x < 100 + then pure "(Value*)(&idris2_predefined_Bits64[\{show x}])" + else orStagen + Db _ => orStagen + Ch x => pure "idris2_mkChar(\{escapeChar x})" + Str _ => orStagen + PrT t => pure $ cPrimType t + _ => pure "NULL" + cStatementsFromANF (AErased fc) _ = pure "NULL" cStatementsFromANF (ACrash fc x) _ = pure "(NULL /* CRASH */)" @@ -760,6 +792,7 @@ additionalFFIStub name argTypes retType = createCFunctions : {auto c : Ref Ctxt Defs} -> {auto a : Ref ArgCounter Nat} + -> {auto _ : Ref ConstDef (SortedMap Constant String)} -> {auto f : Ref FunctionDefinitions (List String)} -> {auto oft : Ref OutfileText Output} -> {auto il : Ref IndentLevel Nat} @@ -856,17 +889,19 @@ createCFunctions n (MkAForeign ccs fargs ret) = do decreaseIndentation emit EmptyFC "}" - _ => assert_total $ idris_crash ("INTERNAL ERROR: FFI not found for " ++ cName n) + _ => throw $ InternalError "[refc] FFI not found for \{cName n}" -- not really total but this way this internal error does not contaminate everything else -createCFunctions n (MkAError exp) = assert_total $ idris_crash ("INTERNAL ERROR: Error with expression: " ++ show exp) +createCFunctions n (MkAError exp) = throw $ InternalError "[refc] Error with expression: \{show exp}" -- not really total but this way this internal error does not contaminate everything else + header : {auto c : Ref Ctxt Defs} -> {auto f : Ref FunctionDefinitions (List String)} -> {auto o : Ref OutfileText Output} -> {auto il : Ref IndentLevel Nat} -> {auto h : Ref HeaderFiles (SortedSet String)} + -> {auto _ : Ref ConstDef (SortedMap Constant String)} -> Core () header = do let initLines = """ @@ -875,9 +910,31 @@ header = do """ let headerFiles = SortedSet.toList !(get HeaderFiles) - let headerLines = map (\h => "#include <" ++ h ++ ">\n") headerFiles fns <- get FunctionDefinitions - update OutfileText (appendL ([initLines] ++ headerLines ++ ["\n// function definitions"] ++ fns)) + update OutfileText $ appendL $ + [initLines] ++ + map (\h => "#include <\{h}>\n") headerFiles ++ + ["\n// function definitions"] ++ + fns ++ + ["\n// constant value definitions"] ++ + map (uncurry genConstant) (SortedMap.toList !(get ConstDef)) + where + go : String -> String -> String -> String -> String + go suffix ty tag v = + "static Value_\{ty} const idris2_constant_\{ty}_\{cCleanString suffix}" + ++ " = { IDRIS2_STOCKVAL(\{tag}_TAG), \{v} };" + genConstant : Constant -> String -> String + genConstant c n = case c of + I x => let x' = show x in go x' "Int64" "INT64" (showIntMin x) + I64 x => let x' = show x in go x' "Int64" "INT64" (showInt64Min x) + B64 x => let x' = show x in go x' "Bits64" "BITS64" "UINT64_C(\{x'})" + Db x => let x' = show x in go x' "Double" "DOUBLE" x' + Str x => go n "String" "STRING" (cStringQuoted x) + _ => "/* bad constant */" + + + + footer : {auto il : Ref IndentLevel Nat} -> {auto f : Ref OutfileText Output} @@ -908,6 +965,7 @@ generateCSourceFile : {auto c : Ref Ctxt Defs} generateCSourceFile defs outn = do _ <- newRef ArgCounter 0 _ <- newRef FunctionDefinitions [] + _ <- newRef ConstDef Data.SortedMap.empty _ <- newRef OutfileText DList.Nil _ <- newRef HeaderFiles empty _ <- newRef IndentLevel 0 diff --git a/support/refc/_datatypes.h b/support/refc/_datatypes.h index cb661137ed..68ed3a58a2 100644 --- a/support/refc/_datatypes.h +++ b/support/refc/_datatypes.h @@ -31,9 +31,16 @@ #define CONDITION_TAG 31 typedef struct { - int refCounter; - int tag; + // Objects that reach the maximum reference count will be immortalized. + // This 'immortalization' feature is also utilized to prevent statically + // allocated objects from being destroyed. +#define IDRIS2_VP_REFCOUNTER_MAX UINT16_MAX + uint16_t refCounter; + uint8_t tag; + uint8_t reserved; } Value_header; +#define IDRIS2_STOCKVAL(t) \ + { IDRIS2_VP_REFCOUNTER_MAX, t, 0 } typedef struct { Value_header header; @@ -182,3 +189,5 @@ typedef struct { Value_header header; pthread_cond_t *cond; } Value_Condition; + +void idris2_dumpMemoryStats(void); diff --git a/support/refc/memoryManagement.c b/support/refc/memoryManagement.c index fbfe8cc4a1..157a212a1e 100644 --- a/support/refc/memoryManagement.c +++ b/support/refc/memoryManagement.c @@ -1,6 +1,47 @@ +#include + +#include "_datatypes.h" #include "refc_util.h" #include "runtime.h" +#if 0 +struct { + unsigned int n_newValue; + unsigned int n_newReference; + unsigned int n_actualNewReference; + unsigned int n_immortalized; + unsigned int n_removeReference; + unsigned int n_tried_to_kill_immortals; + unsigned int n_freed; +} idris2_memory_stat = {0, 0, 0, 0, 0, 00, 0}; +#define IDRIS2_INC_MEMSTAT(x) \ + do { \ + ++(idris2_memory_stat.x); \ + } while (0) + +void idris2_dumpMemoryStats(void) { + fprintf( + stderr, + "n_newValue = %u\n" + "n_newReference = %u\n" + "n_actualNewReference = %u\n" + "n_immortalized = %u\n" + "n_removeReference = %u\n" + "n_tried_to_kill_immortals = %u\n" + "n_freed = %u\n", + idris2_memory_stat.n_newValue, idris2_memory_stat.n_newReference, + idris2_memory_stat.n_actualNewReference, + idris2_memory_stat.n_immortalized, idris2_memory_stat.n_removeReference, + idris2_memory_stat.n_tried_to_kill_immortals, idris2_memory_stat.n_freed); +} + +#else +#define IDRIS2_INC_MEMSTAT(x) +// don't inline this, Because IDRIS2_MEMSTAT works only at compiling support +// libraries to suppressing overhead. +void idris2_dumpMemoryStats() {} +#endif + Value *idris2_newValue(size_t size) { #if !defined(_WIN32) && defined(__STDC_VERSION__) && \ (__STDC_VERSION__ >= 201112) /* C11 */ @@ -11,6 +52,7 @@ Value *idris2_newValue(size_t size) { Value *retVal = (Value *)malloc(size); #endif IDRIS2_REFC_VERIFY(retVal && !idris2_vp_is_unboxed(retVal), "malloc failed"); + IDRIS2_INC_MEMSTAT(n_newValue); retVal->header.refCounter = 1; retVal->header.tag = NO_TAG; return retVal; @@ -51,6 +93,9 @@ Value *idris2_mkBits32_Boxed(uint32_t i) { } Value *idris2_mkBits64(uint64_t i) { + if (i < 100) + return (Value *)&idris2_predefined_Bits64[i]; + Value_Bits64 *retVal = IDRIS2_NEW_VALUE(Value_Bits64); retVal->header.tag = BITS64_TAG; retVal->ui64 = i; @@ -65,6 +110,9 @@ Value *idris2_mkInt32_Boxed(int32_t i) { } Value *idris2_mkInt64(int64_t i) { + if (i >= 0 && i < 100) + return (Value *)&idris2_predefined_Int64[i]; + Value_Int64 *retVal = IDRIS2_NEW_VALUE(Value_Int64); retVal->header.tag = INT64_TAG; retVal->i64 = i; @@ -78,13 +126,16 @@ Value_Integer *idris2_mkInteger() { return retVal; } -Value_Integer *idris2_mkIntegerLiteral(char *i) { +Value *idris2_mkIntegerLiteral(char *i) { Value_Integer *retVal = idris2_mkInteger(); mpz_set_str(retVal->i, i, 10); - return retVal; + return (Value *)retVal; } Value_String *idris2_mkEmptyString(size_t l) { + if (l == 1) + return (Value_String *)&idris2_predefined_nullstring; + Value_String *retVal = IDRIS2_NEW_VALUE(Value_String); retVal->header.tag = STRING_TAG; retVal->str = malloc(l); @@ -93,6 +144,9 @@ Value_String *idris2_mkEmptyString(size_t l) { } Value_String *idris2_mkString(char *s) { + if (s[0] == '\0') + return (Value_String *)&idris2_predefined_nullstring; + Value_String *retVal = IDRIS2_NEW_VALUE(Value_String); int l = strlen(s); retVal->header.tag = STRING_TAG; @@ -135,25 +189,30 @@ Value_Array *idris2_makeArray(int length) { } Value *idris2_newReference(Value *source) { + IDRIS2_INC_MEMSTAT(n_newReference); // note that we explicitly allow NULL as source (for erased arguments) - if (source && !idris2_vp_is_unboxed(source)) { - source->header.refCounter++; + if (source && !idris2_vp_is_unboxed(source) && + source->header.refCounter != IDRIS2_VP_REFCOUNTER_MAX) { + IDRIS2_INC_MEMSTAT(n_actualNewReference); + ++source->header.refCounter; + if (source->header.refCounter == IDRIS2_VP_REFCOUNTER_MAX) + IDRIS2_INC_MEMSTAT(n_immortalized); } return source; } void idris2_removeReference(Value *elem) { - if (!elem || idris2_vp_is_unboxed(elem)) { + IDRIS2_INC_MEMSTAT(n_removeReference); + if (!elem || idris2_vp_is_unboxed(elem)) return; - } - - IDRIS2_REFC_VERIFY(elem->header.refCounter > 0, "refCounter %lld", - (long long)elem->header.refCounter); - // remove reference counter - elem->header.refCounter--; - if (elem->header.refCounter == 0) - // recursively remove all references to all children - { + else if (elem->header.refCounter == IDRIS2_VP_REFCOUNTER_MAX) { + IDRIS2_INC_MEMSTAT(n_tried_to_kill_immortals); + return; + } else if (elem->header.refCounter != 1) { + --elem->header.refCounter; + return; + } else { + IDRIS2_INC_MEMSTAT(n_freed); switch (elem->header.tag) { case BITS32_TAG: case BITS64_TAG: @@ -161,13 +220,14 @@ void idris2_removeReference(Value *elem) { case INT64_TAG: /* nothing to delete, added for sake of completeness */ break; - case INTEGER_TAG: { + case INTEGER_TAG: mpz_clear(((Value_Integer *)elem)->i); break; - } + case DOUBLE_TAG: /* nothing to delete, added for sake of completeness */ break; + case STRING_TAG: free(((Value_String *)elem)->str); break; @@ -225,3 +285,62 @@ void idris2_removeReference(Value *elem) { free(elem); } } + +// ///////////////////////////////////////////////////////////////////////// +// PRE-DEFINED VLAUES + +#define IDRIS2_MK_PREDEFINED_INT_10(t, n) \ + {IDRIS2_STOCKVAL(t), (n + 0)}, {IDRIS2_STOCKVAL(t), (n + 1)}, \ + {IDRIS2_STOCKVAL(t), (n + 2)}, {IDRIS2_STOCKVAL(t), (n + 3)}, \ + {IDRIS2_STOCKVAL(t), (n + 4)}, {IDRIS2_STOCKVAL(t), (n + 5)}, \ + {IDRIS2_STOCKVAL(t), (n + 6)}, {IDRIS2_STOCKVAL(t), (n + 7)}, \ + {IDRIS2_STOCKVAL(t), (n + 8)}, { \ + IDRIS2_STOCKVAL(t), (n + 9) \ + } +Value_Int64 const idris2_predefined_Int64[100] = { + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 0), + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 10), + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 20), + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 30), + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 40), + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 50), + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 60), + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 70), + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 80), + IDRIS2_MK_PREDEFINED_INT_10(INT64_TAG, 90)}; + +Value_Bits64 const idris2_predefined_Bits64[100] = { + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 0), + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 10), + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 20), + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 30), + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 40), + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 50), + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 60), + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 70), + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 80), + IDRIS2_MK_PREDEFINED_INT_10(BITS64_TAG, 90)}; + +Value_String const idris2_predefined_nullstring = {IDRIS2_STOCKVAL(STRING_TAG), + ""}; + +static bool idris2_predefined_integer_initialized = false; +Value_Integer idris2_predefined_Integer[100]; + +Value *idris2_getPredefinedInteger(int n) { + IDRIS2_REFC_VERIFY(n >= 0 && n < 100, + "invalid range of predefined integers."); + + if (!idris2_predefined_integer_initialized) { + idris2_predefined_integer_initialized = true; + for (int i = 0; i < 100; ++i) { + idris2_predefined_Integer[i].header.refCounter = IDRIS2_VP_REFCOUNTER_MAX; + idris2_predefined_Integer[i].header.tag = INTEGER_TAG; + idris2_predefined_Integer[i].header.reserved = 0; + + mpz_init(idris2_predefined_Integer[i].i); + mpz_set_si(idris2_predefined_Integer[i].i, i); + } + } + return (Value *)&idris2_predefined_Integer[n]; +} diff --git a/support/refc/memoryManagement.h b/support/refc/memoryManagement.h index a4aefe08b3..470ee4e78d 100644 --- a/support/refc/memoryManagement.h +++ b/support/refc/memoryManagement.h @@ -55,7 +55,7 @@ Value *idris2_mkInt32_Boxed(int32_t i); Value *idris2_mkInt64(int64_t i); Value_Integer *idris2_mkInteger(); -Value_Integer *idris2_mkIntegerLiteral(char *i); +Value *idris2_mkIntegerLiteral(char *i); Value_String *idris2_mkEmptyString(size_t l); Value_String *idris2_mkString(char *); @@ -64,3 +64,12 @@ Value_GCPointer *idris2_makeGCPointer(void *ptr_Raw, Value_Closure *onCollectFct); Value_Buffer *idris2_makeBuffer(void *buf); Value_Array *idris2_makeArray(int length); + +extern Value_Int64 const idris2_predefined_Int64[100]; +extern Value_Bits64 const idris2_predefined_Bits64[100]; +extern Value_Integer idris2_predefined_Integer[100]; +Value *idris2_getPredefinedInteger(int n); +extern Value_String const idris2_predefined_nullstring; + +// You need uncomment a debugging code in memoryManagement.c to use this. +void idris2_dumpMemoryStats(void); diff --git a/support/refc/prim.c b/support/refc/prim.c index 3b328650c1..6773987393 100644 --- a/support/refc/prim.c +++ b/support/refc/prim.c @@ -25,47 +25,35 @@ Value *idris2_Data_IORef_prim__writeIORef(Value *erased, Value *_ioref, // System operations // ----------------------------------- -static Value *osstring = NULL; - -Value *idris2_System_Info_prim__os(void) { - if (osstring == NULL) { - osstring = (Value *)idris2_mkString( +Value_String const idris2_predefined_osstring = {IDRIS2_STOCKVAL(STRING_TAG), #ifdef _WIN32 - "windows" + "windows" #elif _WIN64 - "windows" + "windows" #elif __APPLE__ || __MACH__ - "macOS" + "macOS" #elif __linux__ - "Linux" + "Linux" #elif __FreeBSD__ - "FreeBSD" + "FreeBSD" #elif __OpenBSD__ - "OpenBSD" + "OpenBSD" #elif __NetBSD__ - "NetBSD" + "NetBSD" #elif __DragonFly__ - "DragonFly" + "DragonFly" #elif __unix || __unix__ - "Unix" + "Unix" #else - "Other" + "Other" #endif - ); - } - return idris2_newReference(osstring); -} +}; // NOTE: The codegen is obviously determined at compile time, // so the backend should optimize it by replacing it with a constant. // It would probably also be useful for conditional compilation. -static Value *codegenstring = NULL; - -Value *idris2_System_Info_prim__codegen(void) { - if (codegenstring == NULL) - codegenstring = (Value *)idris2_mkString("refc"); - return idris2_newReference(codegenstring); -} +Value_String const idris2_predefined_codegenstring = { + IDRIS2_STOCKVAL(STRING_TAG), "refc"}; Value *idris2_crash(Value *msg) { Value_String *str = (Value_String *)msg; diff --git a/support/refc/prim.h b/support/refc/prim.h index 41a8f3911a..5ff20f969d 100644 --- a/support/refc/prim.h +++ b/support/refc/prim.h @@ -12,8 +12,11 @@ Value *idris2_Data_IORef_prim__writeIORef(Value *, Value *, Value *, Value *); // Sys -Value *idris2_System_Info_prim__os(void); -Value *idris2_System_Info_prim__codegen(void); +extern Value_String const idris2_predefined_osstring; +extern Value_String const idris2_predefined_codegenstring; +#define idris2_System_Info_prim__os() ((Value *)&idris2_predefined_osstring) +#define idris2_System_Info_prim__codegen() \ + ((Value *)&idris2_predefined_codegenstring) Value *idris2_crash(Value *msg); // Array diff --git a/support/refc/stringOps.c b/support/refc/stringOps.c index d27d513648..b9a21a134f 100644 --- a/support/refc/stringOps.c +++ b/support/refc/stringOps.c @@ -6,18 +6,14 @@ Value *tail(Value *input) { tailStr->header.tag = STRING_TAG; Value_String *s = (Value_String *)input; int l = strlen(s->str); - if (l != 0) { - tailStr->str = malloc(l); - IDRIS2_REFC_VERIFY(tailStr->str, "malloc failed"); - memset(tailStr->str, 0, l); - memcpy(tailStr->str, s->str + 1, l - 1); - return (Value *)tailStr; - } else { - tailStr->str = malloc(1); - IDRIS2_REFC_VERIFY(tailStr->str, "malloc failed"); - tailStr->str[0] = '\0'; - return (Value *)tailStr; - } + if (l == 0) + return (Value *)&idris2_predefined_nullstring; + + tailStr->str = malloc(l); + IDRIS2_REFC_VERIFY(tailStr->str, "malloc failed"); + memset(tailStr->str, 0, l); + memcpy(tailStr->str, s->str + 1, l - 1); + return (Value *)tailStr; } Value *reverse(Value *str) { diff --git a/tests/refc/callingConvention/expected b/tests/refc/callingConvention/expected index 740ed3a86d..dda558ea53 100644 --- a/tests/refc/callingConvention/expected +++ b/tests/refc/callingConvention/expected @@ -9,9 +9,9 @@ Value *Main_last , Value * var_1 ) { - Value * tmp_66 = NULL; // Main:5:8--5:14 + Value * tmp_67 = NULL; // Main:5:8--5:14 if (NULL == var_0 /* Prelude.Basics.Nil [nil] */) { - tmp_66 = var_1; + tmp_67 = var_1; } else if (NULL != var_0 /* Prelude.Basics.(::) [cons] */) { Value *var_2 = ((Value_Constructor*)var_0)->args[0]; Value *var_3 = ((Value_Constructor*)var_0)->args[1]; @@ -19,13 +19,13 @@ Value *Main_last idris2_newReference(var_3); idris2_removeReference(var_0); idris2_removeReference(var_1); - Value *closure_67 = (Value *)idris2_mkClosure((Value *(*)())Main_last, 2, 2); + Value *closure_68 = (Value *)idris2_mkClosure((Value *(*)())Main_last, 2, 2); // Main:7:20--7:24 - ((Value_Closure*)closure_67)->args[0] = var_3; - ((Value_Closure*)closure_67)->args[1] = var_2; - tmp_66 = closure_67; + ((Value_Closure*)closure_68)->args[0] = var_3; + ((Value_Closure*)closure_68)->args[1] = var_2; + tmp_67 = closure_68; } - return tmp_66; + return tmp_67; } Value *Main_main_0 ( @@ -122,8 +122,8 @@ Value *Main_main(void) // Main:11:21--11:22 Value * var_4 = closure_42; // Prelude.Types:605:11--605:20 Value * var_0 = idris2_trampoline(csegen_44()); // Prelude.Types:1121:1--1138:48 - Value * var_1 = (Value*)idris2_mkIntegerLiteral("1"); // Prelude.Types:1121:1--1138:48 - Value * var_2 = (Value*)idris2_mkIntegerLiteral("5"); // Prelude.Types:1121:1--1138:48 + Value * var_1 = idris2_getPredefinedInteger(1); // Prelude.Types:1121:1--1138:48 + Value * var_2 = idris2_getPredefinedInteger(5); // Prelude.Types:1121:1--1138:48 Value * var_5 = idris2_trampoline(Prelude_Types_rangeFromTo_Range__dollara(var_0, var_1, var_2)); // Prelude.Types:605:11--605:20 Value * var_7 = idris2_trampoline(Prelude_Types_List_mapAppend(var_3, var_4, var_5)); @@ -147,7 +147,7 @@ Value *Main_main_11 ) { Value * var_1 = idris2_trampoline(csegen_44()); // Prelude.Types:1121:1--1138:48 - Value * var_2 = (Value*)idris2_mkIntegerLiteral("1"); // Prelude.Types:1121:1--1138:48 + Value * var_2 = idris2_getPredefinedInteger(1); // Prelude.Types:1121:1--1138:48 Value *closure_45 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_rangeFromTo_Range__dollara, 3, 3); // Prelude.Types:1121:1--1138:48 ((Value_Closure*)closure_45)->args[0] = var_1; @@ -161,20 +161,20 @@ Value *Main_main_10 , Value * var_0 ) { - Value * var_2 = (Value*)idris2_mkIntegerLiteral("0"); // Main:10:30--10:36 + Value * var_2 = idris2_getPredefinedInteger(0); // Main:10:30--10:36 Value * var_3 = idris2_trampoline(Main_last(var_1, var_2)); // Prelude.Show:110:1--112:50 Value * var_4 = idris2_trampoline(Prelude_Show_show_Show_Integer(var_3)); - Value * var_5 = (Value*)idris2_mkString("\x0a"""); - Value *primVar_46 = strAppend(var_4, var_5); + Value * var_5 = ((Value*)&idris2_constant_String_46); + Value *primVar_47 = strAppend(var_4, var_5); idris2_removeReference(var_4); idris2_removeReference(var_5); - Value * var_6 = primVar_46; // Prelude.IO:98:22--98:34 - Value *closure_47 = (Value *)idris2_mkClosure((Value *(*)())Prelude_IO_prim__putStr, 2, 2); + Value * var_6 = primVar_47; // Prelude.IO:98:22--98:34 + Value *closure_48 = (Value *)idris2_mkClosure((Value *(*)())Prelude_IO_prim__putStr, 2, 2); // Prelude.IO:98:22--98:34 - ((Value_Closure*)closure_47)->args[0] = var_6; - ((Value_Closure*)closure_47)->args[1] = var_0; - return closure_47; + ((Value_Closure*)closure_48)->args[0] = var_6; + ((Value_Closure*)closure_48)->args[1] = var_0; + return closure_48; } Value *Main_main_9 ( @@ -182,48 +182,48 @@ Value *Main_main_9 , Value * var_0 ) { - Value *closure_48 = (Value *)idris2_mkClosure((Value *(*)())Main_main_0, 5, 0); - Value * var_2 = closure_48; // Prelude.IO:19:1--26:30 - Value *closure_49 = (Value *)idris2_mkClosure((Value *(*)())Main_main_1, 3, 0); - Value * var_3 = closure_49; // Prelude.IO:19:1--26:30 - Value *closure_50 = (Value *)idris2_mkClosure((Value *(*)())Main_main_2, 5, 0); - Value * var_4 = closure_50; // Prelude.IO:19:1--26:30 + Value *closure_49 = (Value *)idris2_mkClosure((Value *(*)())Main_main_0, 5, 0); + Value * var_2 = closure_49; // Prelude.IO:19:1--26:30 + Value *closure_50 = (Value *)idris2_mkClosure((Value *(*)())Main_main_1, 3, 0); + Value * var_3 = closure_50; // Prelude.IO:19:1--26:30 + Value *closure_51 = (Value *)idris2_mkClosure((Value *(*)())Main_main_2, 5, 0); + Value * var_4 = closure_51; // Prelude.IO:19:1--26:30 // constructor Prelude.Interfaces.MkApplicative // Prelude.IO:19:1--26:30 - Value_Constructor* constructor_51 = idris2_newConstructor(3, 0); + Value_Constructor* constructor_52 = idris2_newConstructor(3, 0); // Prelude.IO:19:1--26:30 - constructor_51->args[0] = var_2; - constructor_51->args[1] = var_3; - constructor_51->args[2] = var_4; - Value * var_11 = (Value*)constructor_51; // Main:10:13--10:17 - Value *closure_52 = (Value *)idris2_mkClosure((Value *(*)())Main_main_3, 5, 0); - Value * var_5 = closure_52; // Prelude.Types:656:1--669:59 - Value *closure_53 = (Value *)idris2_mkClosure((Value *(*)())Main_main_4, 5, 0); - Value * var_6 = closure_53; // Prelude.Types:656:1--669:59 - Value *closure_54 = (Value *)idris2_mkClosure((Value *(*)())Main_main_5, 2, 0); - Value * var_7 = closure_54; // Prelude.Types:656:1--669:59 - Value *closure_55 = (Value *)idris2_mkClosure((Value *(*)())Main_main_6, 7, 0); - Value * var_8 = closure_55; // Prelude.Types:656:1--669:59 - Value *closure_56 = (Value *)idris2_mkClosure((Value *(*)())Main_main_7, 2, 0); - Value * var_9 = closure_56; // Prelude.Types:656:1--669:59 - Value *closure_57 = (Value *)idris2_mkClosure((Value *(*)())Main_main_8, 5, 0); - Value * var_10 = closure_57; // Prelude.Types:656:1--669:59 + constructor_52->args[0] = var_2; + constructor_52->args[1] = var_3; + constructor_52->args[2] = var_4; + Value * var_11 = (Value*)constructor_52; // Main:10:13--10:17 + Value *closure_53 = (Value *)idris2_mkClosure((Value *(*)())Main_main_3, 5, 0); + Value * var_5 = closure_53; // Prelude.Types:656:1--669:59 + Value *closure_54 = (Value *)idris2_mkClosure((Value *(*)())Main_main_4, 5, 0); + Value * var_6 = closure_54; // Prelude.Types:656:1--669:59 + Value *closure_55 = (Value *)idris2_mkClosure((Value *(*)())Main_main_5, 2, 0); + Value * var_7 = closure_55; // Prelude.Types:656:1--669:59 + Value *closure_56 = (Value *)idris2_mkClosure((Value *(*)())Main_main_6, 7, 0); + Value * var_8 = closure_56; // Prelude.Types:656:1--669:59 + Value *closure_57 = (Value *)idris2_mkClosure((Value *(*)())Main_main_7, 2, 0); + Value * var_9 = closure_57; // Prelude.Types:656:1--669:59 + Value *closure_58 = (Value *)idris2_mkClosure((Value *(*)())Main_main_8, 5, 0); + Value * var_10 = closure_58; // Prelude.Types:656:1--669:59 // constructor Prelude.Interfaces.MkFoldable // Prelude.Types:656:1--669:59 - Value_Constructor* constructor_58 = idris2_newConstructor(6, 0); + Value_Constructor* constructor_59 = idris2_newConstructor(6, 0); // Prelude.Types:656:1--669:59 - constructor_58->args[0] = var_5; - constructor_58->args[1] = var_6; - constructor_58->args[2] = var_7; - constructor_58->args[3] = var_8; - constructor_58->args[4] = var_9; - constructor_58->args[5] = var_10; - Value * var_12 = (Value*)constructor_58; // Main:10:13--10:17 - Value *closure_59 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Interfaces_for_, 4, 4); + constructor_59->args[0] = var_5; + constructor_59->args[1] = var_6; + constructor_59->args[2] = var_7; + constructor_59->args[3] = var_8; + constructor_59->args[4] = var_9; + constructor_59->args[5] = var_10; + Value * var_12 = (Value*)constructor_59; // Main:10:13--10:17 + Value *closure_60 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Interfaces_for_, 4, 4); // Main:10:13--10:17 - ((Value_Closure*)closure_59)->args[0] = var_11; - ((Value_Closure*)closure_59)->args[1] = var_12; - ((Value_Closure*)closure_59)->args[2] = var_1; - ((Value_Closure*)closure_59)->args[3] = var_0; - return closure_59; + ((Value_Closure*)closure_60)->args[0] = var_11; + ((Value_Closure*)closure_60)->args[1] = var_12; + ((Value_Closure*)closure_60)->args[2] = var_1; + ((Value_Closure*)closure_60)->args[3] = var_0; + return closure_60; } Value *Main_main_8 ( @@ -236,12 +236,12 @@ Value *Main_main_8 { idris2_removeReference(var_3); idris2_removeReference(var_4); - Value *closure_60 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_foldMap_Foldable_List, 3, 3); + Value *closure_61 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_foldMap_Foldable_List, 3, 3); // Prelude.Types:656:1--669:59 - ((Value_Closure*)closure_60)->args[0] = var_2; - ((Value_Closure*)closure_60)->args[1] = var_1; - ((Value_Closure*)closure_60)->args[2] = var_0; - return closure_60; + ((Value_Closure*)closure_61)->args[0] = var_2; + ((Value_Closure*)closure_61)->args[1] = var_1; + ((Value_Closure*)closure_61)->args[2] = var_0; + return closure_61; } Value *Main_main_7 ( @@ -266,13 +266,13 @@ Value *Main_main_6 idris2_removeReference(var_4); idris2_removeReference(var_5); idris2_removeReference(var_6); - Value *closure_61 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_foldlM_Foldable_List, 4, 4); + Value *closure_62 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_foldlM_Foldable_List, 4, 4); // Prelude.Types:656:1--669:59 - ((Value_Closure*)closure_61)->args[0] = var_3; - ((Value_Closure*)closure_61)->args[1] = var_2; - ((Value_Closure*)closure_61)->args[2] = var_1; - ((Value_Closure*)closure_61)->args[3] = var_0; - return closure_61; + ((Value_Closure*)closure_62)->args[0] = var_3; + ((Value_Closure*)closure_62)->args[1] = var_2; + ((Value_Closure*)closure_62)->args[2] = var_1; + ((Value_Closure*)closure_62)->args[3] = var_0; + return closure_62; } Value *Main_main_5 ( @@ -281,10 +281,10 @@ Value *Main_main_5 ) { idris2_removeReference(var_1); - Value *closure_62 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_null_Foldable_List, 1, 1); + Value *closure_63 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_null_Foldable_List, 1, 1); // Prelude.Types:656:1--669:59 - ((Value_Closure*)closure_62)->args[0] = var_0; - return closure_62; + ((Value_Closure*)closure_63)->args[0] = var_0; + return closure_63; } Value *Main_main_4 ( @@ -297,12 +297,12 @@ Value *Main_main_4 { idris2_removeReference(var_3); idris2_removeReference(var_4); - Value *closure_63 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_foldl_Foldable_List, 3, 3); + Value *closure_64 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_foldl_Foldable_List, 3, 3); // Prelude.Types:656:1--669:59 - ((Value_Closure*)closure_63)->args[0] = var_2; - ((Value_Closure*)closure_63)->args[1] = var_1; - ((Value_Closure*)closure_63)->args[2] = var_0; - return closure_63; + ((Value_Closure*)closure_64)->args[0] = var_2; + ((Value_Closure*)closure_64)->args[1] = var_1; + ((Value_Closure*)closure_64)->args[2] = var_0; + return closure_64; } Value *Main_main_3 ( @@ -315,12 +315,12 @@ Value *Main_main_3 { idris2_removeReference(var_3); idris2_removeReference(var_4); - Value *closure_64 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_foldr_Foldable_List, 3, 3); + Value *closure_65 = (Value *)idris2_mkClosure((Value *(*)())Prelude_Types_foldr_Foldable_List, 3, 3); // Prelude.Types:656:1--669:59 - ((Value_Closure*)closure_64)->args[0] = var_2; - ((Value_Closure*)closure_64)->args[1] = var_1; - ((Value_Closure*)closure_64)->args[2] = var_0; - return closure_64; + ((Value_Closure*)closure_65)->args[0] = var_2; + ((Value_Closure*)closure_65)->args[1] = var_1; + ((Value_Closure*)closure_65)->args[2] = var_0; + return closure_65; } Value *Main_main_2 ( @@ -360,10 +360,10 @@ Value *Main_main_0 { idris2_removeReference(var_3); idris2_removeReference(var_4); - Value *closure_65 = (Value *)idris2_mkClosure((Value *(*)())Prelude_IO_map_Functor_IO, 3, 3); + Value *closure_66 = (Value *)idris2_mkClosure((Value *(*)())Prelude_IO_map_Functor_IO, 3, 3); // Prelude.IO:15:1--17:38 - ((Value_Closure*)closure_65)->args[0] = var_2; - ((Value_Closure*)closure_65)->args[1] = var_1; - ((Value_Closure*)closure_65)->args[2] = var_0; - return closure_65; + ((Value_Closure*)closure_66)->args[0] = var_2; + ((Value_Closure*)closure_66)->args[1] = var_1; + ((Value_Closure*)closure_66)->args[2] = var_0; + return closure_66; } diff --git a/tests/refc/reuse/expected b/tests/refc/reuse/expected index 3a5fbb885d..6206aac0ad 100644 --- a/tests/refc/reuse/expected +++ b/tests/refc/reuse/expected @@ -17,39 +17,39 @@ Value *Main_insert , Value * var_2 ) { - Value * tmp_34 = NULL; // Main:6:24--6:31 + Value * tmp_35 = NULL; // Main:6:24--6:31 if (((Value_Constructor *)var_2)->tag == 0 /* Main.Leaf */) { - Value_Constructor* constructor_35 = NULL; + Value_Constructor* constructor_36 = NULL; if (idris2_isUnique(var_2)) { - constructor_35 = (Value_Constructor*)var_2; + constructor_36 = (Value_Constructor*)var_2; } else { idris2_removeReference(var_2); } idris2_removeReference(var_0); // constructor Main.Leaf // Main:7:22--7:26 - if (! constructor_35) { // Main:7:22--7:26 - constructor_35 = idris2_newConstructor(0, 0); // Main:7:22--7:26 + if (! constructor_36) { // Main:7:22--7:26 + constructor_36 = idris2_newConstructor(0, 0); // Main:7:22--7:26 } // Main:7:22--7:26 - Value * var_3 = (Value*)constructor_35; // Main:7:17--7:21 + Value * var_3 = (Value*)constructor_36; // Main:7:17--7:21 // constructor Main.Leaf // Main:7:29--7:33 - Value_Constructor* constructor_36 = idris2_newConstructor(0, 0); + Value_Constructor* constructor_37 = idris2_newConstructor(0, 0); // Main:7:29--7:33 - Value * var_4 = (Value*)constructor_36; // Main:7:17--7:21 + Value * var_4 = (Value*)constructor_37; // Main:7:17--7:21 // constructor Main.Node // Main:7:17--7:21 - Value_Constructor* constructor_37 = idris2_newConstructor(3, 1); + Value_Constructor* constructor_38 = idris2_newConstructor(3, 1); // Main:7:17--7:21 - constructor_37->args[0] = var_3; - constructor_37->args[1] = var_1; - constructor_37->args[2] = var_4; - tmp_34 = (Value*)constructor_37; + constructor_38->args[0] = var_3; + constructor_38->args[1] = var_1; + constructor_38->args[2] = var_4; + tmp_35 = (Value*)constructor_38; } else if (((Value_Constructor *)var_2)->tag == 1 /* Main.Node */) { Value *var_5 = ((Value_Constructor*)var_2)->args[0]; Value *var_6 = ((Value_Constructor*)var_2)->args[1]; Value *var_7 = ((Value_Constructor*)var_2)->args[2]; - Value_Constructor* constructor_38 = NULL; + Value_Constructor* constructor_39 = NULL; if (idris2_isUnique(var_2)) { - constructor_38 = (Value_Constructor*)var_2; + constructor_39 = (Value_Constructor*)var_2; } else { idris2_newReference(var_5); @@ -57,7 +57,7 @@ Value *Main_insert idris2_newReference(var_7); idris2_removeReference(var_2); } - Value * tmp_39 = NULL; // Prelude.EqOrd:121:3--121:6 + Value * tmp_40 = NULL; // Prelude.EqOrd:121:3--121:6 if (((Value_Constructor *)var_0)->tag == 0 /* Prelude.EqOrd.MkOrd */) { Value *var_8 = ((Value_Constructor*)var_0)->args[0]; Value *var_9 = ((Value_Constructor*)var_0)->args[1]; @@ -70,39 +70,39 @@ Value *Main_insert idris2_newReference(var_10); Value * var_16 = idris2_apply_closure(var_10, idris2_newReference(var_1)); // Prelude.EqOrd:121:3--121:6 - tmp_39 = idris2_apply_closure(var_16, idris2_newReference(var_6)); + tmp_40 = idris2_apply_closure(var_16, idris2_newReference(var_6)); } - Value * var_19 = tmp_39; - Value *tmp_40 = NULL; - int64_t tmp_41 = idris2_extractInt(var_19); - if (tmp_41 == UINT8_C(1)) { + Value * var_19 = tmp_40; + Value *tmp_41 = NULL; + int64_t tmp_42 = idris2_extractInt(var_19); + if (tmp_42 == UINT8_C(1)) { idris2_removeReference(var_19); Value * var_17 = idris2_trampoline(Main_insert(var_0, var_1, var_5)); // Main:8:42--8:46 // constructor Main.Node // Main:8:42--8:46 - if (! constructor_38) { // Main:8:42--8:46 - constructor_38 = idris2_newConstructor(3, 1); + if (! constructor_39) { // Main:8:42--8:46 + constructor_39 = idris2_newConstructor(3, 1); // Main:8:42--8:46 } // Main:8:42--8:46 - constructor_38->args[0] = var_17; - constructor_38->args[1] = var_6; - constructor_38->args[2] = var_7; - tmp_40 = (Value*)constructor_38; - } else if (tmp_41 == UINT8_C(0)) { + constructor_39->args[0] = var_17; + constructor_39->args[1] = var_6; + constructor_39->args[2] = var_7; + tmp_41 = (Value*)constructor_39; + } else if (tmp_42 == UINT8_C(0)) { idris2_removeReference(var_19); Value * var_18 = idris2_trampoline(Main_insert(var_0, var_1, var_7)); // Main:9:42--9:46 // constructor Main.Node // Main:9:42--9:46 - if (! constructor_38) { // Main:9:42--9:46 - constructor_38 = idris2_newConstructor(3, 1); + if (! constructor_39) { // Main:9:42--9:46 + constructor_39 = idris2_newConstructor(3, 1); // Main:9:42--9:46 } // Main:9:42--9:46 - constructor_38->args[0] = var_5; - constructor_38->args[1] = var_6; - constructor_38->args[2] = var_18; - tmp_40 = (Value*)constructor_38; + constructor_39->args[0] = var_5; + constructor_39->args[1] = var_6; + constructor_39->args[2] = var_18; + tmp_41 = (Value*)constructor_39; } - tmp_34 = tmp_40; + tmp_35 = tmp_41; } - return tmp_34; + return tmp_35; }