1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Initial checkin

This commit is contained in:
Brian Fiete 2019-08-23 11:56:54 -07:00
parent c74712dad9
commit 078564ac9e
3242 changed files with 1616395 additions and 0 deletions

338
BeefRT/rt/BfObjects.h Normal file
View file

@ -0,0 +1,338 @@
#pragma once
#include "BeefySysLib/Common.h"
#include "BeefySysLib/util/String.h"
#define BFRT_VERSION 8
#ifdef BFRT_DYNAMIC
#define BFRT_EXPORT __declspec(dllexport)
#else
#define BFRT_EXPORT
#endif
class BfType;
class BfInternalThread;
#define BF_DECLARE_CLASS(ClassName, BaseClassName) static System::ClassVData sBfClassVData;
enum BfObjectFlags : uint8
{
BfObjectFlag_None = 0,
BfObjectFlag_Mark1 = 0x01,
BfObjectFlag_Mark2 = 0x02,
BfObjectFlag_Mark3 = 0x03,
BfObjectFlag_Allocated = 0x04,
BfObjectFlag_StackAlloc = 0x08,
BfObjectFlag_AppendAlloc = 0x10,
BfObjectFlag_AllocInfo = 0x20,
BfObjectFlag_AllocInfo_Short= 0x40,
BfObjectFlag_Deleted = 0x80
};
enum BfRtFlags
{
BfRtFlags_ObjectHasDebugFlags = 1,
BfRtFlags_LeakCheck = 2,
BfRtFlags_SilentCrash = 4,
BfRtFlags_DebugAlloc = 8
};
namespace bf
{
namespace System
{
struct ClassVData;
class Type;
class String;
class Object;
namespace Threading
{
class Thread;
}
}
}
namespace bf
{
namespace System
{
struct DbgRawAllocData
{
Type* mType;
void* mMarkFunc;
int32 mMaxStackTrace; // Only 0, 1, >1 matters
};
class Runtime
{
public:
enum RtCrashReportKind : int32
{
RtCrashReportKind_Default,
RtCrashReportKind_GUI,
RtCrashReportKind_Console,
RtCrashReportKind_PrintOnly,
RtCrashReportKind_None
};
public:
struct BfRtCallbacks
{
void*(*Alloc)(intptr size);
void(*Free)(void* ptr);
void(*Object_Delete)(bf::System::Object* obj);
void(*Object_ToString)(bf::System::Object* obj, bf::System::String* str);
bf::System::Type* (*Object_GetType)(bf::System::Object* obj);
void(*Object_GCMarkMembers)(bf::System::Object* obj);
bf::System::Object* (*Object_DynamicCastToTypeId)(bf::System::Object* obj, int typeId);
void(*Type_GetFullName)(System::Type* type, bf::System::String* str);
bf::System::String* (*String_Alloc)();
const char* (*String_ToCStr)(bf::System::String* str);
bf::System::Threading::Thread* (*Thread_Alloc)();
bf::System::Threading::Thread* (*Thread_GetMainThread)();
void(*Thread_ThreadProc)(bf::System::Threading::Thread* thread);
BfInternalThread* (*Thread_GetInternalThread)(bf::System::Threading::Thread* thread);
void(*Thread_SetInternalThread)(bf::System::Threading::Thread* thread, BfInternalThread* internalThread);
bool(*Thread_IsAutoDelete)(bf::System::Threading::Thread* thread);
void(*Thread_AutoDelete)(bf::System::Threading::Thread* thread);
int32(*Thread_GetMaxStackSize)(bf::System::Threading::Thread* thread);
void(*GC_MarkAllStaticMembers)();
bool(*GC_CallRootCallbacks)();
void(*GC_Shutdown)();
void(*SetErrorString)(const char* str);
void(*DebugMessageData_SetupError)(const char* str, int32 stackWindbackCount);
void(*DebugMessageData_SetupProfilerCmd)(const char* str);
void(*DebugMessageData_Fatal)();
void(*DebugMessageData_Clear)();
};
public:
BFRT_EXPORT static void SetCrashReportKind(RtCrashReportKind crashReportKind);
private:
BFRT_EXPORT static void Init(int version, int flags, BfRtCallbacks* callbacks);
BFRT_EXPORT static void AddCrashInfoFunc(void* func);
BFRT_EXPORT static void SetErrorString(char* errorStr);
BFRT_EXPORT static void Dbg_Init(int version, int flags, BfRtCallbacks* callbacks);
BFRT_EXPORT static void* Dbg_GetCrashInfoFunc();
};
}
}
extern bf::System::Runtime::BfRtCallbacks gBfRtCallbacks;
extern BfRtFlags gBfRtFlags;
namespace bf
{
namespace System
{
struct ClassVData
{
Type* mType;
void* mInterfaceSlots[16];
};
class Object
{
public:
union
{
intptr mClassVData;
struct
{
BfObjectFlags mObjectFlags;
uint8 mClassVDataBytes[sizeof(intptr) - 1];
};
};
#ifndef BFRT_NODBGFLAGS
union
{
void* mAllocCheckPtr;
intptr mDbgAllocInfo; // Meaning depends on object flags- could be PC at allocation
};
#endif
Type* GetType()
{
return gBfRtCallbacks.Object_GetType(this);
}
Type* GetTypeSafe()
{
return NULL;
}
Beefy::String GetTypeName();
};
class Exception : public Object
{
};
typedef int32 TypeId;
class Type : public Object
{
public:
int32 mSize;
TypeId mTypeId;
uint16 mTypeFlags;
int32 mMemberDataOffset;
uint8 mTypeCode;
uint8 mAlign;
Beefy::String GetFullName();
};
class Type_NOFLAGS
{
public:
intptr mClassVData;
int32 mSize;
TypeId mTypeId;
uint16 mTypeFlags;
int32 mMemberDataOffset;
uint8 mTypeCode;
uint8 mAlign;
};
namespace Reflection
{
typedef int16 TypeId;
typedef uint8 FieldFlags;
class TypeInstance : public Type
{
public:
struct FieldData
{
String* mName;
int64 mConstValue;
int32 mDataOffset;
TypeId mFieldTypeId;
FieldFlags mFlags;
int16 mCustomAttributesIdx;
};
struct MethodData
{
String* mName; // mName
void* mPtr;
};
ClassVData* mTypeClassVData;
String* mName;
String* mNamespace;
int32 mInstSize;
int32 mInstAlign;
TypeId mBaseType;
TypeId mUnderlyingType;
TypeId mOuterType;
uint8 mInterfaceSlot;
uint8 mInterfaceCount;
int16 mMethodDataCount;
int16 mPropertyDataCount;
int16 mFieldDataCount;
int16 mConstructorDataCount;
void* mInterfaceDataPtr;
MethodData* mMethodDataPtr;
void* mPropertyDataPtr;
FieldData* mFieldDataPtr;
void* mConstructorDataPtr;
void** mCustomAttrDataPtr;
};
}
struct IntPtr
{
intptr mValue;
};
struct Delegate
{
};
class String : public Object
{
public:
BF_DECLARE_CLASS(String, Object);
private:
BFRT_EXPORT static intptr UTF8GetAllocSize(char* str, intptr strlen, int32 options);
BFRT_EXPORT static intptr UTF8Map(char* str, intptr strlen, char* outStr, intptr outSize, int32 options);
public:
int mLength;
uint mAllocSizeAndFlags;
char* mPtr;
const char* CStr()
{
return gBfRtCallbacks.String_ToCStr(this);
}
};
}
}
/*struct BfDebugMessageData
{
enum MessageType
{
MessageType_None = 0,
MessageType_Error = 1,
MessageType_ProfilerCmd = 2
};
int mMessageType; // 0 = none, 1 = error
int mStackWindbackCount;
int mStrParamLen;
const char* mStrParam;
void* mPCOverride;
////
String mStrBuffer;
void SetupError(const Beefy::String& str, int stackWindbackCount = 0)
{
mMessageType = MessageType_Error;
mStackWindbackCount = stackWindbackCount;
mStrBuffer = str;
mStrParam = mStrBuffer.c_str();
mStrParamLen = (int) mStrBuffer.length();
mPCOverride = NULL;
}
void SetupProfilerCmd(const String& str)
{
mMessageType = MessageType_ProfilerCmd;
mStackWindbackCount = 0;
mStrBuffer = str;
mStrParam = mStrBuffer.c_str();
mStrParamLen = (int) mStrBuffer.length();
mPCOverride = NULL;
}
void Clear()
{
mMessageType = 0;
mStrBuffer.clear();
mStrParamLen = 0;
}
};*/
namespace Beefy
{
String PointerToString(void* ptr);
}
//extern "C" BfDebugMessageData gBfDebugMessageData;
//extern "C" void* BfObjectNew(System::ClassVData* classVData, intptr size, uint8 flags);
//extern "C" void* BfObjectStackInit(System::Object* result, System::ClassVData* classVData);

