mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
Initial checkin
This commit is contained in:
parent
c74712dad9
commit
078564ac9e
3242 changed files with 1616395 additions and 0 deletions
338
BeefRT/rt/BfObjects.h
Normal file
338
BeefRT/rt/BfObjects.h
Normal 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
195
BeefRT/rt/Chars.cpp
Normal 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
910
BeefRT/rt/Internal.cpp
Normal 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
244
BeefRT/rt/Math.cpp
Normal 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
22
BeefRT/rt/Object.cpp
Normal 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
202
BeefRT/rt/StompAlloc.cpp
Normal 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
4
BeefRT/rt/StompAlloc.h
Normal 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
4
BeefRT/rt/Test.cpp
Normal file
|
@ -0,0 +1,4 @@
|
|||
int TestO()
|
||||
{
|
||||
return 0;
|
||||
}
|
321
BeefRT/rt/Thread.cpp
Normal file
321
BeefRT/rt/Thread.cpp
Normal 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
163
BeefRT/rt/Thread.h
Normal 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")
|
57
BeefRT/rt/ThreadLocalStorage.cpp
Normal file
57
BeefRT/rt/ThreadLocalStorage.cpp
Normal 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]);
|
||||
}
|
150
BeefRT/rt/ThreadLocalStorage.h
Normal file
150
BeefRT/rt/ThreadLocalStorage.h
Normal 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;
|
||||
}
|
||||
};
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue