From cca61ea16398904883e454c847b5ef5d73f6ac7a Mon Sep 17 00:00:00 2001 From: Taylor Robbins Date: Sun, 31 Aug 2025 17:33:48 -0700 Subject: [PATCH] Added cwasm_arena.c and cwasm_debug.c. Arena API hasn't been tested well yet. There's also something wrong with our DebugOutputLineBuffer usage for splitting lines to multiple Javascript output calls. Also added an int level to jsStdPrint and a bunch of macros to cwasm.h --- CWasm.sublime-project | 102 ++++++++++++++++++++- cwasm.c | 19 ++-- cwasm.h | 66 ++++++++++++++ cwasm_arena.c | 182 ++++++++++++++++++++++++++++++++++++++ cwasm_debug.c | 186 +++++++++++++++++++++++++++++++++++++++ std/assert.h | 2 + std/src/std_js_imports.h | 2 +- std/src/std_printf.c | 2 +- test_app.c | 16 ++++ 9 files changed, 566 insertions(+), 11 deletions(-) create mode 100644 cwasm_arena.c create mode 100644 cwasm_debug.c diff --git a/CWasm.sublime-project b/CWasm.sublime-project index 30111fe..6ec223c 100644 --- a/CWasm.sublime-project +++ b/CWasm.sublime-project @@ -10,5 +10,105 @@ "build", ], } - ] + ], + "settings": + { + "build_options": + [ + ], + "custom_constants": + [ + "ArenaFlag_All", + "ArenaFlag_Count", + "ArenaFlag_Debug", + "ArenaFlag_DefaultAligned16", + "ArenaFlag_DefaultAligned4", + "ArenaFlag_DefaultAligned8", + "ArenaFlag_IsMainWasmMemory", + "ArenaFlag_IsScratch", + "ArenaFlag_None", + "CWASM_ASSERTIONS_ENABLED", + "CWASM_DEBUG", + "CWASM_DEBUG_OUTPUT_LINE_BUFFER_SIZE", + "CWASM_DEBUG_OUTPUT_PRINT_BUFFER_SIZE", + "CWASM_ENABLE_DBG_LEVEL_DEBUG", + "CWASM_ENABLE_DBG_LEVEL_DEBUG", + "CWASM_ENABLE_DBG_LEVEL_ERROR", + "CWASM_ENABLE_DBG_LEVEL_ERROR", + "CWASM_ENABLE_DBG_LEVEL_INFO", + "CWASM_ENABLE_DBG_LEVEL_INFO", + "CWASM_ENABLE_DBG_LEVEL_WARNING", + "CWASM_ENABLE_DBG_LEVEL_WARNING", + "DbgLevel_Count", + "DbgLevel_Debug", + "DbgLevel_Error", + "DbgLevel_Info", + "DbgLevel_None", + "DbgLevel_Warning", + "END_EXTERN_C", + "LANGUAGE_IS_C", + "LANGUAGE_IS_CPP", + "MAYBE_END_EXTERN_C", + "MAYBE_EXTERN_C", + "MAYBE_START_EXTERN_C", + "SCRATCH_ARENAS_SIZE", + "START_EXTERN_C", + "WASM_MEMORY_MAX_NUM_PAGES", + "WASM_MEMORY_MAX_SIZE", + "WASM_MEMORY_PAGE_SIZE", + "WASM_PROTECTED_SIZE", + "ZEROED", + ], + "custom_functions": + [ + "#define AlignOffset(pntr, alignment)", + "#define AllocArray(type, arenaPntr, count)", + "#define AllocStruct(type, arenaPntr)", + "#define ArrayCount(array)", + "#define Assert(condition)", + "#define IsAlignedTo(pntr, alignment)", + "#define PrintLine_D(formatStrNt, ...)", + "#define PrintLine_E(formatStrNt, ...)", + "#define PrintLine_I(formatStrNt, ...)", + "#define PrintLine_W(formatStrNt, ...)", + "#define Print_D(formatStrNt, ...)", + "#define Print_E(formatStrNt, ...)", + "#define Print_I(formatStrNt, ...)", + "#define Print_W(formatStrNt, ...)", + "#define ScratchBegin(scratchName)", + "#define ScratchBegin1(scratchName, conflictArenaPntr)", + "#define ScratchEnd(scratchName)", + "#define WASM_EXPORT(functionName)", + "#define WriteLine_D(messageNt)", + "#define WriteLine_E(messageNt)", + "#define WriteLine_I(messageNt)", + "#define WriteLine_W(messageNt)", + "#define Write_D(messageNt)", + "#define Write_E(messageNt)", + "#define Write_I(messageNt)", + "#define Write_W(messageNt)", + "Arena NewArena(void* basePntr, u32 size)", + "Arena* AllocArena(Arena* sourceArena, u32 newArenaFlags, u32 newArenaSize, u32 newArenaAlignment)", + "ArenaMark GetArenaMark(Arena* arena)", + "ArenaMark GetScratch()", + "ArenaMark GetScratch1(Arena* conflictArena)", + "inline void* ReallocMem(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize)", + "inline void* ReallocMemUnaligned(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize)", + "void InitGlobalArenas(u32 scratchArenasSize)", + "void ResetToArenaMark(ArenaMark arenaMark)", + "void ResetToMark(Arena* arena, u32 mark)", + "void* AllocMemUnaligned(Arena* arena, u32 numBytes)", + "void* ReallocMemAligned(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize, u32 newAlignment)", + ], + "custom_globals": + [ + ], + "custom_types": + [ + "Arena", + "ArenaFlag", + "ArenaMark", + "DbgLevel", + ], + }, } diff --git a/cwasm.c b/cwasm.c index 3028bbd..4837420 100644 --- a/cwasm.c +++ b/cwasm.c @@ -9,14 +9,17 @@ Description: #include "cwasm.h" #include "std/src/std_main.c" +#include "cwasm_arena.c" +#include "cwasm_debug.c" -WASM_EXPORT(HelloFromWasm) float HelloFromWasm(float value, float value2) +void InitializeCWasm(u32 scratchArenasSize) { - printf("Called HelloFromWasm(%g)!\n", fmodf(value, value2)); - for (int iIndex = 0; iIndex < 1024; iIndex++) - { - void* newMem = grow_mem(1024); - printf("mem[%d] = %p\n", iIndex, newMem); - } - return value*(value+1)*2; + // CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Warning, true, "Hello\nWorld!"); + Write_D("Hello\nWorld!"); + PrintLine_D(" Fuzzy %u Bunnies!\n%s", 31415926, "What"); + WriteLine_D(""); + WriteLine_I("When"); + Write_D("\n"); + WriteLine_E("Where"); + InitGlobalArenas(scratchArenasSize); } diff --git a/cwasm.h b/cwasm.h index 67e4fba..688abd3 100644 --- a/cwasm.h +++ b/cwasm.h @@ -31,6 +31,36 @@ Description: #error This standard library implementation assumes little-endian byte order #endif +// +--------------------------------------------------------------+ +// | Check Configuration Macros | +// +--------------------------------------------------------------+ +#ifndef CWASM_DEBUG +#define CWASM_DEBUG 0 +#endif + +#ifndef CWASM_ASSERTIONS_ENABLED +#define CWASM_ASSERTIONS_ENABLED CWASM_DEBUG +#endif + +#ifndef CWASM_DEBUG_OUTPUT_LINE_BUFFER_SIZE +#define CWASM_DEBUG_OUTPUT_LINE_BUFFER_SIZE 1024 //chars +#endif +#ifndef CWASM_DEBUG_OUTPUT_PRINT_BUFFER_SIZE +#define CWASM_DEBUG_OUTPUT_PRINT_BUFFER_SIZE 1024 //chars +#endif +#ifndef CWASM_ENABLE_DBG_LEVEL_DEBUG +#define CWASM_ENABLE_DBG_LEVEL_DEBUG 1 +#endif +#ifndef CWASM_ENABLE_DBG_LEVEL_INFO +#define CWASM_ENABLE_DBG_LEVEL_INFO 1 +#endif +#ifndef CWASM_ENABLE_DBG_LEVEL_WARNING +#define CWASM_ENABLE_DBG_LEVEL_WARNING 1 +#endif +#ifndef CWASM_ENABLE_DBG_LEVEL_ERROR +#define CWASM_ENABLE_DBG_LEVEL_ERROR 1 +#endif + // +--------------------------------------------------------------+ // | Macros | // +--------------------------------------------------------------+ @@ -65,6 +95,41 @@ Description: #define WASM_EXPORT(functionName) MAYBE_EXTERN_C __attribute__((export_name(#functionName))) +#if LANGUAGE_IS_C +#define ZEROED {0} +#else +#define ZEROED {} +#endif + +#define ArrayCount(array) (sizeof(array) / sizeof((array)[0])) +#define IsAlignedTo(pntr, alignment) ((alignment) == 0 || (((size_t)(pntr)) % (alignment)) == 0) +#define AlignOffset(pntr, alignment) ((alignment) == 0 ? 0 : (((alignment) - (((size_t)(pntr)) % (alignment))) % alignment)) + +// Shorthand for writing things like (4 * 1024 * 1024) as Megabytes(4). +// Can be used for more than just memory sizes but these powers of 1024 are often +// used when partitioning memory because they relate to binary bit patterns +#define Kilo(value) ((value) * 1024ULL) +#define Mega(value) (Kilo(value) * 1024ULL) +#define Giga(value) (Mega(value) * 1024ULL) +#define Tera(value) (Giga(value) * 1024ULL) +#define Kilobytes(value) Kilo(value) +#define Megabytes(value) Mega(value) +#define Gigabytes(value) Giga(value) +#define Terabytes(value) Tera(value) + +#define Thousand(value) ((value) * 1000ULL) +#define Million(value) ((value) * 1000000ULL) +#define Billion(value) ((value) * 1000000000ULL) +#define Trillion(value) ((value) * 1000000000000ULL) + +#if CWASM_ASSERTIONS_ENABLED +#define Assert(condition) assert(condition) +#define AssertMsg(condition, message) assert_msg((condition), (message)) +#else +#define Assert(condition) sizeof(condition) //do nothing, but make sure anything used in condition is not treated as "unused" when assertions are disabled +#define AssertMsg(condition, message) sizeof(condition) +#endif + // +--------------------------------------------------------------+ // | Standard Includes | // +--------------------------------------------------------------+ @@ -76,6 +141,7 @@ Description: #include #include #include +#include #include #include #include diff --git a/cwasm_arena.c b/cwasm_arena.c new file mode 100644 index 0000000..d25eb2e --- /dev/null +++ b/cwasm_arena.c @@ -0,0 +1,182 @@ +/* +File: cwasm_arena.c +Author: Taylor Robbins +Date: 08\28\2025 +Description: + ** Defines a basic memory Arena structure and API + ** Also defines a few global memory arenas: MainWasmMemory and 2x ScratchArenas +*/ + +// +--------------------------------------------------------------+ +// | Arena Types | +// +--------------------------------------------------------------+ +typedef enum ArenaFlag ArenaFlag; +enum ArenaFlag +{ + ArenaFlag_None = 0x00000000, + ArenaFlag_Debug = 0x00000001, + ArenaFlag_IsMainWasmMemory = 0x00000002, + ArenaFlag_DefaultAligned4 = 0x00000004, + ArenaFlag_DefaultAligned8 = 0x00000008, + ArenaFlag_DefaultAligned16 = 0x00000010, + ArenaFlag_IsScratch = 0x00000020, + ArenaFlag_All = 0x0000003F, + ArenaFlag_Count = 6, +}; + +typedef struct Arena Arena; +struct Arena +{ + u32 flags; //ArenaFlags + void* base; + u32 size; + u32 used; +}; + +typedef struct ArenaMark ArenaMark; +struct ArenaMark +{ + Arena* arena; + u32 mark; +}; + +// +--------------------------------------------------------------+ +// | Global Arenas | +// +--------------------------------------------------------------+ +static Arena MainWasmMemory = ZEROED; +static Arena ScratchArenas[2] = ZEROED; + +// +--------------------------------------------------------------+ +// | Arena API | +// +--------------------------------------------------------------+ +__attribute__((always_inline)) Arena NewArena(u32 flags, u32 size, void* basePntr) +{ + Arena result = ZEROED; + result.flags = flags; + result.size = size; + result.base = basePntr; + return result; +} + +static inline ArenaMark GetArenaMark(Arena* arena) +{ + ArenaMark result = ZEROED; + result.arena = arena; + result.mark = arena->used; + return result; +} +static inline void ResetToMark(Arena* arena, u32 mark) +{ + arena->used = mark; +} +static inline void ResetToArenaMark(ArenaMark arenaMark) { ResetToMark(arenaMark.arena, arenaMark.mark); } + +void* AllocMemAligned(Arena* arena, u32 numBytes, u32 alignment) +{ + Assert(arena != nullptr && arena->base != nullptr); + u32 realAlignment = alignment; + if (realAlignment == UINT32_MAX) { realAlignment = 0; } + else if (realAlignment == 0 && (arena->flags & ArenaFlag_DefaultAligned16) != 0) { realAlignment = 16; } + else if (realAlignment == 0 && (arena->flags & ArenaFlag_DefaultAligned8) != 0) { realAlignment = 8; } + else if (realAlignment == 0 && (arena->flags & ArenaFlag_DefaultAligned4) != 0) { realAlignment = 4; } + u32 alignOffset = AlignOffset((u8*)arena->base + arena->used, realAlignment); + u32 newSize = arena->used + alignOffset + numBytes; + if (newSize > arena->size) + { + if ((arena->flags & ArenaFlag_IsMainWasmMemory) != 0) + { + void* newMemory = grow_mem(newSize - arena->size); + Assert(newMemory == (u8*)arena->base + arena->size); + arena->size = newSize; + } + else { return nullptr; } + } + + void* result = (u8*)arena->base + arena->used; + arena->used += alignOffset + numBytes; + return result; +} +static inline void* AllocMemUnaligned(Arena* arena, u32 numBytes) { return AllocMemAligned(arena, numBytes, UINT32_MAX); } +static inline void* AllocMem(Arena* arena, u32 numBytes) { return AllocMemAligned(arena, numBytes, 0); } + +static inline Arena* AllocArena(Arena* sourceArena, u32 newArenaFlags, u32 newArenaSize, u32 newArenaAlignment) +{ + //TODO: Do we need to make sure the Arena structure is aligned to it's own struct alignment? + #if LANGUAGE_IS_C + u32 arenaStructAlignment = (u32)_Alignof(Arena); + #else + u32 arenaStructAlignment = (u32)std::alignment_of(); + #endif + u32 offsetAfterStruct = AlignOffset(sizeof(Arena), newArenaAlignment); + Arena* result = (Arena*)AllocMemAligned(sourceArena, sizeof(Arena) + offsetAfterStruct + newArenaSize, (arenaStructAlignment >= newArenaAlignment) ? arenaStructAlignment : newArenaAlignment); + if (result == nullptr) { return nullptr; } + *result = NewArena(newArenaFlags, newArenaSize, ((u8*)result) + sizeof(Arena) + offsetAfterStruct); + return result; +} + +#if LANGUAGE_IS_C +#define AllocStruct(type, arenaPntr) (type*)AllocMemAligned((arenaPntr), sizeof(type), (u32)_Alignof(type)) +#define AllocArray(type, arenaPntr, count) (type*)AllocMemAligned((arenaPntr), sizeof(type) * (count), (u32)_Alignof(type)) +#else +#define AllocStruct(type, arenaPntr) (type*)AllocMemAligned((arenaPntr), sizeof(type), (u32)std::alignment_of()) +#define AllocArray(type, arenaPntr, count) (type*)AllocMemAligned((arenaPntr), sizeof(type) * (count), (u32)std::alignment_of()) +#endif + +void* ReallocMemAligned(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize, u32 newAlignment) +{ + if (oldSize == newSize) { return oldPntr; } + if (oldPntr == nullptr) { return AllocMemAligned(arena, newSize, newAlignment); } + Assert(arena != nullptr && arena->base != nullptr); + + u32 realAlignment = newAlignment; + if (realAlignment == UINT32_MAX) { realAlignment = 0; } + else if (realAlignment == 0 && (arena->flags & ArenaFlag_DefaultAligned16) != 0) { realAlignment = 16; } + else if (realAlignment == 0 && (arena->flags & ArenaFlag_DefaultAligned8) != 0) { realAlignment = 8; } + else if (realAlignment == 0 && (arena->flags & ArenaFlag_DefaultAligned4) != 0) { realAlignment = 4; } + + if ((u8*)oldPntr + oldSize == (u8*)arena->base + arena->used && IsAlignedTo(oldPntr, realAlignment)) + { + if (newSize > oldSize) + { + void* newSpace = AllocMemUnaligned(arena, newSize - oldSize); + if (newSpace == nullptr) { return nullptr; } + Assert(newSpace == (u8*)oldPntr + oldSize); + } + else { arena->used -= (oldSize - newSize); } + return oldPntr; + } + else + { + void* newPntr = AllocMemAligned(arena, newSize, newAlignment); + if (oldSize > 0 && newPntr != nullptr) { memcpy(newPntr, oldPntr, oldSize); } + return newPntr; + } +} +static inline void* ReallocMemUnaligned(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize) { return ReallocMemAligned(arena, oldPntr, oldSize, newSize, UINT32_MAX); } +static inline void* ReallocMem(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize) { return ReallocMemAligned(arena, oldPntr, oldSize, newSize, 0); } + +void InitGlobalArenas(u32 scratchArenasSize) +{ + u32 mainInitialSize = 1024; + void* mainPntr = grow_mem(mainInitialSize); + MainWasmMemory = NewArena(ArenaFlag_IsMainWasmMemory|ArenaFlag_DefaultAligned16, mainInitialSize, mainPntr); + + for (u32 aIndex = 0; aIndex < ArrayCount(ScratchArenas); aIndex++) + { + void* scratchMemory = AllocMem(&MainWasmMemory, scratchArenasSize); + ScratchArenas[aIndex] = NewArena(ArenaFlag_IsScratch, scratchArenasSize, scratchMemory); + } +} + +// +==============================+ +// | Scratch API | +// +==============================+ +ArenaMark GetScratch1(Arena* conflictArena) +{ + return GetArenaMark((conflictArena == &ScratchArenas[0]) ? &ScratchArenas[1] : &ScratchArenas[0]); +} +static inline ArenaMark GetScratch() { return GetScratch1(nullptr); } + +#define ScratchBegin1(scratchName, conflictArenaPntr) ArenaMark scratchName##Mark = GetScratch1(conflictArenaPntr); Arena* scratchName = scratchName##Mark.arena +#define ScratchBegin(scratchName) ScratchBegin(scratchName, nullptr) +#define ScratchEnd(scratchName) ResetToArenaMark(scratchName##Mark) diff --git a/cwasm_debug.c b/cwasm_debug.c new file mode 100644 index 0000000..5fdf333 --- /dev/null +++ b/cwasm_debug.c @@ -0,0 +1,186 @@ +/* +File: cwasm_debug.c +Author: Taylor Robbins +Date: 08\29\2025 +Description: + ** Holds functions and macros for the debug output API we use in the application +*/ + +typedef enum DbgLevel DbgLevel; +enum DbgLevel +{ + DbgLevel_Debug = 0, + DbgLevel_Info, + DbgLevel_Warning, + DbgLevel_Error, + DbgLevel_Count, +}; + +static DbgLevel DebugOutputLineBufferLevel = DbgLevel_Debug; +static u32 DebugOutputLineBufferLength = 0; +static char DebugOutputLineBuffer[CWASM_DEBUG_OUTPUT_LINE_BUFFER_SIZE]; +static char DebugOutputPrintBuffer[CWASM_DEBUG_OUTPUT_PRINT_BUFFER_SIZE]; + +#if CWASM_DEBUG +void CwasmDebugOutput(const char* filePath, u32 lineNumber, const char* functionName, DbgLevel level, bool newLine, const char* messageNt) +#else +void CwasmDebugOutput(DbgLevel level, bool newLine, const char* messageNt) +#endif +{ + if (level == DbgLevel_Debug && !CWASM_ENABLE_DBG_LEVEL_DEBUG) { return; } + if (level == DbgLevel_Info && !CWASM_ENABLE_DBG_LEVEL_INFO) { return; } + if (level == DbgLevel_Warning && !CWASM_ENABLE_DBG_LEVEL_WARNING) { return; } + if (level == DbgLevel_Error && !CWASM_ENABLE_DBG_LEVEL_ERROR) { return; } + + u32 lineStart = 0; + int messageLength = (messageNt != nullptr) ? strlen(messageNt) : 0; + for (int cIndex = 0; cIndex < messageLength + (newLine ? 1 : 0); cIndex++) + { + char character = (cIndex < messageLength) ? messageNt[cIndex] : '\n'; + if (character == '\n') + { + if (DebugOutputLineBufferLength > 0) + { + DebugOutputLineBufferLevel = (level > DebugOutputLineBufferLevel) ? level : DebugOutputLineBufferLevel; + u32 numCharsToCopy = ((cIndex - lineStart) < (CWASM_DEBUG_OUTPUT_LINE_BUFFER_SIZE - DebugOutputLineBufferLength)) + ? (cIndex - lineStart) + : (CWASM_DEBUG_OUTPUT_LINE_BUFFER_SIZE - DebugOutputLineBufferLength); + if (numCharsToCopy > 0) + { + memcpy(&DebugOutputLineBuffer[DebugOutputLineBufferLength], &messageNt[lineStart], numCharsToCopy); + DebugOutputLineBufferLength += numCharsToCopy; + } + jsStdPrint((int)DebugOutputLineBufferLevel, &DebugOutputLineBuffer[0], DebugOutputLineBufferLength); + DebugOutputLineBufferLength = 0; + DebugOutputLineBufferLevel = DbgLevel_Debug; + } + else + { + jsStdPrint((int)level, &messageNt[lineStart], messageLength - lineStart); + } + lineStart = cIndex+1; + } + } + + if (lineStart < messageLength) + { + u32 numCharsToCopy = ((messageLength - lineStart) < (CWASM_DEBUG_OUTPUT_LINE_BUFFER_SIZE - DebugOutputLineBufferLength)) + ? (messageLength - lineStart) + : (CWASM_DEBUG_OUTPUT_LINE_BUFFER_SIZE - DebugOutputLineBufferLength); + if (numCharsToCopy > 0) + { + DebugOutputLineBufferLevel = (level > DebugOutputLineBufferLevel) ? level : DebugOutputLineBufferLevel; + memcpy(&DebugOutputLineBuffer[DebugOutputLineBufferLength], &messageNt[lineStart], numCharsToCopy); + DebugOutputLineBufferLength += numCharsToCopy; + } + } +} + +#if CWASM_DEBUG +void CwasmDebugOutputPrint(const char* filePath, u32 lineNumber, const char* functionName, DbgLevel level, bool newLine, const char* formatStrNt, ...) +#else +void CwasmDebugOutputPrint(DbgLevel level, bool newLine, const char* formatStrNt, ...) +#endif +{ + va_list args; + va_start(args, formatStrNt); + int printResult = vsnprintf(&DebugOutputPrintBuffer[0], CWASM_DEBUG_OUTPUT_PRINT_BUFFER_SIZE, formatStrNt, args); + va_end(args); + if (printResult >= 0) + { + DebugOutputPrintBuffer[CWASM_DEBUG_OUTPUT_PRINT_BUFFER_SIZE-1] = '\0'; + #if CWASM_DEBUG + CwasmDebugOutput(filePath, lineNumber, functionName, level, newLine, &DebugOutputPrintBuffer[0]); + #else + CwasmDebugOutput(level, newLine, &DebugOutputPrintBuffer[0]); + #endif + } + else + { + #if CWASM_DEBUG + CwasmDebugOutput(filePath, lineNumber, functionName, level, false, "CWASM_PRINT_ERROR("); + CwasmDebugOutput(filePath, lineNumber, functionName, level, false, formatStrNt); + CwasmDebugOutput(filePath, lineNumber, functionName, level, true, ")"); + #else + CwasmDebugOutput(level, false, "CWASM_PRINT_ERROR("); + CwasmDebugOutput(level, false, formatStrNt); + CwasmDebugOutput(level, true, ")"); + #endif + } +} + +#if CWASM_ENABLE_DBG_LEVEL_DEBUG +#if CWASM_DEBUG +#define Write_D(messageNt) CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Debug, false, (messageNt)) +#define Print_D(formatStrNt, ...) CwasmDebugOutputPrint(__FILE__, __LINE__, __func__, DbgLevel_Debug, false, (formatStrNt), ##__VA_ARGS__) +#define WriteLine_D(messageNt) CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Debug, true, (messageNt)) +#define PrintLine_D(formatStrNt, ...) CwasmDebugOutputPrint(__FILE__, __LINE__, __func__, DbgLevel_Debug, true, (formatStrNt), ##__VA_ARGS__) +#else +#define Write_D(messageNt) CwasmDebugOutput(DbgLevel_Debug, false, (messageNt)) +#define Print_D(formatStrNt, ...) CwasmDebugOutputPrint(DbgLevel_Debug, false, (formatStrNt), ##__VA_ARGS__) +#define WriteLine_D(messageNt) CwasmDebugOutput(DbgLevel_Debug, true, (messageNt)) +#define PrintLine_D(formatStrNt, ...) CwasmDebugOutputPrint(DbgLevel_Debug, true, (formatStrNt), ##__VA_ARGS__) +#endif +#else +#define Write_D(messageNt) //nothing +#define Print_D(formatStrNt, ...) //nothing +#define WriteLine_D(messageNt) //nothing +#define PrintLine_D(formatStrNt, ...) //nothing +#endif + +#if CWASM_ENABLE_DBG_LEVEL_INFO +#if CWASM_DEBUG +#define Write_I(messageNt) CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Info, false, (messageNt)) +#define Print_I(formatStrNt, ...) CwasmDebugOutputPrint(__FILE__, __LINE__, __func__, DbgLevel_Info, false, (formatStrNt), ##__VA_ARGS__) +#define WriteLine_I(messageNt) CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Info, true, (messageNt)) +#define PrintLine_I(formatStrNt, ...) CwasmDebugOutputPrint(__FILE__, __LINE__, __func__, DbgLevel_Info, true, (formatStrNt), ##__VA_ARGS__) +#else +#define Write_I(messageNt) CwasmDebugOutput(DbgLevel_Info, false, (messageNt)) +#define Print_I(formatStrNt, ...) CwasmDebugOutputPrint(DbgLevel_Info, false, (formatStrNt), ##__VA_ARGS__) +#define WriteLine_I(messageNt) CwasmDebugOutput(DbgLevel_Info, true, (messageNt)) +#define PrintLine_I(formatStrNt, ...) CwasmDebugOutputPrint(DbgLevel_Info, true, (formatStrNt), ##__VA_ARGS__) +#endif +#else +#define Write_I(messageNt) //nothing +#define Print_I(formatStrNt, ...) //nothing +#define WriteLine_I(messageNt) //nothing +#define PrintLine_I(formatStrNt, ...) //nothing +#endif + +#if CWASM_ENABLE_DBG_LEVEL_WARNING +#if CWASM_DEBUG +#define Write_W(messageNt) CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Warning, false, (messageNt)) +#define Print_W(formatStrNt, ...) CwasmDebugOutputPrint(__FILE__, __LINE__, __func__, DbgLevel_Warning, false, (formatStrNt), ##__VA_ARGS__) +#define WriteLine_W(messageNt) CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Warning, true, (messageNt)) +#define PrintLine_W(formatStrNt, ...) CwasmDebugOutputPrint(__FILE__, __LINE__, __func__, DbgLevel_Warning, true, (formatStrNt), ##__VA_ARGS__) +#else +#define Write_W(messageNt) CwasmDebugOutput(DbgLevel_Warning, false, (messageNt)) +#define Print_W(formatStrNt, ...) CwasmDebugOutputPrint(DbgLevel_Warning, false, (formatStrNt), ##__VA_ARGS__) +#define WriteLine_W(messageNt) CwasmDebugOutput(DbgLevel_Warning, true, (messageNt)) +#define PrintLine_W(formatStrNt, ...) CwasmDebugOutputPrint(DbgLevel_Warning, true, (formatStrNt), ##__VA_ARGS__) +#endif +#else +#define Write_W(messageNt) //nothing +#define Print_W(formatStrNt, ...) //nothing +#define WriteLine_W(messageNt) //nothing +#define PrintLine_W(formatStrNt, ...) //nothing +#endif + +#if CWASM_ENABLE_DBG_LEVEL_ERROR +#if CWASM_DEBUG +#define Write_E(messageNt) CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Error, false, (messageNt)) +#define Print_E(formatStrNt, ...) CwasmDebugOutputPrint(__FILE__, __LINE__, __func__, DbgLevel_Error, false, (formatStrNt), ##__VA_ARGS__) +#define WriteLine_E(messageNt) CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Error, true, (messageNt)) +#define PrintLine_E(formatStrNt, ...) CwasmDebugOutputPrint(__FILE__, __LINE__, __func__, DbgLevel_Error, true, (formatStrNt), ##__VA_ARGS__) +#else +#define Write_E(messageNt) CwasmDebugOutput(DbgLevel_Error, false, (messageNt)) +#define Print_E(formatStrNt, ...) CwasmDebugOutputPrint(DbgLevel_Error, false, (formatStrNt), ##__VA_ARGS__) +#define WriteLine_E(messageNt) CwasmDebugOutput(DbgLevel_Error, true, (messageNt)) +#define PrintLine_E(formatStrNt, ...) CwasmDebugOutputPrint(DbgLevel_Error, true, (formatStrNt), ##__VA_ARGS__) +#endif +#else +#define Write_E(messageNt) //nothing +#define Print_E(formatStrNt, ...) //nothing +#define WriteLine_E(messageNt) //nothing +#define PrintLine_E(formatStrNt, ...) //nothing +#endif diff --git a/std/assert.h b/std/assert.h index 7a09e64..e822feb 100644 --- a/std/assert.h +++ b/std/assert.h @@ -7,6 +7,8 @@ Date: 08\28\2025 #ifndef _ASSERT_H #define _ASSERT_H +#include "src/std_js_imports.h" + #define assert(condition) do { if (!(condition)) { jsStdAssertFailure(__FILE__, __LINE__, __func__, #condition, nullptr); } } while(0) //NOTE: assert_msg is not a standard function but we want to be able to pass a message to jsStdAssertFailure so we added this variant #define assert_msg(condition, message) do { if (!(condition)) { jsStdAssertFailure(__FILE__, __LINE__, __func__, #condition, (message)); } } while(0) diff --git a/std/src/std_js_imports.h b/std/src/std_js_imports.h index 3d54d87..a6737bc 100644 --- a/std/src/std_js_imports.h +++ b/std/src/std_js_imports.h @@ -9,7 +9,7 @@ Description: #ifndef _STD_JS_IMPORTS_H #define _STD_JS_IMPORTS_H -MAYBE_EXTERN_C void jsStdPrint(const char* messageStrPntr, int messageLength); +MAYBE_EXTERN_C void jsStdPrint(int level, const char* messageStrPntr, int messageLength); MAYBE_EXTERN_C _Noreturn void jsStdAbort(const char* messageStrPntr, int exitCode); MAYBE_EXTERN_C _Noreturn void jsStdAssertFailure(const char* filePathPntr, int fileLineNum, const char* funcNamePntr, const char* conditionStrPntr, const char* messageStrPntr); MAYBE_EXTERN_C void jsStdDebugBreak(); diff --git a/std/src/std_printf.c b/std/src/std_printf.c index 494a257..c598392 100644 --- a/std/src/std_printf.c +++ b/std/src/std_printf.c @@ -31,7 +31,7 @@ int vprintf(const char* restrict formatStr, va_list args) if (result > 0 && result < STD_PRINTF_BUFFER_SIZE) { stdGlobalPrintBuffer[result] = '\0'; //ensure null-termination - jsStdPrint(&stdGlobalPrintBuffer[0], result); + jsStdPrint(1, &stdGlobalPrintBuffer[0], result); } return result; } diff --git a/test_app.c b/test_app.c index 2266495..64ee8e9 100644 --- a/test_app.c +++ b/test_app.c @@ -8,4 +8,20 @@ Description: #include "cwasm.c" +#define SCRATCH_ARENAS_SIZE Kilobytes(128) +WASM_EXPORT(InitializeApp) void InitializeApp() +{ + InitializeCWasm(SCRATCH_ARENAS_SIZE); +} + +WASM_EXPORT(HelloFromWasm) float HelloFromWasm(float value, float value2) +{ + printf("Called HelloFromWasm(%g)!\n", fmodf(value, value2)); + for (int iIndex = 0; iIndex < 1024; iIndex++) + { + void* newMem = grow_mem(1024); + printf("mem[%d] = %p\n", iIndex, newMem); + } + return value*(value+1)*2; +}