195
BeefRT/rt/Chars.cpp Normal file
View file

@ -0,0 +1,195 @@
#include "BeefySysLib/Common.h"
#include "BeefySysLib/util/TLSingleton.h"
#include "BfObjects.h"
extern "C"
{
#include "BeefySysLib/third_party/utf8proc/utf8proc.h"
}
namespace bf
{
namespace System
{
struct Char32
{
private:
BFRT_EXPORT static bool get__IsWhiteSpace_EX(char32_t c);
public:
BFRT_EXPORT static char32_t get__ToLower(char32_t c);
BFRT_EXPORT static char32_t get__ToUpper(char32_t c);
BFRT_EXPORT static bool get__IsLower(char32_t c);
BFRT_EXPORT static bool get__IsUpper(char32_t c);
BFRT_EXPORT static bool get__IsLetterOrDigit(char32_t c);
BFRT_EXPORT static bool get__IsLetter(char32_t c);
BFRT_EXPORT static bool get__IsNumber(char32_t c);
};
struct Char16
{
public:
BFRT_EXPORT static char16_t get__ToLower(char16_t c);
BFRT_EXPORT static char16_t get__ToUpper(char16_t c);
BFRT_EXPORT static bool get__IsLower(char16_t c);
BFRT_EXPORT static bool get__IsUpper(char16_t c);
BFRT_EXPORT static bool get__IsWhiteSpace(char16_t c);
BFRT_EXPORT static bool get__IsLetterOrDigit(char16_t c);
BFRT_EXPORT static bool get__IsLetter(char16_t c);
BFRT_EXPORT static bool get__IsNumber(char16_t c);
};
}
}
char32_t bf::System::Char32::get__ToLower(char32_t c)
{
return utf8proc_tolower(c);
}
char32_t bf::System::Char32::get__ToUpper(char32_t c)
{
return utf8proc_toupper(c);
}
bool bf::System::Char32::get__IsLower(char32_t c)
{
return utf8proc_category(c) == UTF8PROC_CATEGORY_LL;
}
bool bf::System::Char32::get__IsUpper(char32_t c)
{
return utf8proc_category(c) == UTF8PROC_CATEGORY_LU;
}
bool bf::System::Char32::get__IsWhiteSpace_EX(char32_t c)
{
auto cat = utf8proc_category(c);
return (cat == UTF8PROC_CATEGORY_ZS) || (cat == UTF8PROC_CATEGORY_ZL) || (cat == UTF8PROC_CATEGORY_ZP);
}
bool bf::System::Char32::get__IsLetterOrDigit(char32_t c)
{
auto cat = utf8proc_category(c);
switch (cat)
{
case UTF8PROC_CATEGORY_LU:
case UTF8PROC_CATEGORY_LL:
case UTF8PROC_CATEGORY_LT:
case UTF8PROC_CATEGORY_LM:
case UTF8PROC_CATEGORY_LO:
case UTF8PROC_CATEGORY_ND:
case UTF8PROC_CATEGORY_NL:
case UTF8PROC_CATEGORY_NO: return true;
}
return false;
}
bool bf::System::Char32::get__IsLetter(char32_t c)
{
auto cat = utf8proc_category(c);
switch (cat)
{
case UTF8PROC_CATEGORY_LU:
case UTF8PROC_CATEGORY_LL:
case UTF8PROC_CATEGORY_LT:
case UTF8PROC_CATEGORY_LM:
case UTF8PROC_CATEGORY_LO: return true;
}
return false;
}
bool bf::System::Char32::get__IsNumber(char32_t c)
{
auto cat = utf8proc_category(c);
switch (cat)
{
case UTF8PROC_CATEGORY_ND:
case UTF8PROC_CATEGORY_NL:
case UTF8PROC_CATEGORY_NO: return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
char16_t bf::System::Char16::get__ToLower(char16_t c)
{
return utf8proc_tolower(c);
}
char16_t bf::System::Char16::get__ToUpper(char16_t c)
{
return utf8proc_toupper(c);
}
bool bf::System::Char16::get__IsLower(char16_t c)
{
return utf8proc_category(c) == UTF8PROC_CATEGORY_LL;
}
bool bf::System::Char16::get__IsUpper(char16_t c)
{
return utf8proc_category(c) == UTF8PROC_CATEGORY_LU;
}
bool bf::System::Char16::get__IsWhiteSpace(char16_t c)
{
return utf8proc_category(c) == UTF8PROC_CATEGORY_ZS;
}
bool bf::System::Char16::get__IsLetterOrDigit(char16_t c)
{
auto cat = utf8proc_category(c);
switch (cat)
{
case UTF8PROC_CATEGORY_LU:
case UTF8PROC_CATEGORY_LL:
case UTF8PROC_CATEGORY_LT:
case UTF8PROC_CATEGORY_LM:
case UTF8PROC_CATEGORY_LO:
case UTF8PROC_CATEGORY_ND:
case UTF8PROC_CATEGORY_NL:
case UTF8PROC_CATEGORY_NO: return true;
}
return false;
}
bool bf::System::Char16::get__IsLetter(char16_t c)
{
auto cat = utf8proc_category(c);
switch (cat)
{
case UTF8PROC_CATEGORY_LU:
case UTF8PROC_CATEGORY_LL:
case UTF8PROC_CATEGORY_LT:
case UTF8PROC_CATEGORY_LM:
case UTF8PROC_CATEGORY_LO: return true;
}
return false;
}
bool bf::System::Char16::get__IsNumber(char16_t c)
{
auto cat = utf8proc_category(c);
switch (cat)
{
case UTF8PROC_CATEGORY_ND:
case UTF8PROC_CATEGORY_NL:
case UTF8PROC_CATEGORY_NO: return true;
}
return false;
}
intptr bf::System::String::UTF8GetAllocSize(char* str, intptr strlen, int32 options)
{
return utf8proc_decompose_custom((const utf8proc_uint8_t*)str, strlen, NULL, 0, (utf8proc_option_t)options, NULL, NULL);
}
intptr bf::System::String::UTF8Map(char* str, intptr strlen, char* outStr, intptr outSize, int32 options)
{
intptr result = utf8proc_decompose_custom((const utf8proc_uint8_t*)str, strlen, (utf8proc_int32_t*)outStr, outSize, (utf8proc_option_t)options, NULL, NULL);
if (result < 0)
return result;
result = utf8proc_reencode((utf8proc_int32_t*)outStr, outSize, (utf8proc_option_t)options);
return result;
}

910
BeefRT/rt/Internal.cpp Normal file
View file

@ -0,0 +1,910 @@
#pragma warning(disable:4996)
#define HEAPHOOK
//#define USE_CHARCONV
#include <stdio.h>
//#include <crtdefs.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
//#include <intrin.h>
#ifdef USE_CHARCONV
#include <charconv>
#endif
//#define OBJECT_GUARD_END_SIZE 8
#define OBJECT_GUARD_END_SIZE 0
//#define BF_USE_STOMP_ALLOC 1
//extern "C"
//{
//#include "gperftools/stacktrace.h"
//}
#ifdef _MSC_VER
#include <intrin.h>
#pragma intrinsic(_ReturnAddress)
#define BF_RETURN_ADDRESS _ReturnAddress()
#else
#define BF_RETURN_ADDRESS __builtin_return_address(0)
#endif
#include "BeefySysLib/Common.h"
#include "BfObjects.h"
//#include "gc.h"
#include "StompAlloc.h"
#include "BeefySysLib/platform/PlatformHelper.h"
#include "ffi.h"
#include "Thread.h"
#ifdef BF_PLATFORM_WINDOWS
#include <fcntl.h>
#include <io.h>
#endif
USING_NS_BF;
static Beefy::StringT<0> gCmdLineString;
bf::System::Runtime::BfRtCallbacks gBfRtCallbacks;
BfRtFlags gBfRtFlags = (BfRtFlags)0;
namespace bf
{
namespace System
{
class Object;
class Exception;
//System::Threading::Thread* gMainThread;
class Internal
{
private:
BFRT_EXPORT static void __BfStaticCtor();
BFRT_EXPORT static void __BfStaticDtor();
BFRT_EXPORT static void BfStaticCtor();
BFRT_EXPORT static void BfStaticDtor();
BFRT_EXPORT static void Shutdown();
public:
BFRT_EXPORT static Object* UnsafeCastToObject(void* inPtr);
BFRT_EXPORT static void* UnsafeCastToPtr(Object* obj);
BFRT_EXPORT static void ObjectDynCheck(Object* object, int typeId, bool allowNull);
BFRT_EXPORT static void ObjectDynCheckFailed(Object* object, int typeId);
BFRT_EXPORT static void Throw(Exception* ex);
BFRT_EXPORT static void ThrowIndexOutOfRange(intptr stackOffset);
BFRT_EXPORT static void FatalError(String* error, intptr stackOffset = 0);
BFRT_EXPORT static void MemCpy(void* dest, void* src, intptr length);
BFRT_EXPORT static void MemMove(void* dest, void* src, intptr length);
BFRT_EXPORT static void MemSet(void* addr, uint8 val, intptr length);
BFRT_EXPORT static int CStrLen(char* charPtr);
BFRT_EXPORT static void* Malloc(intptr length);
BFRT_EXPORT static void Free(void* ptr);
BFRT_EXPORT static void* VirtualAlloc(intptr size, bool canExecute, bool canWrite);
BFRT_EXPORT static int64 GetTickCountMicro();
BFRT_EXPORT static void BfDelegateTargetCheck(void* target);
BFRT_EXPORT static void* LoadSharedLibrary(char* filePath);
BFRT_EXPORT static void LoadSharedLibraryInto(char* filePath, void** libDest);
BFRT_EXPORT static void* GetSharedProcAddress(void* libHandle, char* procName);
BFRT_EXPORT static void GetSharedProcAddressInto(void* libHandle, char* procName, void** procDest);
BFRT_EXPORT static char* GetCommandLineArgs();
BFRT_EXPORT static void BfLog(char* str);
BFRT_EXPORT static void ProfilerCmd(char* str);
BFRT_EXPORT static void ReportMemory();
private:
BFRT_EXPORT static void Test_Init(char* testData);
BFRT_EXPORT static int32 Test_Query();
BFRT_EXPORT static void Test_Finish();
};
namespace IO
{
class File
{
private:
BFRT_EXPORT static bool Exists(char* fileName);
};
class Directory
{
private:
BFRT_EXPORT static bool Exists(char* fileName);
};
}
namespace Diagnostics
{
namespace Contracts
{
class Contract
{
public:
enum ContractFailureKind : uint8
{
ContractFailureKind_Precondition,
//[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Postcondition")]
ContractFailureKind_Postcondition,
//[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Postcondition")]
ContractFailureKind_PostconditionOnException,
ContractFailureKind_Invariant,
ContractFailureKind_Assert,
ContractFailureKind_Assume,
};
private:
BFRT_EXPORT static void ReportFailure(ContractFailureKind failureKind, char* userMessage, int userMessageLen, char* conditionText, int conditionTextLen);
};
}
class Debug
{
private:
BFRT_EXPORT static void Write(char* str, intptr strLen);
};
}
namespace FFI
{
enum FFIABI : int32;
enum FFIResult : int32;
struct FFIType;
struct FFILIB
{
struct FFICIF;
BFRT_EXPORT static void* ClosureAlloc(intptr size, void** outFunc);
BFRT_EXPORT static FFIResult PrepCif(FFICIF* cif, FFIABI abi, int32 nargs, FFIType* rtype, FFIType** argTypes);
BFRT_EXPORT static void Call(FFICIF* cif, void* funcPtr, void* rvalue, void** args);
};
}
struct Float
{
private:
BFRT_EXPORT static int ToString(float f, char* outStr);
};
struct Double
{
private:
BFRT_EXPORT static int ToString(double f, char* outStr);
};
}
}
//#define BF_TRACK_SIZES 1
#if BF_TRACK_SIZES
static int sAllocSizes[1024*1024];
static int sHighestId = 0;
#endif
using namespace bf::System;
#ifndef BF_PLATFORM_WINDOWS
bool IsDebuggerPresent()
{
return false;
}
#endif
extern "C" BFRT_EXPORT int BF_CALLTYPE ftoa(float val, char* str)
{
return sprintf(str, "%1.9f", val);
}
/*static void* MallocHook(size_t size, const void *caller)
{
printf("MallocHook\n");
return NULL;
}*/
/*static int __cdecl HeapHook(int a, size_t b, void* c, void** d)
{
printf("Heap Hook\n");
return 0;
}*/
//////////////////////////////////////////////////////////////////////////
//static Beefy::StringT<0> gErrorString;
static const char* volatile gErrorString = NULL;
void SetErrorString(const char* str)
{
char* newStr = strdup(str);
while (true)
{
const char* prevStr = gErrorString;
auto result = ::InterlockedCompareExchangePointer((void* volatile*)&gErrorString, (void*)newStr, (void*)prevStr);
if (result != prevStr)
continue;
if (prevStr != NULL)
free((void*)prevStr);
break;
}
}
#define SETUP_ERROR(str, skip) SetErrorString(str); gBfRtCallbacks.DebugMessageData_SetupError(str, skip)
static void GetCrashInfo()
{
auto errorString = gErrorString;
if (errorString != NULL)
{
Beefy::String debugStr;
debugStr += "Beef Error: ";
debugStr += (const char*)errorString;
BfpSystem_AddCrashInfo(debugStr.c_str());
}
}
void bf::System::Runtime::Init(int version, int flags, BfRtCallbacks* callbacks)
{
BfpSystemInitFlags sysInitFlags = BfpSystemInitFlag_InstallCrashCatcher;
if ((flags & 4) != 0)
sysInitFlags = (BfpSystemInitFlags)(sysInitFlags | BfpSystemInitFlag_SilentCrash);
BfpSystem_Init(BFP_VERSION, sysInitFlags);
BfpSystem_AddCrashInfoFunc(GetCrashInfo);
if (version != BFRT_VERSION)
{
BfpSystem_FatalError(StrFormat("BeefRT build version '%d' does not match requested version '%d'", BFRT_VERSION, version).c_str(), "BEEF FATAL ERROR");
}
gBfRtCallbacks = *callbacks;
gBfRtFlags = (BfRtFlags)flags;
Beefy::String cmdLine;
BfpSystemResult result;
BFP_GETSTR_HELPER(cmdLine, result, BfpSystem_GetCommandLine(__STR, __STRLEN, &result));
char* cmdLineStr = (char*)cmdLine.c_str();
//::MessageBoxA(NULL, cmdLineStr, "BFRT", 0);
char* useCmdLineStr = cmdLineStr;
if (cmdLineStr[0] != 0)
{
bool nameQuoted = cmdLineStr[0] == '\"';
Beefy::String passedName;
int i;
for (i = (nameQuoted ? 1 : 0); cmdLineStr[i] != 0; i++)
{
wchar_t c = cmdLineStr[i];
if (((nameQuoted) && (c == '"')) ||
((!nameQuoted) && (c == ' ')))
{
i++;
break;
}
passedName += cmdLineStr[i];
}
useCmdLineStr += i;
while (*useCmdLineStr == L' ')
useCmdLineStr++;
}
gCmdLineString = useCmdLineStr;
}
void bf::System::Runtime::SetErrorString(char* errorStr)
{
::SetErrorString(errorStr);
}
void bf::System::Runtime::AddCrashInfoFunc(void* func)
{
BfpSystem_AddCrashInfoFunc(*(BfpCrashInfoFunc*)&func);
}
void bf::System::Runtime::SetCrashReportKind(bf::System::Runtime::RtCrashReportKind crashReportKind)
{
BfpSystem_SetCrashReportKind((BfpCrashReportKind)crashReportKind);
}
//////////////////////////////////////////////////////////////////////////
void Internal::Shutdown()
{
BfInternalThread::WaitForAllDone();
if (gBfRtCallbacks.GC_Shutdown != NULL)
gBfRtCallbacks.GC_Shutdown();
BfpSystem_Shutdown();
}
void Internal::BfStaticCtor()
{
__BfStaticCtor();
}
void Internal::__BfStaticCtor()
{
}
void Internal::BfStaticDtor()
{
}
void Internal::__BfStaticDtor()
{
}
Object* Internal::UnsafeCastToObject(void* inPtr)
{
return (Object*)inPtr;
}
void* Internal::UnsafeCastToPtr(Object* obj)
{
return (void*)obj;
}
void Internal::Throw(Exception* ex)
{
bf::System::String* exStr = gBfRtCallbacks.String_Alloc();
gBfRtCallbacks.Object_ToString(ex, exStr);
Beefy::String errorStr = StrFormat("FATAL: %s", exStr->CStr());
SETUP_ERROR(errorStr.c_str(), 1);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
printf("Thrown: %s", errorStr.c_str());
//TODO: What about capturing callstack?
exit(3);
//throw ex;
}
void Internal::ThrowIndexOutOfRange(intptr stackOffset)
{
if ((stackOffset != -1) && (::IsDebuggerPresent()))
{
SETUP_ERROR("Index out of range", (int)(2 + stackOffset));
BF_DEBUG_BREAK();
}
BfpSystem_FatalError("Index out of range", "FATAL ERROR");
}
void Internal::FatalError(bf::System::String* error, intptr stackOffset)
{
if ((stackOffset != -1) && (::IsDebuggerPresent()))
{
SETUP_ERROR(error->CStr(), (int)(2 + stackOffset));
BF_DEBUG_BREAK();
}
BfpSystem_FatalError(error->CStr(), "FATAL ERROR");
}
void Internal::MemCpy(void* dest, void* src, intptr length)
{
memcpy(dest, src, length);
}
void Internal::MemMove(void* dest, void* src, intptr length)
{
memmove(dest, src, length);
}
void Internal::MemSet(void* addr, uint8 val, intptr length)
{
memset(addr, val, length);
}
int Internal::CStrLen(char* charPtr)
{
return (int)strlen(charPtr);
}
void* Internal::Malloc(intptr length)
{
#if BF_USE_STOMP_ALLOC
return StompAlloc(length);
#elif BF_TRACK_SIZES
uint8* allocPtr = (uint8*)malloc(length + 16);
*((int*)allocPtr) = length;
sAllocSizes[0] += length;
return allocPtr + 16;
#else
return malloc(length);
#endif
}
void* Internal::VirtualAlloc(intptr size, bool canExecute, bool canWrite)
{
#ifdef BF_PLATFORM_WINDOWS
OutputDebugStrF("Performing VirtualAlloc: %d %d %d\n", size, canExecute, canWrite);
int prot = PAGE_READWRITE;
if (canExecute && canWrite)
prot = PAGE_EXECUTE_READWRITE;
else if (canExecute)
prot = PAGE_EXECUTE_READ;
void* ptr = ::VirtualAlloc(NULL, size, MEM_RESERVE, prot);
return ptr;
#else
BF_FATAL("Not supported");
#endif
}
void Internal::Free(void* ptr)
{
#if BF_USE_STOMP_ALLOC
StompFree(ptr);
#elif BF_TRACK_SIZES
uint8* allocPtr = ((uint8*)ptr) - 16;
sAllocSizes[0] -= *((int*)allocPtr);
free(allocPtr);
#else
free(ptr);
#endif
}
BFRT_EXPORT int64 Internal::GetTickCountMicro()
{
return BFGetTickCountMicro();
}
void Internal::BfDelegateTargetCheck(void* target)
{
if (target != NULL)
{
SETUP_ERROR("Attempting pass non-static method reference to extern method", 2);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
}
}
void* Internal::LoadSharedLibrary(char* libName)
{
//::MessageBox(NULL, "Hey", "Dude", 0);
void* libHandle = BfpDynLib_Load(libName);
if (libHandle == NULL)
{
Beefy::String errorStr = StrFormat("Failed to load shared library: %s", libName);
SETUP_ERROR(errorStr.c_str(), 1);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
}
return libHandle;
}
void Internal::LoadSharedLibraryInto(char* libName, void** libDest)
{
if (*libDest == NULL)
*libDest = LoadSharedLibrary(libName);
}
void* Internal::GetSharedProcAddress(void* libHandle, char* procName)
{
if (libHandle == NULL)
return NULL;
void* procAddr = BfpDynLib_GetProcAddress((BfpDynLib*)libHandle, procName);
if (procAddr == NULL)
{
char libFileName[4096];
int libFileNameLen = 4096;
BfpDynLib_GetFilePath((BfpDynLib*)libHandle, libFileName, &libFileNameLen, NULL);
Beefy::String errorStr = StrFormat("Failed to load shared procedure '%s' from '%s'", procName, libFileName);
SETUP_ERROR(errorStr.c_str(), 1);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
}
return procAddr;
}
void Internal::GetSharedProcAddressInto(void* libHandle, char* procName, void** procDest)
{
*procDest = GetSharedProcAddress(libHandle, procName);
}
char* Internal::GetCommandLineArgs()
{
return (char*)gCmdLineString.c_str();
}
void Internal::BfLog(char* str)
{
// static int lineNum = 0;
// lineNum++;
//
// static FILE* fp = fopen("dbg_internal.txt", "wb");
//
// Beefy::String aResult = StrFormat("%d ", lineNum) + str;
// fwrite(aResult.c_str(), 1, aResult.length(), fp);
// fflush(fp);
}
void Internal::ProfilerCmd(char* str)
{
if (!::IsDebuggerPresent())
return;
gBfRtCallbacks.DebugMessageData_SetupProfilerCmd(str);
BF_DEBUG_BREAK();
}
void Internal::ReportMemory()
{
int totalMem = 0;
#if BF_TRACK_SIZES
for (int i = 0; i <= sHighestId; i++)
totalMem += sAllocSizes[i];
OutputDebugStrF("Beef Object Memory: %dk\n", totalMem / 1024);
#endif
}
static int gTestMethodIdx = -1;
static uint32 gTestStartTick = 0;
static BfpFile* gClientPipe = NULL;
static Beefy::String gTestInBuffer;
static void TestString(const StringImpl& str)
{
BfpFileResult fileResult;
BfpFile_Write(gClientPipe, str.c_str(), str.length(), -1, &fileResult);
BF_ASSERT_REL(fileResult == BfpFileResult_Ok);
}
static void TestReadCmd(Beefy::String& str)
{
while (true)
{
int crPos = (int)gTestInBuffer.IndexOf('\n');
if (crPos != -1)
{
str = gTestInBuffer.Substring(0, crPos);
gTestInBuffer.Remove(0, crPos + 1);
return;
}
char data[1024];
BfpFileResult fileResult;
int readSize = (int)BfpFile_Read(gClientPipe, data, 1024, -1, &fileResult);
if ((fileResult == BfpFileResult_Ok) || (fileResult == BfpFileResult_PartialData))
{
gTestInBuffer.Append(data, readSize);
}
else
{
BF_FATAL("Failed to read pipe to test manager");
}
}
}
void Internal::Test_Init(char* testData)
{
BfpSystem_SetCrashReportKind(BfpCrashReportKind_None);
Beefy::String args = GetCommandLineArgs();
BfpFileResult fileResult;
gClientPipe = BfpFile_Create(args.c_str(), BfpFileCreateKind_OpenExisting, (BfpFileCreateFlags)(BfpFileCreateFlag_Read | BfpFileCreateFlag_Write | BfpFileCreateFlag_Pipe), BfpFileAttribute_None, &fileResult);
if (fileResult != BfpFileResult_Ok)
BF_FATAL("Test_Init failed to create pipe to test manager");
Beefy::String outStr;
outStr += ":TestInit\n";
outStr += testData;
outStr += "\n";
outStr += ":TestBegin\n";
TestString(outStr);
}
int32 Internal::Test_Query()
{
if (gTestMethodIdx != -1)
{
uint32 tickEnd = BfpSystem_TickCount();
TestString(StrFormat(":TestResult\t%d\n", tickEnd - gTestStartTick));
}
TestString(":TestQuery\n");
Beefy::String result;
TestReadCmd(result);
Beefy::String param;
int tabPos = (int)result.IndexOf('\t');
if (tabPos != -1)
{
param = result.Substring(tabPos + 1);
result.RemoveToEnd(tabPos);
}
if (result == ":TestRun")
{
gTestStartTick = BfpSystem_TickCount();
gTestMethodIdx = atoi(param.c_str());
return gTestMethodIdx;
}
else if (result == ":TestFinish")
{
return -1;
}
else
{
printf("Command Str: %s\n", result.c_str());
BF_FATAL("Invalid test command string from test manager");
}
return false;
}
void Internal::Test_Finish()
{
TestString(":TestFinish\n");
if (gClientPipe != NULL)
{
BfpFile_Release(gClientPipe);
gClientPipe = NULL;
}
}
///
int GetStackTrace(void **result, int max_depth, int skip_count);
void BfLog(const char* fmt ...);
static const int cMaxStackTraceCount = 1024;
struct PendingAllocState
{
bool mHasData;
void* mStackTrace[cMaxStackTraceCount];
int mStackTraceCount;
int mMetadataBytes;
bool IsSmall(intptr curAllocBytes)
{
if ((mStackTraceCount > 255) || (mMetadataBytes > 255))
return false;
const intptr maxSmallObjectSize = ((intptr)1 << ((sizeof(intptr) - 2) * 8)) - 1;
if (curAllocBytes <= maxSmallObjectSize)
return true;
intptr objBytes = curAllocBytes - mStackTraceCount*sizeof(intptr) - mMetadataBytes;
return (objBytes < maxSmallObjectSize);
}
};
void Internal::ObjectDynCheck(bf::System::Object* object, int typeId, bool allowNull)
{
return;
if (object == NULL)
{
if (allowNull)
return;
SETUP_ERROR("Attempting unboxing on null object", 1);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
return;
}
auto result = gBfRtCallbacks.Object_DynamicCastToTypeId(object, typeId);
if (result == NULL)
{
Beefy::String errorStr = "Attempting invalid cast on object";
//errorStr += StrFormat("\x1LEAK\t0x%@\n (%s)0x%@\n", object, object->GetTypeName().c_str(), object);
errorStr += StrFormat("\x1LEAK\t0x%@\n (%s)0x%@\n", object, "System.Object", object);
SETUP_ERROR(errorStr.c_str(), 2);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
}
}
void Internal::ObjectDynCheckFailed(bf::System::Object* object, int typeId)
{
if (object == NULL)
{
SETUP_ERROR("Attempting unboxing on null object", 1);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
return;
}
Beefy::String errorStr = "Attempting invalid cast on object";
errorStr += StrFormat("\x1LEAK\t0x%@\n (%s)0x%@\n", object, "System.Object", object);
SETUP_ERROR(errorStr.c_str(), 2);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
}
extern "C" BFRT_EXPORT int PrintF(const char* fmt, ...)
{
int ret;
/* Declare a va_list type variable */
va_list myargs;
/* Initialise the va_list variable with the ... after fmt */
va_start(myargs, fmt);
/* Forward the '...' to vprintf */
ret = vprintf(fmt, myargs);
/* Clean up the va_list */
va_end(myargs);
return ret;
}
///
using namespace bf::System::Diagnostics::Contracts;
void Contract::ReportFailure(Contract::ContractFailureKind failureKind, char* userMessage, int userMessageLen, char* conditionText, int conditionTextLen)
{
Beefy::String userMessageStr;
if (userMessageLen > 0)
userMessageStr.Reference(userMessage, userMessageLen);
Beefy::String conditionTextStr;
if (conditionTextLen > 0)
conditionTextStr.Reference(conditionText, conditionTextLen);
Beefy::String errorMsg = "Contract";
if (failureKind == Contract::ContractFailureKind_Assert)
errorMsg += ": Assert failed";
if (userMessage != NULL)
errorMsg += Beefy::String(": ") + userMessageStr;
if (conditionText != NULL)
errorMsg += Beefy::String(": ") + conditionTextStr;
if (::IsDebuggerPresent())
{
SETUP_ERROR(errorMsg.c_str(), 3);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
}
BfpSystem_FatalError(errorMsg.c_str(), "CONTRACT ERROR");
return;
}
void bf::System::Diagnostics::Debug::Write(char* str, intptr strLen)
{
Beefy::String strVal(str, strLen);
OutputDebugStr(strVal);
}
//////////////////////////////////////////////////////////////////////////
bool IO::File::Exists(char* fileName)
{
return BfpFile_Exists(fileName);
}
bool IO::Directory::Exists(char* fileName)
{
return BfpDirectory_Exists(fileName);
}
//////////////////////////////////////////////////////////////////////////
void* bf::System::FFI::FFILIB::ClosureAlloc(intptr size, void** outFunc)
{
return ffi_closure_alloc(size, outFunc);
}
bf::System::FFI::FFIResult bf::System::FFI::FFILIB::PrepCif(bf::System::FFI::FFILIB::FFICIF* cif, bf::System::FFI::FFIABI abi, int32 nargs, bf::System::FFI::FFIType* rtype, bf::System::FFI::FFIType** argTypes)
{
return (bf::System::FFI::FFIResult)ffi_prep_cif((ffi_cif*)cif, (ffi_abi)abi, nargs, (ffi_type*)rtype, (ffi_type**)argTypes);
}
void bf::System::FFI::FFILIB::Call(bf::System::FFI::FFILIB::FFICIF* cif, void* funcPtr, void* rvalue, void** args)
{
ffi_call((ffi_cif*)cif, (void(*)())funcPtr, rvalue, args);
}
//////////////////////////////////////////////////////////////////////////
static int ToString(float d, char* outStr)
{
sprintf(outStr, "%1.9g", d);
int len = (int)strlen(outStr);
for (int i = 0; outStr[i] != 0; i++)
{
if (outStr[i] == '.')
{
int checkC = len - 1;
while (true)
{
char c = outStr[checkC];
if (c == '.')
{
return checkC;
}
else if (c != '0')
{
for (int j = i + 1; j <= checkC; j++)
if (outStr[j] == 'e')
return len;
return checkC + 1;
}
checkC--;
}
}
}
return len;
}
static int ToString(double d, char* outStr)
{
sprintf(outStr, "%1.17g", d);
int len = (int)strlen(outStr);
for (int i = 0; outStr[i] != 0; i++)
{
if (outStr[i] == '.')
{
int checkC = len - 1;
while (true)
{
char c = outStr[checkC];
if (c == '.')
{
return checkC;
}
else if (c == 'e')
{
return len;
}
else if (c != '0')
{
for (int j = i + 1; j <= checkC; j++)
if (outStr[j] == 'e')
return len;
return checkC + 1;
}
checkC--;
}
}
}
return len;
}
int Float::ToString(float f, char* outStr)
{
#ifdef USE_CHARCONV
auto result = std::to_chars(outStr, outStr + 256, f);
return (int)(result.ptr - outStr);
#else
return ::ToString(f, outStr);
#endif
}
int Double::ToString(double d, char* outStr)
{
#ifdef USE_CHARCONV
auto result = std::to_chars(outStr, outStr + 256, d);
return (int)(result.ptr - outStr);
#else
return ::ToString(d, outStr);
#endif
}

244
BeefRT/rt/Math.cpp Normal file
View file

@ -0,0 +1,244 @@
#include <math.h>
#include <stdio.h>
#include "BfObjects.h"
namespace bf
{
namespace System
{
class Math
{
public:
BFRT_EXPORT static float Acos(float d);
BFRT_EXPORT static double Acos(double d);
BFRT_EXPORT static float Asin(float d);
BFRT_EXPORT static double Asin(double d);
BFRT_EXPORT static float Atan(float d);
BFRT_EXPORT static double Atan(double d);
BFRT_EXPORT static float Atan2(float y, float x);
BFRT_EXPORT static double Atan2(double y, double x);
BFRT_EXPORT static float Ceiling(float a);
BFRT_EXPORT static double Ceiling(double a);
BFRT_EXPORT static float Cos(float d);
BFRT_EXPORT static double Cos(double d);
BFRT_EXPORT static float Cosh(float d);
BFRT_EXPORT static double Cosh(double d);
BFRT_EXPORT static float Floor(float d);
BFRT_EXPORT static double Floor(double d);
BFRT_EXPORT static float Sin(float a);
BFRT_EXPORT static double Sin(double a);
BFRT_EXPORT static float Tan(float a);
BFRT_EXPORT static double Tan(double a);
BFRT_EXPORT static float Sinh(float value);
BFRT_EXPORT static double Sinh(double value);
BFRT_EXPORT static float Tanh(float value);
BFRT_EXPORT static double Tanh(double value);
BFRT_EXPORT static float Round(float a);
BFRT_EXPORT static double Round(double a);
BFRT_EXPORT static float Sqrt(float f);
BFRT_EXPORT static double Sqrt(double d);
BFRT_EXPORT static float Log(float d);
BFRT_EXPORT static double Log(double d);
BFRT_EXPORT static float Log10(float d);
BFRT_EXPORT static double Log10(double d);
BFRT_EXPORT static float Exp(float d);
BFRT_EXPORT static double Exp(double d);
BFRT_EXPORT static float Pow(float x, float y);
BFRT_EXPORT static double Pow(double x, double y);
BFRT_EXPORT static float Abs(float value);
BFRT_EXPORT static double Abs(double value);
};
}
}
using namespace bf::System;
float Math::Acos(float d)
{
return acosf(d);
}
double Math::Acos(double d)
{
return acos(d);
}
float Math::Asin(float d)
{
return asinf(d);
}
double Math::Asin(double d)
{
return asin(d);
}
float Math::Atan(float d)
{
return atanf(d);
}
double Math::Atan(double d)
{
return atan(d);
}
float Math::Atan2(float y, float x)
{
return atan2f(y, x);
}
double Math::Atan2(double y,double x)
{
return atan2(y, x);
}
float Math::Ceiling(float a)
{
return ceilf(a);
}
double Math::Ceiling(double a)
{
return ceil(a);
}
float Math::Cos(float d)
{
return cosf(d);
}
double Math::Cos(double d)
{
return cos(d);
}
float Math::Cosh(float d)
{
return coshf(d);
}
double Math::Cosh(double d)
{
return cosh(d);
}
float Math::Floor(float d)
{
return floorf(d);
}
double Math::Floor(double d)
{
return floor(d);
}
float Math::Sin(float a)
{
return sinf(a);
}
double Math::Sin(double a)
{
return sin(a);
}
float Math::Tan(float a)
{
return tanf(a);
}
double Math::Tan(double a)
{
return tan(a);
}
float Math::Sinh(float value)
{
return sinhf(value);
}
double Math::Sinh(double value)
{
return sinh(value);
}
float Math::Tanh(float value)
{
return tanhf(value);
}
double Math::Tanh(double value)
{
return tanh(value);
}
float Math::Round(float a)
{
return roundf(a);
}
double Math::Round(double a)
{
return round(a);
}
float Math::Sqrt(float f)
{
return sqrtf(f);
}
double Math::Sqrt(double d)
{
return sqrt(d);
}
float Math::Log(float d)
{
return logf(d);
}
double Math::Log(double d)
{
return log(d);
}
float Math::Log10(float d)
{
return log10f(d);
}
double Math::Log10(double d)
{
return log10(d);
}
float Math::Exp(float d)
{
return expf(d);
}
double Math::Exp(double d)
{
return exp(d);
}
float Math::Pow(float x, float y)
{
return powf(x, y);
}
double Math::Pow(double x, double y)
{
return pow(x, y);
}
float Math::Abs(float value)
{
return (float)fabs(value);
}
double Math::Abs(double value)
{
return fabs(value);
}

22
BeefRT/rt/Object.cpp Normal file
View file

@ -0,0 +1,22 @@
#include "BfObjects.h"
USING_NS_BF;
Beefy::String bf::System::Object::GetTypeName()
{
String* strObj = gBfRtCallbacks.String_Alloc();
Type* type = GetType();
gBfRtCallbacks.Type_GetFullName(type, strObj);
Beefy::String str = strObj->CStr();
gBfRtCallbacks.Object_Delete(strObj);
return str;
}
Beefy::String bf::System::Type::GetFullName()
{
String* strObj = gBfRtCallbacks.String_Alloc();
gBfRtCallbacks.Type_GetFullName(this, strObj);
Beefy::String str = strObj->CStr();
gBfRtCallbacks.Object_Delete(strObj);
return str;
}

202
BeefRT/rt/StompAlloc.cpp Normal file
View file

@ -0,0 +1,202 @@
#ifdef BF_USE_STOMP_ALLOC
#include "BeefySysLib/Common.h"
#ifdef BF_PLATFORM_WINDOWS
#include "StompAlloc.h"
#include "BeefySysLib/util/CritSect.h"
#include <list>
#include <assert.h>
USING_NS_BF;
#define STOMP_MAGIC 0xBF12BF34
class BfBitSet
{
public:
uint32* mBits;
public:
BfBitSet(int numBits);
~BfBitSet();
bool IsSet(int idx);
void Set(int idx);
void Clear(int idx);
};
BfBitSet::BfBitSet(int numBits)
{
int numInts = (numBits + 31) / 32;
mBits = new uint32[numInts];
memset(mBits, 0, numInts * 4);
}
BfBitSet::~BfBitSet()
{
delete mBits;
}
bool BfBitSet::IsSet(int idx)
{
return (mBits[idx / 32] & (1 << (idx % 32))) != 0;
}
void BfBitSet::Set(int idx)
{
mBits[idx / 32] |= (1 << (idx % 32));
}
void BfBitSet::Clear(int idx)
{
mBits[idx / 32] &= ~(1 << (idx % 32));
}
struct SA_AllocHeader
{
int mNumPages;
int mMagic;
};
struct SA_AllocRange
{
public:
static const int PAGE_SIZE = 4096;
static const int NUM_PAGES = 0x8000;
uint8* mMemory;
int mSize;
int mLastUsedIdx;
BfBitSet mUsedBits;
public:
SA_AllocRange() : mUsedBits(NUM_PAGES)
{
mMemory = (uint8*)::VirtualAlloc(0, PAGE_SIZE * NUM_PAGES, MEM_RESERVE, PAGE_READWRITE);
mSize = 0;
mLastUsedIdx = -1;
}
~SA_AllocRange()
{
if (mMemory != NULL)
::VirtualFree(mMemory, 0, MEM_RELEASE);
}
int FindFreeRange(int numPages, int from, int to)
{
int lastUsedIdx = from - 1;
for (int pageIdx = from; pageIdx < to; pageIdx++)
{
if (mUsedBits.IsSet(pageIdx))
{
lastUsedIdx = pageIdx;
}
else if (pageIdx - lastUsedIdx >= numPages)
{
return lastUsedIdx + 1;
}
}
return -1;
}
void* Alloc(int size)
{
int numPages = (size + sizeof(SA_AllocHeader) + PAGE_SIZE - 1) / PAGE_SIZE;
int startIdx = FindFreeRange(numPages, mLastUsedIdx + 1, NUM_PAGES);
if (startIdx == -1)
startIdx = FindFreeRange(numPages, 0, mLastUsedIdx);
if (startIdx == -1)
return NULL;
mLastUsedIdx = startIdx + numPages - 1;
for (int markIdx = startIdx; markIdx < startIdx + numPages; markIdx++)
{
mUsedBits.Set(markIdx);
}
uint8* ptr = mMemory + startIdx*PAGE_SIZE;
auto allocHeader = (SA_AllocHeader*)ptr;
::VirtualAlloc(ptr, numPages * PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
allocHeader->mNumPages = numPages;
allocHeader->mMagic = STOMP_MAGIC;
int alignedOffset = sizeof(SA_AllocHeader);
bool alignAtEnd = true;
if (alignAtEnd)
{
alignedOffset = (PAGE_SIZE - (size % PAGE_SIZE));
if (alignedOffset < sizeof(SA_AllocHeader))
{
// For cases where the alloc size (mod PAGE_SIZE) is almost equal to the page size, we need to bump the offset into the next page
// so we don't clobber the SA_AllocHeader
alignedOffset += PAGE_SIZE;
}
}
return ptr + alignedOffset;
}
bool Free(void* ptr)
{
uint8* memPtr = (uint8*)ptr;
if ((memPtr < mMemory) || (memPtr >= mMemory + PAGE_SIZE * NUM_PAGES))
return false;
int pageStart = (int)(memPtr - mMemory) / PAGE_SIZE;
int pageOfs = (int)(memPtr - mMemory) % PAGE_SIZE;
if (pageOfs < sizeof(SA_AllocHeader))
pageStart--; // We actually allocated on the previous page
SA_AllocHeader* allocHeader = (SA_AllocHeader*)(mMemory + pageStart*PAGE_SIZE);
assert(allocHeader->mMagic == STOMP_MAGIC);
for (int pageIdx = pageStart; pageIdx < pageStart + allocHeader->mNumPages; pageIdx++)
{
assert(mUsedBits.IsSet(pageIdx));
mUsedBits.Clear(pageIdx);
}
::VirtualFree(allocHeader, allocHeader->mNumPages * PAGE_SIZE, MEM_DECOMMIT);
return true;
}
};
static std::list<SA_AllocRange> gAllocRanges;
static CritSect gSA_CritSect;
extern "C" void* StompAlloc(intptr size)
{
AutoCrit autoCrit(gSA_CritSect);
while (true)
{
for (auto itr = gAllocRanges.rbegin(); itr != gAllocRanges.rend(); itr++)
{
auto& alloc = *itr;
void* result = alloc.Alloc((int)size);
if (result != NULL)
return result;
}
gAllocRanges.resize(gAllocRanges.size() + 1);
}
}
extern "C" void StompFree(void* addr)
{
AutoCrit autoCrit(gSA_CritSect);
for (auto& alloc : gAllocRanges)
{
if (alloc.Free(addr))
return;
}
assert("Invalid address" == 0);
}
#endif //BF_PLATFORM_WINDOWS
#endif

4
BeefRT/rt/StompAlloc.h Normal file
View file

@ -0,0 +1,4 @@
#pragma once
extern "C" void* StompAlloc(intptr size);
extern "C" void StompFree(void* addr);

4
BeefRT/rt/Test.cpp Normal file
View file

@ -0,0 +1,4 @@
int TestO()
{
return 0;
}

321
BeefRT/rt/Thread.cpp Normal file
View file

@ -0,0 +1,321 @@
#include "BeefySysLib/Common.h"
#include "BfObjects.h"
#include "Thread.h"
//#include "ThreadLocalStorage.h"
#include "StompAlloc.h"
//#include <crtdbg.h>
//#define USE_STOMP_ALLOC
#undef MemoryBarrier
using namespace bf::System;
using namespace bf::System::Threading;
#ifdef BF_THREAD_TLS
BF_TLS_DECLSPEC Thread* Thread::sCurrentThread;
#endif
static volatile int gLiveThreadCount;
static Beefy::SyncEvent gThreadsDoneEvent;
bf::System::Threading::Thread* BfGetCurrentThread()
{
#ifdef BF_THREAD_TLS
return Thread::sCurrentThread;
#else
Thread* internalThread = (Thread*)BfpTLS_GetValue(BfTLSManager::sInternalThreadKey);
return internalThread;
#endif
}
void Thread::SuspendInternal()
{
BfpThread_Suspend(GetInternalThread()->mThreadHandle, NULL);
}
void Thread::ResumeInternal()
{
BfpThread_Resume(GetInternalThread()->mThreadHandle, NULL);
}
void Thread::InterruptInternal()
{
//TODO:
}
void Thread::SetJoinOnDelete(bool joinOnDelete)
{
auto internalThread = GetInternalThread();
Beefy::AutoCrit autoCrit(internalThread->mCritSect);
internalThread->mJoinOnDelete = joinOnDelete;
}
int Thread::GetPriorityNative()
{
return (int)BfpThread_GetPriority(GetInternalThread()->mThreadHandle, NULL);
}
void Thread::SetPriorityNative(int priority)
{
return BfpThread_SetPriority(GetInternalThread()->mThreadHandle, (BfpThreadPriority)priority, NULL);
}
bool Thread::GetIsAlive()
{
if (GetInternalThread() == NULL)
return false;
bool success = BfpThread_WaitFor(GetInternalThread()->mThreadHandle, 0);
return !success;
}
bool Thread::GetIsThreadPoolThread()
{
return false;
}
bool Thread::JoinInternal(int millisecondsTimeout)
{
bool success = BfpThread_WaitFor(GetInternalThread()->mThreadHandle, millisecondsTimeout);
//((BFInternalThread*) thread)->ClrState(Threading::ThreadState::WaitSleepJoin);
return success;
}
void Thread::SleepInternal(int millisecondsTimeout)
{
BfpThread_Sleep(millisecondsTimeout);
}
void Thread::SpinWaitInternal(int iterations)
{
BF_COMPILER_FENCE();
BF_SPINWAIT_NOP();
}
bool Thread::YieldInternal()
{
return BfpThread_Yield();
}
Thread* Thread::GetCurrentThreadNative()
{
return BfGetCurrentThread();
}
unsigned long Thread::GetProcessDefaultStackSize()
{
return 0;
}
static void BF_CALLTYPE CStartProc(void* threadParam)
{
Thread* thread = (Thread*)threadParam;
#ifdef BF_THREAD_TLS
Thread::sCurrentThread = thread;
#else
BfpTLS_SetValue(BfTLSManager::sInternalThreadKey, thread);
#endif
auto internalThread = thread->GetInternalThread();
internalThread->mThreadHandle = BfpThread_GetCurrent();
internalThread->mStackStart = (intptr)&thread;
internalThread->ThreadStarted();
bool isAutoDelete = gBfRtCallbacks.Thread_IsAutoDelete(thread);
gBfRtCallbacks.Thread_ThreadProc(thread);
bool isLastThread = BfpSystem_InterlockedExchangeAdd32((uint32*)&gLiveThreadCount, -1) == 1;
//printf("Stopping thread\n");
bool wantsDelete = false;
//
{
internalThread->ThreadStopped();
Beefy::AutoCrit autoCrit(internalThread->mCritSect);
if (isAutoDelete)
gBfRtCallbacks.Thread_AutoDelete(thread);
internalThread->mDone = true;
if (internalThread->mThread == NULL)
{
// If the thread was already deleted then we need to delete ourselves now
wantsDelete = true;
internalThread = NULL;
}
}
if (wantsDelete)
delete internalThread;
if (isLastThread)
gThreadsDoneEvent.Set(false);
//printf("Thread stopped\n");
}
void BfInternalThread::WaitForAllDone()
{
while (gLiveThreadCount != 0)
{
// Clear out any old done events
gThreadsDoneEvent.WaitFor();
}
}
BfInternalThread* Thread::SetupInternalThread()
{
BfInternalThread* internalThread;
internalThread = new BfInternalThread();
SetInternalThread(internalThread);
return internalThread;
}
void Thread::ManualThreadInit()
{
#ifdef BF_THREAD_TLS
sCurrentThread = this;
#endif
BfInternalThread* internalThread = SetupInternalThread();
internalThread->ManualThreadInit(this);
}
void Thread::StartInternal()
{
BfpSystem_InterlockedExchangeAdd32((uint32*)&gLiveThreadCount, 1);
BfInternalThread* internalThread = SetupInternalThread();
SetInternalThread(internalThread);
internalThread->mThread = this;
internalThread->mThreadHandle = BfpThread_Create(CStartProc, (void*)this, GetMaxStackSize(), BfpThreadCreateFlag_StackSizeReserve, &internalThread->mThreadId);
}
int Thread::GetThreadId()
{
return (int)GetInternalThread()->mThreadId;
}
void Thread::SetStackStart(void* ptr)
{
GetInternalThread()->mRunning = true;
GetInternalThread()->mStackStart = (intptr)ptr;
}
void Thread::InternalFinalize()
{
auto internalThread = GetInternalThread();
bool wantsJoin = false;
//
{
Beefy::AutoCrit autoCrit(internalThread->mCritSect);
if ((!internalThread->mDone) && (internalThread->mJoinOnDelete))
{
if (this != BfGetCurrentThread())
{
wantsJoin = true;
}
}
}
if (wantsJoin)
JoinInternal(0);
bool wantsDelete = false;
//
{
Beefy::AutoCrit autoCrit(internalThread->mCritSect);
if (!internalThread->mDone)
{
// We need to let the internal thread delete itself when it's done...
internalThread->mThread = NULL;
}
else
{
wantsDelete = true;
}
SetInternalThread(NULL);
}
if (wantsDelete)
delete internalThread;
}
bool Thread::IsBackgroundNative()
{
return false;
}
void Thread::SetBackgroundNative(bool isBackground)
{
}
int Thread::GetThreadStateNative()
{
return 0;
}
void Thread::InformThreadNameChange(String* name)
{
BfpThread_SetName(GetInternalThread()->mThreadHandle, (name != NULL) ? name->CStr() : "", NULL);
}
void Thread::MemoryBarrier()
{
BF_FULL_MEMORY_FENCE();
}
//////////////////////////////////////////////////////////////////////////
// BfInternalThread::BfInternalThread()
// {
// #ifdef BF_GC_SUPPORTED
// mBFIThreadData = NULL;
// #endif
//
// mThread = NULL;
// mThreadHandle = 0;
// mStarted = false;
// mRunning = false;
// mDone = false;
// mIsSuspended = false;
// }
//
// BfInternalThread::~BfInternalThread()
// {
// if (mThreadHandle != 0)
// {
// BfpThread_Release(mThreadHandle);
// }
// }
//
// void BfInternalThread::ManualThreadInit(bf::System::Threading::Thread* thread)
// {
// bf::System::Threading::Thread* newThread = thread;
//
// mStarted = true;
// mThread = newThread;
// newThread->SetInternalThread(this);
// mThreadId = BfpThread_GetCurrentId();
// mThreadHandle = BfpThread_GetCurrent();
// mStackStart = ((intptr)&newThread + 0xFFF) & ~(intptr)0xFFF;
// ThreadStarted();
// }
// void BfInternalThread::ThreadStarted()
// {
// BF_ASSERT((gBfRtFlags & BfRtFlags_ObjectHasDebugFlags) == 0);
// int threadPriority = BfpThread_GetPriority(mThreadHandle, NULL);
// mRunning = true;
// }
//
// void BfInternalThread::ThreadStopped()
// {
// BF_ASSERT((gBfRtFlags & BfRtFlags_ObjectHasDebugFlags) == 0);
// mRunning = false;
// }

163
BeefRT/rt/Thread.h Normal file
View file

@ -0,0 +1,163 @@
#pragma once
#include "BeefySysLib/Common.h"
#include "BeefySysLib/util/CritSect.h"
#include "BfObjects.h"
#include "ThreadLocalStorage.h"
#ifdef BF_HAS_TLS_DECLSPEC
#define BF_THREAD_TLS
#endif
#pragma push_macro("MemoryBarrier")
#undef MemoryBarrier
class BfDbgInternalThread;
namespace bf
{
namespace System
{
namespace Threading
{
struct ThreadHandle
{
};
class Thread : public Object
{
private:
Thread();
public:
BF_DECLARE_CLASS(Thread, Object);
#ifdef BF_THREAD_TLS
static BF_TLS_DECLSPEC Thread* sCurrentThread;
#endif
private:
BfInternalThread* SetupInternalThread();
BFRT_EXPORT void ManualThreadInit();
BFRT_EXPORT void SuspendInternal();
BFRT_EXPORT void ResumeInternal();
BFRT_EXPORT void InterruptInternal();
BFRT_EXPORT int GetPriorityNative();
BFRT_EXPORT void SetPriorityNative(int priority);
BFRT_EXPORT void SetJoinOnDelete(bool joinOnDelete);
BFRT_EXPORT bool GetIsAlive();
BFRT_EXPORT bool GetIsThreadPoolThread();
BFRT_EXPORT bool JoinInternal(int millisecondsTimeout);
BFRT_EXPORT static void SleepInternal(int millisecondsTimeout);
BFRT_EXPORT static void SpinWaitInternal(int iterations);
BFRT_EXPORT static bool YieldInternal();
BFRT_EXPORT static Thread* GetCurrentThreadNative();
BFRT_EXPORT unsigned long GetProcessDefaultStackSize();
BFRT_EXPORT void StartInternal();
BFRT_EXPORT void SetStackStart(void* ptr);
BFRT_EXPORT void InternalFinalize();
BFRT_EXPORT bool IsBackgroundNative();
BFRT_EXPORT void SetBackgroundNative(bool isBackground);
BFRT_EXPORT int GetThreadStateNative();
BFRT_EXPORT void InformThreadNameChange(String* name);
BFRT_EXPORT int GetThreadId();
BFRT_EXPORT void Dbg_CreateInternal();
public:
BFRT_EXPORT static void MemoryBarrier();
static Thread* Alloc()
{
return gBfRtCallbacks.Thread_Alloc();
}
BfInternalThread* GetInternalThread()
{
return gBfRtCallbacks.Thread_GetInternalThread(this);
}
BfDbgInternalThread* Dbg_GetInternalThread()
{
return (BfDbgInternalThread*)gBfRtCallbacks.Thread_GetInternalThread(this);
}
void SetInternalThread(BfInternalThread* internalThread)
{
gBfRtCallbacks.Thread_SetInternalThread(this, internalThread);
}
int GetMaxStackSize()
{
return gBfRtCallbacks.Thread_GetMaxStackSize(this);
}
};
}
} // Namespace System
}
class BfInternalThread
{
public:
bool mIsSuspended;
intptr mStackStart;
bf::System::Threading::Thread* mThread;
bool mRunning;
bool mDone;
bool mStarted;
bool mJoinOnDelete;
BfpThread* mThreadHandle;
intptr mThreadId;
Beefy::CritSect mCritSect;
BfInternalThread()
{
mThread = NULL;
mThreadHandle = 0;
mStarted = false;
mRunning = false;
mDone = false;
mIsSuspended = false;
mJoinOnDelete = true;
mStackStart = 0;
mThreadId = 0;
}
virtual ~BfInternalThread()
{
if (mThreadHandle != 0)
{
BfpThread_Release(mThreadHandle);
}
}
virtual void ManualThreadInit(bf::System::Threading::Thread* thread)
{
bf::System::Threading::Thread* newThread = thread;
mStarted = true;
mThread = newThread;
newThread->SetInternalThread(this);
mThreadId = BfpThread_GetCurrentId();
mThreadHandle = BfpThread_GetCurrent();
mStackStart = ((intptr)&newThread + 0xFFF) & ~(intptr)0xFFF;
ThreadStarted();
}
virtual void ThreadStarted()
{
int threadPriority = BfpThread_GetPriority(mThreadHandle, NULL);
mRunning = true;
}
virtual void ThreadStopped()
{
//printf("TheadStopped\n");
mRunning = false;
}
static void WaitForAllDone();
};
#pragma pop_macro("MemoryBarrier")

View file

@ -0,0 +1,57 @@
#include "ThreadLocalStorage.h"
BfpTLS* BfTLSManager::sInternalThreadKey = 0;
BfTLSManager gBfTLSManager;
uint32 BfTLSManager::Alloc()
{
Beefy::AutoCrit autoCrit(mCritSect);
int idx = 0;
if (mFreeIndices.size() != 0)
{
idx = mFreeIndices.back();
mFreeIndices.pop_back();
}
else
{
idx = mAllocIdx++;
if (mAllocIdx >= mAllocSize)
{
int newSize = std::max(mAllocSize, 4);
BfpTLS** newArr = new BfpTLS*[newSize];
BfTLSDatumRoot** newDatumArr = new BfTLSDatumRoot*[newSize];
if (mAllocSize > 0)
{
memcpy(newArr, mAllocatedKeys, mAllocSize*sizeof(BfpTLS*));
memcpy(newDatumArr, mAssociatedTLSDatums, mAllocSize*sizeof(BfTLSDatumRoot*));
}
mAllocSize = newSize;
BF_FULL_MEMORY_FENCE();
mAllocatedKeys = newArr;
mAssociatedTLSDatums = newDatumArr;
}
}
mAllocatedKeys[idx] = BfpTLS_Create();
mAssociatedTLSDatums[idx] = NULL;
return idx;
}
void BfTLSManager::RegisterTlsDatum(uint32 key, BfTLSDatumRoot* tlsDatum)
{
mAssociatedTLSDatums[key] = tlsDatum;
}
void BfTLSManager::Free(uint32 idx)
{
BfTLSDatumRoot* tlsDatumRoot = (BfTLSDatumRoot*) mAssociatedTLSDatums[idx];
if (tlsDatumRoot != NULL)
tlsDatumRoot->Finalize();
Beefy::AutoCrit autoCrit(mCritSect);
mFreeIndices.push_back(idx);
BfpTLS_Release(mAllocatedKeys[idx]);
}

View file

@ -0,0 +1,150 @@
#pragma once
#include "BeefySysLib/util/CritSect.h"
#include "BeefySysLib/util/Array.h"
#include "BeefySysLib/util/Dictionary.h"
namespace bf
{
namespace System
{
namespace Threading
{
class Thread;
}
}
}
bf::System::Threading::Thread* BfGetCurrentThread();
class BfTLSEntry
{
public:
BfpTLS* mThreadKey;
};
class BfTLSDatumRoot
{
public:
virtual void Finalize() = 0;
};
class BfTLSManager
{
public:
static BfpTLS* sInternalThreadKey;
Beefy::CritSect mCritSect;
BfpTLS** mAllocatedKeys;
BfTLSDatumRoot** mAssociatedTLSDatums;
int mAllocSize;
int mAllocIdx;
Beefy::Array<int> mFreeIndices;
BfTLSManager()
{
sInternalThreadKey = BfpTLS_Create();
mAssociatedTLSDatums = NULL;
mAllocSize = 0;
mAllocIdx = 1;
mAllocatedKeys = NULL;
}
uint32 Alloc();
void RegisterTlsDatum(uint32 key, BfTLSDatumRoot* tlsDatum);
void Free(uint32 idx);
BfpTLS* Lookup(uint32 idx)
{
return mAllocatedKeys[idx];
}
};
extern BfTLSManager gBfTLSManager;
//#define DECLARE_THREAD_LOCAL_STORAGE(memberType) __thread memberType
#define DECLARE_THREAD_LOCAL_STORAGE(memberType) BfTLSStatic<memberType>
class BfTLSStaticBase
{
};
template <class T>
class BFMemClear
{
public:
static void Clear(T& valPtr)
{
memset(&valPtr, 0, sizeof(T));
}
};
template <class T>
class BFNoMemClear
{
public:
static void Clear(T& valPtr)
{
}
};
template <class T, class TClear = BFMemClear<T> >
class BfTLSStatic : public BfTLSStaticBase
{
public:
typedef BfTLSStatic<T, TClear> TLSType;
typedef T TLSInnerType;
typedef T InnerType;
typedef Beefy::Dictionary<bf::System::Threading::Thread*, T*> ValueMapType;
typedef void BFBoxedType;
mutable Beefy::CritSect mCritSect;
mutable uint32 mKey;
mutable ValueMapType mValueMap;
public:
BfTLSStatic()
{
mKey = BfpTLS_Create();
}
T* getSafe() const
{
T* valPtr = (T*) BfpTLS_GetValue(mKey);
if (valPtr == NULL)
{
Beefy::AutoCrit autoCrit(mCritSect);
valPtr = new T();
TClear::Clear(*valPtr);
mValueMap[::BfGetCurrentThread()] = valPtr;
BfpTLS_SetValue(mKey, valPtr);
}
return valPtr;
}
const BfTLSStatic<T>& operator=(const T& rhs) const
{
*getSafe() = rhs;
return *this;
}
T& operator->() const
{
return *getSafe();
}
T& operator*() const
{
return *getSafe();
}
operator T&() const
{
return *getSafe();
}
ValueMapType* GetValueMap()
{
return &mValueMap;
}
};