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; +}