forked from LeenkxTeam/LNXSDK
Update
This commit is contained in:
177
Kha/Backends/Kore-hxcpp/khacpp/src/hx/AbcOpCodes.h
Normal file
177
Kha/Backends/Kore-hxcpp/khacpp/src/hx/AbcOpCodes.h
Normal file
@ -0,0 +1,177 @@
|
||||
DEFINE_OP(add,0xa0)
|
||||
DEFINE_OP(add_d,0x9B)
|
||||
DEFINE_OP(add_i,0xC5)
|
||||
DEFINE_OP(applytype,0x53)
|
||||
DEFINE_OP(astype,0x86)
|
||||
DEFINE_OP(astypelate,0x87)
|
||||
DEFINE_OP(bitand,0xa8)
|
||||
DEFINE_OP(bitnot,0x97)
|
||||
DEFINE_OP(bitor,0xa9)
|
||||
DEFINE_OP(bitxor,0xAA)
|
||||
DEFINE_OP(bkpt,0x01)
|
||||
DEFINE_OP(bkptline,0xF2)
|
||||
DEFINE_OP(call,0x41)
|
||||
DEFINE_OP(callinterface,0x4D)
|
||||
DEFINE_OP(callmethod,0x43)
|
||||
DEFINE_OP(callproperty,0x46)
|
||||
DEFINE_OP(callproplex,0x4C)
|
||||
DEFINE_OP(callpropvoid,0x4f)
|
||||
DEFINE_OP(callstatic,0x44)
|
||||
DEFINE_OP(callsuper,0x45)
|
||||
DEFINE_OP(callsuperid,0x4B)
|
||||
DEFINE_OP(callsupervoid,0x4e)
|
||||
DEFINE_OP(checkfilter,0x78)
|
||||
DEFINE_OP(coerce,0x80)
|
||||
DEFINE_OP(coerce_a,0x82)
|
||||
DEFINE_OP(coerce_b,0x81)
|
||||
DEFINE_OP(coerce_d,0x84)
|
||||
DEFINE_OP(coerce_i,0x83)
|
||||
DEFINE_OP(coerce_o,0x89)
|
||||
DEFINE_OP(coerce_s,0x85)
|
||||
DEFINE_OP(coerce_u,0x88)
|
||||
DEFINE_OP(concat,0x9A)
|
||||
DEFINE_OP(construct,0x42)
|
||||
DEFINE_OP(constructprop,0x4a)
|
||||
DEFINE_OP(constructsuper,0x49)
|
||||
DEFINE_OP(convert_b,0x76)
|
||||
DEFINE_OP(convert_d,0x75)
|
||||
DEFINE_OP(convert_i,0x73)
|
||||
DEFINE_OP(convert_o,0x77)
|
||||
DEFINE_OP(convert_s,0x70)
|
||||
DEFINE_OP(convert_u,0x74)
|
||||
DEFINE_OP(debug,0xEF)
|
||||
DEFINE_OP(debugfile,0xF1)
|
||||
DEFINE_OP(debugline,0xF0)
|
||||
DEFINE_OP(declocal,0x94)
|
||||
DEFINE_OP(declocal_i,0xC3)
|
||||
DEFINE_OP(decrement,0x93)
|
||||
DEFINE_OP(decrement_i,0xc1)
|
||||
DEFINE_OP(deleteproperty,0x6a)
|
||||
DEFINE_OP(deletepropertylate,0x6B)
|
||||
DEFINE_OP(divide,0xa3)
|
||||
DEFINE_OP(dup,0x2a)
|
||||
DEFINE_OP(dxns,0x06)
|
||||
DEFINE_OP(dxnslate,0x07)
|
||||
DEFINE_OP(equals,0xab)
|
||||
DEFINE_OP(esc_xattr,0x72)
|
||||
DEFINE_OP(esc_xelem,0x71)
|
||||
DEFINE_OP(finddef,0x5F)
|
||||
DEFINE_OP(findproperty,0x5e)
|
||||
DEFINE_OP(findpropglobal,0x5c)
|
||||
DEFINE_OP(findpropglobalstrict,0x5b)
|
||||
DEFINE_OP(findpropstrict,0x5d)
|
||||
DEFINE_OP(getdescendants,0x59)
|
||||
DEFINE_OP(getglobalscope,0x64)
|
||||
DEFINE_OP(getglobalslot,0x6E)
|
||||
DEFINE_OP(getlex,0x60)
|
||||
DEFINE_OP(getlocal,0x62)
|
||||
DEFINE_OP(getlocal_0,0xd0)
|
||||
DEFINE_OP(getlocal_1,0xd1)
|
||||
DEFINE_OP(getlocal_2,0xd2)
|
||||
DEFINE_OP(getlocal_3,0xd3)
|
||||
DEFINE_OP(getouterscope,0x67)
|
||||
DEFINE_OP(getproperty,0x66)
|
||||
DEFINE_OP(getscopeobject,0x65)
|
||||
DEFINE_OP(getslot,0x6c)
|
||||
DEFINE_OP(getsuper,0x04)
|
||||
DEFINE_OP(greaterequals,0xb0)
|
||||
DEFINE_OP(greaterthan,0xaf)
|
||||
DEFINE_OP(hasnext,0x1F)
|
||||
DEFINE_OP(hasnext2,0x32)
|
||||
DEFINE_OP(ifeq,0x13)
|
||||
DEFINE_OP(iffalse,0x12)
|
||||
DEFINE_OP(ifge,0x18)
|
||||
DEFINE_OP(ifgt,0x17)
|
||||
DEFINE_OP(ifle,0x16)
|
||||
DEFINE_OP(iflt,0x15)
|
||||
DEFINE_OP(ifne,0x14)
|
||||
DEFINE_OP(ifnge,0x0f)
|
||||
DEFINE_OP(ifngt,0x0e)
|
||||
DEFINE_OP(ifnle,0x0d)
|
||||
DEFINE_OP(ifnlt,0x0c)
|
||||
DEFINE_OP(ifstricteq,0x19)
|
||||
DEFINE_OP(ifstrictne,0x1a)
|
||||
DEFINE_OP(iftrue,0x11)
|
||||
DEFINE_OP(in_op,0xb4)
|
||||
DEFINE_OP(inclocal,0x92)
|
||||
DEFINE_OP(inclocal_i,0xc2)
|
||||
DEFINE_OP(increment,0x91)
|
||||
DEFINE_OP(increment_i,0xc0)
|
||||
DEFINE_OP(initproperty,0x68)
|
||||
DEFINE_OP(instance_of,0xB1)
|
||||
DEFINE_OP(istype,0xB2)
|
||||
DEFINE_OP(istypelate,0xb3)
|
||||
DEFINE_OP(jump,0x10)
|
||||
DEFINE_OP(kill,0x08)
|
||||
DEFINE_OP(label,0x09)
|
||||
DEFINE_OP(lessequals,0xae)
|
||||
DEFINE_OP(lessthan,0xad)
|
||||
DEFINE_OP(lf32,0x38)
|
||||
DEFINE_OP(lf64,0x39)
|
||||
DEFINE_OP(li16,0x36)
|
||||
DEFINE_OP(li32,0x37)
|
||||
DEFINE_OP(li8,0x35)
|
||||
DEFINE_OP(lookupswitch,0x1b)
|
||||
DEFINE_OP(lshift,0xa5)
|
||||
DEFINE_OP(modulo,0xa4)
|
||||
DEFINE_OP(multiply,0xa2)
|
||||
DEFINE_OP(multiply_i,0xC7)
|
||||
DEFINE_OP(negate,0x90)
|
||||
DEFINE_OP(negate_i,0xC4)
|
||||
DEFINE_OP(newactivation,0x57)
|
||||
DEFINE_OP(newarray,0x56)
|
||||
DEFINE_OP(newcatch,0x5a)
|
||||
DEFINE_OP(newclass,0x58)
|
||||
DEFINE_OP(newfunction,0x40)
|
||||
DEFINE_OP(newobject,0x55)
|
||||
DEFINE_OP(nextname,0x1e)
|
||||
DEFINE_OP(nextvalue,0x23)
|
||||
DEFINE_OP(nop,0x02)
|
||||
DEFINE_OP(not,0x96)
|
||||
DEFINE_OP(pop,0x29)
|
||||
DEFINE_OP(popscope,0x1d)
|
||||
DEFINE_OP(pushbyte,0x24)
|
||||
DEFINE_OP(pushconstant,0x22)
|
||||
DEFINE_OP(pushdecimal,0x33)
|
||||
DEFINE_OP(pushdnan,0x34)
|
||||
DEFINE_OP(pushdouble,0x2f)
|
||||
DEFINE_OP(pushfalse,0x27)
|
||||
DEFINE_OP(pushint,0x2d)
|
||||
DEFINE_OP(pushnamespace,0x31)
|
||||
DEFINE_OP(pushnan,0x28)
|
||||
DEFINE_OP(pushnull,0x20)
|
||||
DEFINE_OP(pushscope,0x30)
|
||||
DEFINE_OP(pushshort,0x25)
|
||||
DEFINE_OP(pushstring,0x2c)
|
||||
DEFINE_OP(pushtrue,0x26)
|
||||
DEFINE_OP(pushuint,0x2E)
|
||||
DEFINE_OP(pushundefined,0x21)
|
||||
DEFINE_OP(pushwith,0x1c)
|
||||
DEFINE_OP(returnvalue,0x48)
|
||||
DEFINE_OP(returnvoid,0x47)
|
||||
DEFINE_OP(rshift,0xa6)
|
||||
DEFINE_OP(setglobalslot,0x6F)
|
||||
DEFINE_OP(setlocal,0x63)
|
||||
DEFINE_OP(setlocal_0,0xD4)
|
||||
DEFINE_OP(setlocal_1,0xD5)
|
||||
DEFINE_OP(setlocal_2,0xD6)
|
||||
DEFINE_OP(setlocal_3,0xD7)
|
||||
DEFINE_OP(setproperty,0x61)
|
||||
DEFINE_OP(setpropertylate,0x69)
|
||||
DEFINE_OP(setslot,0x6d)
|
||||
DEFINE_OP(setsuper,0x05)
|
||||
DEFINE_OP(sf32,0x3d)
|
||||
DEFINE_OP(sf64,0x3e)
|
||||
DEFINE_OP(si16,0x3b)
|
||||
DEFINE_OP(si32,0x3c)
|
||||
DEFINE_OP(si8,0x3a)
|
||||
DEFINE_OP(strictequals,0xac)
|
||||
DEFINE_OP(subtract,0xa1)
|
||||
DEFINE_OP(subtract_i,0xC6)
|
||||
DEFINE_OP(swap,0x2b)
|
||||
DEFINE_OP(sxi1,0x50)
|
||||
DEFINE_OP(sxi16,0x52)
|
||||
DEFINE_OP(sxi8,0x51)
|
||||
DEFINE_OP(throw_op,0x03)
|
||||
DEFINE_OP(typeof_op,0x95)
|
||||
DEFINE_OP(urshift,0xa7)
|
||||
69
Kha/Backends/Kore-hxcpp/khacpp/src/hx/AndroidCompat.cpp
Normal file
69
Kha/Backends/Kore-hxcpp/khacpp/src/hx/AndroidCompat.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include <hxcpp.h>
|
||||
#include <limits>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <dlfcn.h>
|
||||
#include <android/log.h>
|
||||
|
||||
// These functions are inlined prior to android-ndk-platform-21, which means they
|
||||
// are missing from the libc functions on those phones, and you will get link errors.
|
||||
|
||||
#if 0 && (HXCPP_ANDROID_PLATFORM>=21) && !defined(HXCPP_ARM64)
|
||||
extern "C" {
|
||||
|
||||
|
||||
char * stpcpy(char *dest, const char *src)
|
||||
{
|
||||
register char *d = dest;
|
||||
register const char *s = src;
|
||||
do
|
||||
*d++ = *s;
|
||||
while (*s++ != '\0');
|
||||
return d - 1;
|
||||
}
|
||||
|
||||
|
||||
int rand() { return lrand48(); }
|
||||
|
||||
void srand(unsigned int x) { srand48(x); }
|
||||
|
||||
|
||||
double atof(const char *nptr)
|
||||
{
|
||||
return (strtod(nptr, 0));
|
||||
}
|
||||
// extern __sighandler_t bsd_signal(int, __sighandler_t);
|
||||
|
||||
|
||||
typedef __sighandler_t (*bsd_signal_func_t)(int, __sighandler_t);
|
||||
bsd_signal_func_t bsd_signal_func = 0;
|
||||
|
||||
__sighandler_t bsd_signal(int s, __sighandler_t f)
|
||||
{
|
||||
if (bsd_signal_func == 0)
|
||||
{
|
||||
// For now (up to Android 7.0) this is always available
|
||||
bsd_signal_func = (bsd_signal_func_t) dlsym(RTLD_DEFAULT, "bsd_signal");
|
||||
|
||||
if (bsd_signal_func == 0)
|
||||
{
|
||||
// You may try dlsym(RTLD_DEFAULT, "signal") or dlsym(RTLD_NEXT, "signal") here
|
||||
// Make sure you add a comment here in StackOverflow
|
||||
// if you find a device that doesn't have "bsd_signal" in its libc.so!!!
|
||||
|
||||
__android_log_assert("", "bsd_signal_wrapper", "bsd_signal symbol not found!");
|
||||
}
|
||||
}
|
||||
|
||||
return bsd_signal_func(s, f);
|
||||
}
|
||||
|
||||
__sighandler_t signal(int s, __sighandler_t f)
|
||||
{
|
||||
return bsd_signal(s,f);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
449
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Anon.cpp
Normal file
449
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Anon.cpp
Normal file
@ -0,0 +1,449 @@
|
||||
#include <hxcpp.h>
|
||||
#undef RegisterClass
|
||||
namespace hx
|
||||
{
|
||||
|
||||
Dynamic FieldMapCreate() { return Dynamic(); }
|
||||
|
||||
bool FieldMapGet(FieldMap *inMap, const String &inName, Dynamic &outValue)
|
||||
{
|
||||
if (!inMap || !inMap->mPtr)
|
||||
return false;
|
||||
|
||||
if (!__string_hash_exists(*inMap,inName))
|
||||
return false;
|
||||
outValue = __string_hash_get(*inMap, inName);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FieldMapGet(FieldMap *inMap, int inId, Dynamic &outValue)
|
||||
{
|
||||
if (!inMap || !inMap->mPtr)
|
||||
return false;
|
||||
|
||||
const String &key = __hxcpp_field_from_id(inId);
|
||||
if (!__string_hash_exists(*inMap,key))
|
||||
return false;
|
||||
outValue = __string_hash_get(*inMap, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool FieldMapHas(FieldMap *inMap, const String &inName)
|
||||
{
|
||||
return inMap && inMap->mPtr && __string_hash_exists(*inMap,inName);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HXCPP_GC_GENERATIONAL
|
||||
void FieldMapSet(hx::Object *inThis,FieldMap *inMap, const String &inName, const Dynamic &inValue)
|
||||
{
|
||||
__string_hash_set(inThis,*inMap, inName, inValue,true);
|
||||
}
|
||||
#else
|
||||
void FieldMapSet(FieldMap *inMap, const String &inName, const Dynamic &inValue)
|
||||
{
|
||||
__string_hash_set(*inMap, inName, inValue,true);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void FieldMapAppendFields(FieldMap *inMap,Array<String> &outFields)
|
||||
{
|
||||
Array<String> keys = __string_hash_keys(*inMap);
|
||||
if (outFields->length==0)
|
||||
outFields = keys;
|
||||
else
|
||||
outFields = outFields->concat(keys);
|
||||
}
|
||||
|
||||
|
||||
// -- Anon_obj -------------------------------------------------
|
||||
|
||||
|
||||
|
||||
Anon_obj::Anon_obj(int inElements)
|
||||
{
|
||||
mFixedFields = inElements;
|
||||
//mFields = hx::FieldMapCreate();
|
||||
}
|
||||
|
||||
void Anon_obj::__Mark(hx::MarkContext *__inCtx)
|
||||
{
|
||||
if (mFixedFields)
|
||||
{
|
||||
VariantKey *fixed = getFixed();
|
||||
for(int i=0;i<mFixedFields;i++)
|
||||
HX_MARK_MEMBER(fixed[i].value);
|
||||
}
|
||||
HX_MARK_MEMBER(mFields);
|
||||
}
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void Anon_obj::__Visit(hx::VisitContext *__inCtx)
|
||||
{
|
||||
if (mFixedFields)
|
||||
{
|
||||
VariantKey *fixed = getFixed();
|
||||
for(int i=0;i<mFixedFields;i++)
|
||||
HX_VISIT_MEMBER(fixed[i].value);
|
||||
}
|
||||
HX_VISIT_MEMBER(mFields);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline int Anon_obj::findFixed(const ::String &inKey, bool inSkip5)
|
||||
{
|
||||
if (!mFixedFields || !inKey.isAsciiEncoded() )
|
||||
return -1;
|
||||
VariantKey *fixed = getFixed();
|
||||
|
||||
if (!inSkip5)
|
||||
if (inKey.__s[HX_GC_CONST_ALLOC_MARK_OFFSET] & HX_GC_CONST_ALLOC_MARK_BIT)
|
||||
{
|
||||
for(int i=0;i<mFixedFields;i++)
|
||||
{
|
||||
if (fixed[i].key.__s == inKey.__s)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sought = inKey.hash();
|
||||
|
||||
if (!inSkip5)
|
||||
{
|
||||
if (mFixedFields<5)
|
||||
{
|
||||
for(int i=0;i<mFixedFields;i++)
|
||||
if (fixed[i].hash==sought && (
|
||||
(fixed[i].key.length == inKey.length && !memcmp(fixed[i].key.raw_ptr(),inKey.raw_ptr(), inKey.length))))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Find node with same hash...
|
||||
/* hash example
|
||||
[0] = -3 <- min
|
||||
[1] = -1
|
||||
[2] = -1 (sought -1)
|
||||
[3] = 4
|
||||
[4] = 4 <- max
|
||||
*/
|
||||
|
||||
int min = inSkip5 ? 5 : 0;
|
||||
if (fixed[min].hash>sought)
|
||||
return -1;
|
||||
if (fixed[min].hash!=sought)
|
||||
{
|
||||
int max = mFixedFields;
|
||||
if (fixed[max-1].hash<sought)
|
||||
return -1;
|
||||
|
||||
while(max>min+1)
|
||||
{
|
||||
int mid = (max+min)>>1;
|
||||
if (fixed[mid].hash <= sought)
|
||||
min = mid;
|
||||
else
|
||||
max = mid;
|
||||
}
|
||||
}
|
||||
|
||||
while(fixed[min].hash==sought)
|
||||
{
|
||||
// Might be multiple?
|
||||
if ( fixed[min].key.length == inKey.length && !memcmp(fixed[min].key.raw_ptr(),inKey.raw_ptr(), inKey.length))
|
||||
return min;
|
||||
|
||||
min++;
|
||||
if (min>=mFixedFields)
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
hx::Val Anon_obj::__Field(const String &inName, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (inName.isAsciiEncodedQ())
|
||||
#endif
|
||||
if (mFixedFields>0)
|
||||
{
|
||||
VariantKey *fixed = getFixed();
|
||||
if (inName.__s[HX_GC_CONST_ALLOC_MARK_OFFSET] & HX_GC_CONST_ALLOC_MARK_BIT)
|
||||
{
|
||||
for(int i=0;i<mFixedFields;i++)
|
||||
{
|
||||
if (fixed[i].key.__s == inName.__s)
|
||||
return fixed[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
int hash = inName.hash();
|
||||
if (fixed->hash==hash && HX_QSTR_EQ_AE(fixed->key,inName))
|
||||
return fixed->value;
|
||||
if (mFixedFields>1)
|
||||
{
|
||||
fixed++;
|
||||
if (fixed->hash==hash && HX_QSTR_EQ_AE(fixed->key,inName))
|
||||
return fixed->value;
|
||||
if (mFixedFields>2)
|
||||
{
|
||||
fixed++;
|
||||
if (fixed->hash==hash && HX_QSTR_EQ_AE(fixed->key,inName))
|
||||
return fixed->value;
|
||||
if (mFixedFields>3)
|
||||
{
|
||||
fixed++;
|
||||
if (fixed->hash==hash && HX_QSTR_EQ_AE(fixed->key,inName))
|
||||
return fixed->value;
|
||||
if (mFixedFields>4)
|
||||
{
|
||||
fixed++;
|
||||
if (fixed->hash==hash && HX_QSTR_EQ_AE(fixed->key,inName))
|
||||
return fixed->value;
|
||||
|
||||
int fixed = findFixed(inName,true);
|
||||
if (fixed>=0)
|
||||
return getFixed()[fixed].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!mFields.mPtr)
|
||||
return hx::Val();
|
||||
|
||||
return __string_hash_get(mFields,inName);
|
||||
}
|
||||
|
||||
bool Anon_obj::__HasField(const String &inName)
|
||||
{
|
||||
if (findFixed(inName)>=0)
|
||||
return true;
|
||||
if (!mFields.mPtr)
|
||||
return false;
|
||||
return __string_hash_exists(mFields,inName);
|
||||
}
|
||||
|
||||
bool Anon_obj::__Remove(String inKey)
|
||||
{
|
||||
int slot = findFixed(inKey);
|
||||
if (slot>=0)
|
||||
{
|
||||
VariantKey *fixed = getFixed();
|
||||
while(slot<mFixedFields)
|
||||
{
|
||||
fixed[slot] = fixed[slot+1];
|
||||
slot++;
|
||||
}
|
||||
mFixedFields--;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mFields.mPtr)
|
||||
return false;
|
||||
return __string_hash_remove(mFields,inKey);
|
||||
}
|
||||
|
||||
|
||||
hx::Val Anon_obj::__SetField(const String &inName,const hx::Val &inValue, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
int slot = findFixed(inName);
|
||||
if (slot>=0)
|
||||
{
|
||||
#ifdef HXCPP_GC_GENERATIONAL
|
||||
VariantKey *fixed = getFixed() + slot;
|
||||
fixed->value=inValue;
|
||||
if (fixed->value.type <= cpp::Variant::typeString)
|
||||
HX_OBJ_WB_GET(this, fixed->value.valObject);
|
||||
#else
|
||||
getFixed()[slot].value=inValue;
|
||||
#endif
|
||||
return inValue;
|
||||
}
|
||||
|
||||
// TODO - fixed
|
||||
if (!mFields.mPtr)
|
||||
{
|
||||
mFields = hx::FieldMapCreate();
|
||||
HX_OBJ_WB_GET(this, mFields.mPtr);
|
||||
}
|
||||
|
||||
__string_hash_set(HX_MAP_THIS_ mFields,inName,inValue,true);
|
||||
return inValue;
|
||||
}
|
||||
|
||||
Anon_obj *Anon_obj::Add(const String &inName,const Dynamic &inValue,bool inSetThisPointer)
|
||||
{
|
||||
// TODO - fixed
|
||||
if (!mFields.mPtr)
|
||||
{
|
||||
mFields = hx::FieldMapCreate();
|
||||
HX_OBJ_WB_GET(this, mFields.mPtr);
|
||||
}
|
||||
|
||||
__string_hash_set(HX_MAP_THIS_ mFields,inName,inValue,true);
|
||||
if (inSetThisPointer && inValue.GetPtr())
|
||||
inValue.GetPtr()->__SetThis(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
static int _hx_toString_depth = 0;
|
||||
String Anon_obj::toString()
|
||||
{
|
||||
if (!mFields.mPtr && !mFixedFields)
|
||||
return HX_CSTRING("{ }");
|
||||
|
||||
if (_hx_toString_depth >= 5)
|
||||
return HX_CSTRING("...");
|
||||
|
||||
_hx_toString_depth++;
|
||||
|
||||
try
|
||||
{
|
||||
int fixedToString = findFixed(HX_CSTRING("toString"));
|
||||
if (fixedToString>=0)
|
||||
{
|
||||
Dynamic func = getFixed()[fixedToString].value;
|
||||
if (func!=null())
|
||||
{
|
||||
String res = func();
|
||||
_hx_toString_depth--;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
Dynamic func;
|
||||
if (FieldMapGet(&mFields, HX_CSTRING("toString"), func))
|
||||
{
|
||||
String res = func();
|
||||
_hx_toString_depth--;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (mFixedFields)
|
||||
{
|
||||
Array<String> array = Array<String>(0,mFixedFields*4+4);
|
||||
array->push(HX_CSTRING("{ "));
|
||||
|
||||
if (mFields.mPtr)
|
||||
{
|
||||
String val = __string_hash_to_string_raw(mFields);
|
||||
if (val.raw_ptr())
|
||||
array->push(val);
|
||||
}
|
||||
|
||||
VariantKey *fixed = getFixed();
|
||||
for(int i=0;i<mFixedFields;i++)
|
||||
{
|
||||
if (array->length>1)
|
||||
array->push(HX_CSTRING(", "));
|
||||
|
||||
array->push(fixed[i].key);
|
||||
array->push(HX_CSTRING(" => "));
|
||||
array->push(fixed[i].value);
|
||||
}
|
||||
array->push(HX_CSTRING(" }"));
|
||||
_hx_toString_depth--;
|
||||
return array->join(HX_CSTRING(""));
|
||||
}
|
||||
|
||||
String ret = __string_hash_to_string(mFields);
|
||||
_hx_toString_depth--;
|
||||
return ret;
|
||||
} catch (...)
|
||||
{
|
||||
_hx_toString_depth--;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void Anon_obj::__GetFields(Array<String> &outFields)
|
||||
{
|
||||
if (mFields.mPtr)
|
||||
outFields = __string_hash_keys(mFields);
|
||||
if (mFixedFields>0)
|
||||
{
|
||||
VariantKey *fixed = getFixed();
|
||||
for(int i=0;i<mFixedFields;i++)
|
||||
outFields->push( fixed[i].key );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String Anon_obj::__ToString() const { return HX_CSTRING("Anon"); }
|
||||
|
||||
Dynamic Anon_obj::__Create(DynamicArray inArgs) { return Anon(new (0) Anon_obj); }
|
||||
|
||||
hx::Class Anon_obj::__mClass;
|
||||
|
||||
|
||||
void Anon_obj::__boot()
|
||||
{
|
||||
Static(__mClass) = hx::_hx_RegisterClass(HX_CSTRING("__Anon"),TCanCast<Anon_obj>,sNone,sNone,0,0,0,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Anon SourceInfo(String inFile, int inLine, String inClass, String inMethod)
|
||||
{
|
||||
Anon result = Anon_obj::Create();
|
||||
result->Add(HX_CSTRING("fileName"),inFile);
|
||||
result->Add(HX_CSTRING("lineNumber"),inLine);
|
||||
result->Add(HX_CSTRING("className"),inClass);
|
||||
result->Add(HX_CSTRING("methodName"),inMethod);
|
||||
return result;
|
||||
}
|
||||
|
||||
String StringFromAnonFields(hx::Object *inPtr)
|
||||
{
|
||||
Array<String> fields = Array_obj<String>::__new();
|
||||
inPtr->__GetFields(fields);
|
||||
|
||||
int n = fields->length;
|
||||
Array<String> array = Array<String>(0,n*4+4);
|
||||
array->push(HX_CSTRING("{ "));
|
||||
for(int i=0;i<n;i++)
|
||||
{
|
||||
if (array->length>1)
|
||||
array->push(HX_CSTRING(", "));
|
||||
|
||||
array->push(fields[i]);
|
||||
array->push(HX_CSTRING(" => "));
|
||||
array->push( inPtr->__Field( fields[i], HX_PROP_DYNAMIC) );
|
||||
}
|
||||
array->push(HX_CSTRING(" }"));
|
||||
return array->join(HX_CSTRING(""));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool __hxcpp_anon_remove(Dynamic inObj,String inKey)
|
||||
{
|
||||
hx::Anon_obj *anon = dynamic_cast<hx::Anon_obj *>(inObj.mPtr);
|
||||
if (anon)
|
||||
{
|
||||
bool removed = anon->__Remove(inKey);
|
||||
if (removed)
|
||||
return true;
|
||||
}
|
||||
Dynamic *map = inObj->__GetFieldMap();
|
||||
if (map)
|
||||
return __string_hash_remove(*map,inKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
35
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Boot.cpp
Normal file
35
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Boot.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hxMath.h>
|
||||
|
||||
#ifdef HX_WINRT
|
||||
#include<Roapi.h>
|
||||
#endif
|
||||
namespace hx
|
||||
{
|
||||
|
||||
void Boot()
|
||||
{
|
||||
//__hxcpp_enable(false);
|
||||
#ifdef HX_WINRT
|
||||
HRESULT hr = ::RoInitialize( RO_INIT_MULTITHREADED );
|
||||
#endif
|
||||
|
||||
#ifdef GPH
|
||||
setvbuf( stdout , 0 , _IONBF , 0 );
|
||||
setvbuf( stderr , 0 , _IONBF , 0 );
|
||||
#endif
|
||||
|
||||
__hxcpp_stdlibs_boot();
|
||||
Object::__boot();
|
||||
Dynamic::__boot();
|
||||
hx::Class_obj::__boot();
|
||||
String::__boot();
|
||||
Anon_obj::__boot();
|
||||
ArrayBase::__boot();
|
||||
EnumBase_obj::__boot();
|
||||
Math_obj::__boot();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
1027
Kha/Backends/Kore-hxcpp/khacpp/src/hx/CFFI.cpp
Normal file
1027
Kha/Backends/Kore-hxcpp/khacpp/src/hx/CFFI.cpp
Normal file
File diff suppressed because it is too large
Load Diff
375
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Class.cpp
Normal file
375
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Class.cpp
Normal file
@ -0,0 +1,375 @@
|
||||
#include <hxcpp.h>
|
||||
#include <map>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
typedef std::map<String,Class> ClassMap;
|
||||
static ClassMap *sClassMap = 0;
|
||||
|
||||
Class _hx_RegisterClass(const String &inClassName, CanCastFunc inCanCast,
|
||||
String inStatics[], String inMembers[],
|
||||
ConstructEmptyFunc inConstructEmpty, ConstructArgsFunc inConstructArgs,
|
||||
Class *inSuperClass, ConstructEnumFunc inConstructEnum,
|
||||
MarkFunc inMarkFunc
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
,VisitFunc inVisitFunc
|
||||
#endif
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
,const hx::StorageInfo *inStorageInfo
|
||||
,const hx::StaticInfo *inStaticInfo
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (sClassMap==0)
|
||||
sClassMap = new ClassMap;
|
||||
|
||||
Class_obj *obj = new Class_obj(inClassName, inStatics, inMembers,
|
||||
inConstructEmpty, inConstructArgs, inSuperClass,
|
||||
inConstructEnum, inCanCast, inMarkFunc
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
,inVisitFunc
|
||||
#endif
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
,inStorageInfo
|
||||
,inStaticInfo
|
||||
#endif
|
||||
);
|
||||
Class c(obj);
|
||||
(*sClassMap)[inClassName] = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
void _hx_RegisterClass(const String &inClassName, Class inClass)
|
||||
{
|
||||
if (sClassMap==0)
|
||||
sClassMap = new ClassMap;
|
||||
(*sClassMap)[inClassName] = inClass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -------- Class ---------------------------------------
|
||||
|
||||
|
||||
Class_obj::Class_obj(const String &inClassName,String inStatics[], String inMembers[],
|
||||
ConstructEmptyFunc inConstructEmpty, ConstructArgsFunc inConstructArgs,
|
||||
Class *inSuperClass,ConstructEnumFunc inConstructEnum,
|
||||
CanCastFunc inCanCast, MarkFunc inFunc
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
,VisitFunc inVisitFunc
|
||||
#endif
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
,const hx::StorageInfo *inStorageInfo
|
||||
,const hx::StaticInfo *inStaticInfo
|
||||
#endif
|
||||
)
|
||||
{
|
||||
mName = inClassName.makePermanent();
|
||||
mSuper = inSuperClass;
|
||||
mConstructEmpty = inConstructEmpty;
|
||||
mConstructArgs = inConstructArgs;
|
||||
mConstructEnum = inConstructEnum;
|
||||
mMarkFunc = inFunc;
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
mVisitFunc = inVisitFunc;
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
mMemberStorageInfo = inStorageInfo;
|
||||
mStaticStorageInfo = inStaticInfo;
|
||||
#endif
|
||||
|
||||
mStatics = dupFunctions(inStatics);
|
||||
mMembers = dupFunctions(inMembers);
|
||||
mCanCast = inCanCast;
|
||||
}
|
||||
|
||||
bool Class_obj::GetNoStaticField(const String &inString, Dynamic &outValue, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool Class_obj::SetNoStaticField(const String &inString, Dynamic &ioValue, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
::Array< ::String > Class_obj::dupFunctions(String inFuncs[])
|
||||
{
|
||||
if (!inFuncs)
|
||||
return null();
|
||||
|
||||
int count = 0;
|
||||
for(String *s = inFuncs; s->length; s++)
|
||||
count++;
|
||||
|
||||
Array<String> result = Array_obj<String>::__newConstWrapper(&inFuncs[0],count);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Class_obj::registerScriptable(bool inOverwrite)
|
||||
{
|
||||
if (!inOverwrite && sClassMap->find(mName)!=sClassMap->end())
|
||||
return;
|
||||
(*sClassMap)[ mName ] = this;
|
||||
}
|
||||
|
||||
Class Class_obj::GetSuper()
|
||||
{
|
||||
if (!mSuper)
|
||||
return null();
|
||||
if (mSuper==&hx::Object::__SGetClass())
|
||||
return null();
|
||||
return *mSuper;
|
||||
}
|
||||
|
||||
|
||||
Class Class_obj__mClass;
|
||||
|
||||
Class Class_obj::__GetClass() const { return Class_obj__mClass; }
|
||||
Class &Class_obj::__SGetClass() { return Class_obj__mClass; }
|
||||
|
||||
void Class_obj::__boot()
|
||||
{
|
||||
Static(Class_obj__mClass) = hx::_hx_RegisterClass(HX_CSTRING("Class"),TCanCast<Class_obj>,sNone,sNone, 0,0 , 0, 0 );
|
||||
}
|
||||
|
||||
|
||||
void Class_obj::MarkStatics(hx::MarkContext *__inCtx)
|
||||
{
|
||||
HX_MARK_MEMBER(__meta__);
|
||||
if (mMarkFunc)
|
||||
mMarkFunc(__inCtx);
|
||||
}
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void Class_obj::VisitStatics(hx::VisitContext *__inCtx)
|
||||
{
|
||||
HX_VISIT_MEMBER(__meta__);
|
||||
if (mVisitFunc)
|
||||
mVisitFunc(__inCtx);
|
||||
}
|
||||
#endif
|
||||
|
||||
Class Class_obj::Resolve(String inName)
|
||||
{
|
||||
ClassMap::const_iterator i = sClassMap->find(inName);
|
||||
if (i==sClassMap->end())
|
||||
{
|
||||
// Class class...
|
||||
if (inName==HX_CSTRING("Enum"))
|
||||
return Class_obj__mClass;
|
||||
return null();
|
||||
}
|
||||
return i->second;
|
||||
}
|
||||
|
||||
Dynamic Class_obj::ConstructEmpty()
|
||||
{
|
||||
return mConstructEmpty();
|
||||
}
|
||||
|
||||
Dynamic Class_obj::ConstructArgs(DynamicArray inArgs)
|
||||
{
|
||||
return mConstructArgs(inArgs);
|
||||
}
|
||||
|
||||
Dynamic Class_obj::ConstructEnum(String inName,DynamicArray inArgs)
|
||||
{
|
||||
if (mConstructEnum==0)
|
||||
return null();
|
||||
return mConstructEnum(inName,inArgs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
String Class_obj::__ToString() const { return mName; }
|
||||
|
||||
|
||||
Array<String> Class_obj::GetInstanceFields()
|
||||
{
|
||||
Array<String> result = mSuper && (*mSuper).mPtr != this ? (*mSuper)->GetInstanceFields() : Array<String>(0,0);
|
||||
if (mMembers.mPtr)
|
||||
for(int m=0;m<mMembers->size();m++)
|
||||
{
|
||||
const String &mem = mMembers[m];
|
||||
if (result->Find(mem)==-1)
|
||||
result.Add(mem);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Array<String> Class_obj::GetClassFields()
|
||||
{
|
||||
Array<String> result = mStatics.mPtr ? mStatics->copy() : new Array_obj<String>(0,0);
|
||||
if (__rtti__.raw_ptr())
|
||||
result->push( HX_CSTRING("__rtti") );
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Class_obj::__HasField(const String &inString)
|
||||
{
|
||||
if (__rtti__.raw_ptr() && inString==HX_CSTRING("__rtti"))
|
||||
return true;
|
||||
|
||||
if (mStatics.mPtr)
|
||||
for(int s=0;s<mStatics->size();s++)
|
||||
if (mStatics[s]==inString)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
hx::Val Class_obj::__Field(const String &inString, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
if (inString==HX_CSTRING("__meta__"))
|
||||
return __meta__;
|
||||
#if (HXCPP_API_LEVEL>320)
|
||||
if (inString==HX_CSTRING("__rtti"))
|
||||
return __rtti__;
|
||||
#endif
|
||||
|
||||
if (mGetStaticField)
|
||||
{
|
||||
Dynamic result;
|
||||
if (mGetStaticField(inString,result,inCallProp))
|
||||
return result;
|
||||
|
||||
// Throw ?
|
||||
return null();
|
||||
}
|
||||
|
||||
// Not the most efficient way of doing this!
|
||||
if (!mConstructEmpty)
|
||||
return null();
|
||||
Dynamic instance = mConstructEmpty();
|
||||
return instance->__Field(inString, inCallProp);
|
||||
}
|
||||
|
||||
hx::Val Class_obj::__SetField(const String &inString,const hx::Val &inValue, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
|
||||
if (mSetStaticField)
|
||||
{
|
||||
Dynamic result = inValue;
|
||||
if (mSetStaticField(inString,result,inCallProp))
|
||||
return result;
|
||||
|
||||
// Throw ?
|
||||
return inValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Not the most efficient way of doing this!
|
||||
if (!mConstructEmpty)
|
||||
return null();
|
||||
Dynamic instance = mConstructEmpty();
|
||||
return instance->__SetField(inString,inValue, inCallProp);
|
||||
}
|
||||
|
||||
bool Class_obj::__IsEnum()
|
||||
{
|
||||
return mConstructEnum || this==GetVoidClass().GetPtr() || this==GetBoolClass().GetPtr();
|
||||
}
|
||||
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
const hx::StorageInfo* Class_obj::GetMemberStorage(String inName)
|
||||
{
|
||||
if (mMemberStorageInfo)
|
||||
{
|
||||
for(const StorageInfo *s = mMemberStorageInfo; s->offset; s++)
|
||||
{
|
||||
if (s->name == inName)
|
||||
return s;
|
||||
}
|
||||
}
|
||||
if (mSuper)
|
||||
return (*mSuper)->GetMemberStorage(inName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const hx::StaticInfo* Class_obj::GetStaticStorage(String inName)
|
||||
{
|
||||
if (mStaticStorageInfo)
|
||||
{
|
||||
for(const StaticInfo *s = mStaticStorageInfo; s->address; s++)
|
||||
{
|
||||
if (s->name == inName)
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void MarkClassStatics(hx::MarkContext *__inCtx)
|
||||
{
|
||||
#ifdef HXCPP_DEBUG
|
||||
MarkPushClass("MarkClassStatics",__inCtx);
|
||||
#endif
|
||||
ClassMap::iterator end = sClassMap->end();
|
||||
for(ClassMap::iterator i = sClassMap->begin(); i!=end; ++i)
|
||||
{
|
||||
Class c = i->second;
|
||||
if (c->__meta__.mPtr || c->mMarkFunc)
|
||||
{
|
||||
#ifdef HXCPP_DEBUG
|
||||
hx::MarkPushClass(i->first.raw_ptr(),__inCtx);
|
||||
hx::MarkSetMember("statics",__inCtx);
|
||||
#endif
|
||||
|
||||
c->MarkStatics(__inCtx);
|
||||
|
||||
#ifdef HXCPP_DEBUG
|
||||
hx::MarkPopClass(__inCtx);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HXCPP_DEBUG
|
||||
MarkPopClass(__inCtx);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
|
||||
void VisitClassStatics(hx::VisitContext *__inCtx)
|
||||
{
|
||||
HX_VISIT_MEMBER(Class_obj__mClass);
|
||||
ClassMap::iterator end = sClassMap->end();
|
||||
for(ClassMap::iterator i = sClassMap->begin(); i!=end; ++i)
|
||||
i->second->VisitStatics(__inCtx);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
} // End namespace hx
|
||||
|
||||
Array<String> __hxcpp_get_class_list()
|
||||
{
|
||||
Array<String> result = Array_obj<String>::__new();
|
||||
if (hx::sClassMap)
|
||||
{
|
||||
for(hx::ClassMap::iterator i=hx::sClassMap->begin(); i!=hx::sClassMap->end(); ++i)
|
||||
{
|
||||
if (i->second.mPtr)
|
||||
result->push( i->first );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
430
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Date.cpp
Normal file
430
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Date.cpp
Normal file
@ -0,0 +1,430 @@
|
||||
#include <hxcpp.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef HX_WINDOWS
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#if (_POSIX_VERSION >= 1)
|
||||
#define USE_TIME_R
|
||||
#endif
|
||||
#if (_POSIX_VERSION >= 199309L)
|
||||
#include <sys/time.h>
|
||||
#define USE_CLOCK_GETTIME
|
||||
#define USE_GETTIMEOFDAY
|
||||
#endif
|
||||
#endif
|
||||
#if defined(KINC_SONY)
|
||||
// fill in for a missing localtime_r with localtime_s
|
||||
#define localtime_r localtime_s
|
||||
#define gmtime_r gmtime_s
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HX_MACOS
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
#if defined(IPHONE) || defined(APPLETV)
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
#endif
|
||||
|
||||
|
||||
//#include <hxMacros.h>
|
||||
|
||||
static double t0 = 0;
|
||||
double __hxcpp_time_stamp()
|
||||
{
|
||||
#ifdef HX_WINDOWS
|
||||
static __int64 t0=0;
|
||||
static double period=0;
|
||||
__int64 now;
|
||||
|
||||
if (QueryPerformanceCounter((LARGE_INTEGER*)&now))
|
||||
{
|
||||
if (t0==0)
|
||||
{
|
||||
t0 = now;
|
||||
__int64 freq;
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
||||
if (freq!=0)
|
||||
period = 1.0/freq;
|
||||
}
|
||||
if (period!=0)
|
||||
return (now-t0)*period;
|
||||
}
|
||||
|
||||
return (double)clock() / ( (double)CLOCKS_PER_SEC);
|
||||
#elif defined(HX_MACOS)
|
||||
static double time_scale = 0.0;
|
||||
if (time_scale==0.0)
|
||||
{
|
||||
mach_timebase_info_data_t info;
|
||||
mach_timebase_info(&info);
|
||||
time_scale = 1e-9 * (double)info.numer / info.denom;
|
||||
}
|
||||
double r = mach_absolute_time() * time_scale;
|
||||
return mach_absolute_time() * time_scale;
|
||||
#else
|
||||
#if defined(IPHONE) || defined(APPLETV)
|
||||
double t = CACurrentMediaTime();
|
||||
#elif defined(USE_GETTIMEOFDAY) && !defined(KINC_CONSOLE)
|
||||
struct timeval tv;
|
||||
if( gettimeofday(&tv,NULL) )
|
||||
return 0;
|
||||
double t = ( tv.tv_sec + ((double)tv.tv_usec) / 1000000.0 );
|
||||
#elif defined(USE_CLOCK_GETTIME) && !defined(KINC_CONSOLE)
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
double t = ( ts.tv_sec + ((double)ts.tv_nsec)*1e-9 );
|
||||
#else
|
||||
double t = (double)clock() * (1.0 / CLOCKS_PER_SEC);
|
||||
#endif
|
||||
if (t0==0) t0 = t;
|
||||
return t-t0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* for the provided Epoch time, fills the passed struct tm with date_time representation in local time zone
|
||||
*/
|
||||
void __internal_localtime(double inSeconds, struct tm* time)
|
||||
{
|
||||
time_t t = (time_t) inSeconds;
|
||||
#ifdef USE_TIME_R
|
||||
localtime_r(&t, time);
|
||||
#else
|
||||
struct tm *result = localtime(&t);
|
||||
if (result)
|
||||
*time = *result;
|
||||
else
|
||||
memset(time, 0, sizeof(*time) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* for the provided Epoch time, fills the passed struct tm with with date_time representation in UTC
|
||||
*/
|
||||
void __internal_gmtime(double inSeconds, struct tm* time)
|
||||
{
|
||||
time_t t = (time_t) inSeconds;
|
||||
#ifdef USE_TIME_R
|
||||
gmtime_r(&t, time);
|
||||
#else
|
||||
*time = *gmtime(&t);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* input: takes Y-M-D h:m:s.ms (considers that date parts are in local date_time representation)
|
||||
* output: returns UTC time stamp (Epoch), in seconds
|
||||
*/
|
||||
double __hxcpp_new_date(int inYear,int inMonth,int inDay,int inHour, int inMin, int inSeconds, int inMilliseconds)
|
||||
{
|
||||
struct tm time;
|
||||
|
||||
time.tm_isdst = -1;
|
||||
time.tm_year = inYear - 1900;
|
||||
time.tm_mon = inMonth;
|
||||
time.tm_mday = inDay;
|
||||
time.tm_hour = inHour;
|
||||
time.tm_min = inMin;
|
||||
time.tm_sec = inSeconds;
|
||||
|
||||
return (mktime(&time) + ((double) inMilliseconds * 0.001));
|
||||
}
|
||||
|
||||
// Used by DateTools.makeUtc
|
||||
double __hxcpp_utc_date(int inYear,int inMonth,int inDay,int inHour, int inMin, int inSeconds)
|
||||
{
|
||||
int diff;
|
||||
time_t a, b;
|
||||
struct tm time, *temp;
|
||||
|
||||
time.tm_year = inYear;
|
||||
time.tm_isdst = -1;
|
||||
time.tm_year = inYear - 1900;
|
||||
time.tm_mon = inMonth;
|
||||
time.tm_mday = inDay;
|
||||
time.tm_hour = inHour;
|
||||
time.tm_min = inMin;
|
||||
time.tm_sec = inSeconds;
|
||||
|
||||
a = mktime(&time); //timestamp based on local interpretation of date parts
|
||||
temp = gmtime(&a); //get utc date parts corresponding to this timestamp
|
||||
temp->tm_isdst=-1; //reset dst flag for use in mktime
|
||||
b = mktime(temp); //get timestamp for local interpretation of utc date parts
|
||||
diff= a - b; //find difference in timestamp values .
|
||||
|
||||
return a+diff;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns hh value (in hh:mm:ss) of date_time representation in local time zone
|
||||
*/
|
||||
int __hxcpp_get_hours(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_localtime( inSeconds, &time);
|
||||
return time.tm_hour;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns mm value (in hh:mm:ss) of date_time representation in local time zone
|
||||
*/
|
||||
int __hxcpp_get_minutes(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_localtime( inSeconds, &time);
|
||||
return time.tm_min;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns ss value (in hh:mm:ss) of date_time representation in local time zone
|
||||
*/
|
||||
int __hxcpp_get_seconds(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_localtime( inSeconds, &time);
|
||||
return time.tm_sec;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns YYYY value (in YYYY-MM-DD) of date_time representation in local time zone
|
||||
*/
|
||||
int __hxcpp_get_year(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_localtime( inSeconds, &time);
|
||||
return (time.tm_year + 1900);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns MM value (in YYYY-MM-DD) of date_time representation in local time zone
|
||||
*/
|
||||
int __hxcpp_get_month(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_localtime( inSeconds, &time);
|
||||
return time.tm_mon;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns DD value (in YYYY-MM-DD) of date_time representation in local time zone
|
||||
*/
|
||||
int __hxcpp_get_date(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_localtime( inSeconds, &time);
|
||||
return time.tm_mday;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns week day (as int, Sun=0...Sat=6) of date_time representation in local time zone
|
||||
*/
|
||||
int __hxcpp_get_day(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_localtime( inSeconds, &time);
|
||||
return time.tm_wday;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns hh value (in hh:mm:ss) of date_time representation in UTC
|
||||
*/
|
||||
int __hxcpp_get_utc_hours(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_gmtime( inSeconds, &time);
|
||||
return time.tm_hour;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns mm value (in hh:mm:ss) of date_time representation in UTC
|
||||
*/
|
||||
int __hxcpp_get_utc_minutes(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_gmtime( inSeconds, &time);
|
||||
return time.tm_min;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns ss value (in hh:mm:ss) of date_time representation in UTC
|
||||
*/
|
||||
int __hxcpp_get_utc_seconds(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_gmtime( inSeconds, &time);
|
||||
return time.tm_sec;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns YYYY value (in YYYY-MM-DD) of date_time representation in UTC
|
||||
*/
|
||||
int __hxcpp_get_utc_year(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_gmtime( inSeconds, &time);
|
||||
return (time.tm_year + 1900);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns MM value (in YYYY-MM-DD) of date_time representation in UTC
|
||||
*/
|
||||
int __hxcpp_get_utc_month(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_gmtime( inSeconds, &time);
|
||||
return time.tm_mon;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns DD value (in YYYY-MM-DD) of date_time representation in UTC
|
||||
*/
|
||||
int __hxcpp_get_utc_date(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_gmtime( inSeconds, &time);
|
||||
return time.tm_mday;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns week day (as int, Sun=0...Sat=6) of date_time representation in UTC
|
||||
*/
|
||||
int __hxcpp_get_utc_day(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_gmtime( inSeconds, &time);
|
||||
return time.tm_wday;
|
||||
}
|
||||
|
||||
/*
|
||||
* similar to __hxcpp_new_date but, takes no date parts as input because, it assumes NOW date_time
|
||||
*/
|
||||
double __hxcpp_date_now()
|
||||
{
|
||||
#ifdef KINC_CONSOLE
|
||||
return 0;
|
||||
#elif defined(HX_WINDOWS)
|
||||
typedef unsigned __int64 uint64_t;
|
||||
static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
|
||||
|
||||
SYSTEMTIME system_time;
|
||||
FILETIME file_time;
|
||||
ULARGE_INTEGER ularge;
|
||||
|
||||
GetSystemTime( &system_time );
|
||||
SystemTimeToFileTime( &system_time, &file_time );
|
||||
|
||||
ularge.LowPart = file_time.dwLowDateTime;
|
||||
ularge.HighPart = file_time.dwHighDateTime;
|
||||
|
||||
return (double)( (long) ((ularge.QuadPart - EPOCH) / 10000000L) ) +
|
||||
system_time.wMilliseconds*0.001;
|
||||
#elif defined(USE_GETTIMEOFDAY)
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
return (tv.tv_sec + (((double) tv.tv_usec) / (1000 * 1000)));
|
||||
#else
|
||||
// per-second time resolution. not ideal, but OK given the docs for Date.now
|
||||
time_t t;
|
||||
struct tm ti;
|
||||
time(&t);
|
||||
__internal_localtime((double)t, &ti);
|
||||
return mktime(&ti);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* for the input Epoch time, returns whether the corresponding local time would be in DST
|
||||
* 1 : yes, in DST ; 0 : no, not in DST
|
||||
*/
|
||||
int __hxcpp_is_dst(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_localtime( inSeconds, &time);
|
||||
return time.tm_isdst;
|
||||
}
|
||||
|
||||
/*
|
||||
* for the input Epoch time, returns the correct timezone offset of local time zone;
|
||||
* return value is in seconds e.g. -28800 (that would be -8 hrs)
|
||||
*/
|
||||
double __hxcpp_timezone_offset(double inSeconds)
|
||||
{
|
||||
struct tm localTime;
|
||||
__internal_localtime( inSeconds, &localTime);
|
||||
|
||||
#if defined(HX_WINDOWS) || defined(__SNC__) || defined(__ORBIS__) || defined(KINC_CONSOLE)
|
||||
struct tm gmTime;
|
||||
__internal_gmtime(inSeconds, &gmTime );
|
||||
|
||||
return mktime(&localTime) - mktime(&gmTime);
|
||||
#else
|
||||
return localTime.tm_gmtoff;
|
||||
#endif
|
||||
}
|
||||
|
||||
String __internal_to_string(struct tm time)
|
||||
{
|
||||
// YYYY-MM-DD hh:mm:ss
|
||||
|
||||
char buf[100];
|
||||
strftime(buf,100, "%Y-%m-%d %H:%M:%S", &time);
|
||||
return String::create(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* string form of a given Epoch time, without milliseconds,
|
||||
* as in format [YYYY-MM-DD hh:mm:ss +hhmm] ex: [1997-07-16 19:20:30 +0100].
|
||||
*/
|
||||
String __hxcpp_to_utc_string(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_gmtime( inSeconds, &time);
|
||||
return __internal_to_string( time);
|
||||
}
|
||||
|
||||
/*
|
||||
* string form of a given Epoch time, without milliseconds and timezone offset,
|
||||
* as in format [YYYY-MM-DD hh:mm:ss] ex: [1997-07-16 19:20:30].
|
||||
*/
|
||||
String __hxcpp_to_string(double inSeconds)
|
||||
{
|
||||
struct tm time;
|
||||
__internal_localtime( inSeconds, &time);
|
||||
return __internal_to_string( time);
|
||||
}
|
||||
|
||||
/*
|
||||
* input: takes Y-M-D h:m:s.ms (considers that date parts are in UTC date_time representation)
|
||||
* output: returns UTC time stamp (Epoch), in seconds
|
||||
*/
|
||||
double __hxcpp_from_utc(int inYear,int inMonth,int inDay,int inHour, int inMin, int inSeconds, int inMilliseconds)
|
||||
{
|
||||
struct tm time;
|
||||
|
||||
time.tm_isdst = -1;
|
||||
time.tm_year = inYear - 1900;
|
||||
time.tm_mon = inMonth;
|
||||
time.tm_mday = inDay;
|
||||
time.tm_hour = inHour;
|
||||
time.tm_min = inMin;
|
||||
time.tm_sec = inSeconds;
|
||||
|
||||
time_t z = mktime(&time);
|
||||
time_t t = z + __hxcpp_timezone_offset(z);
|
||||
|
||||
struct tm local_tm;
|
||||
__internal_localtime( t, &local_tm);
|
||||
|
||||
return (mktime(&local_tm) + ((double) inMilliseconds * 0.001));
|
||||
}
|
||||
|
||||
583
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Debug.cpp
Normal file
583
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Debug.cpp
Normal file
@ -0,0 +1,583 @@
|
||||
#include <hxcpp.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <hx/Debug.h>
|
||||
#include <hx/Thread.h>
|
||||
#include <hx/Telemetry.h>
|
||||
#include <hx/Unordered.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
|
||||
#if defined(HXCPP_CATCH_SEGV) && !defined(_MSC_VER)
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#if defined(HX_WINDOWS) || defined(HX_WINRT)
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef HX_WINRT
|
||||
#define DBGLOG WINRT_LOG
|
||||
#elif defined(ANDROID)
|
||||
#include <android/log.h>
|
||||
#define DBGLOG(...) __android_log_print(ANDROID_LOG_INFO, "HXCPP", __VA_ARGS__)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define DBGLOG printf
|
||||
#endif
|
||||
|
||||
#if _MSC_VER
|
||||
#ifndef snprintf
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
const char* EXTERN_CLASS_NAME = "extern";
|
||||
|
||||
#ifdef HXCPP_STACK_IDS
|
||||
static HxMutex sStackMapMutex;
|
||||
typedef UnorderedMap<int, StackContext *> StackMap;
|
||||
static StackMap sStackMap;
|
||||
#endif
|
||||
|
||||
// User settable String->Void
|
||||
// String : message
|
||||
// You can 'throw' to prevent default action
|
||||
static Dynamic sCriticalErrorHandler;
|
||||
|
||||
|
||||
static void setStaticHandler(Dynamic &inStore, Dynamic inValue)
|
||||
{
|
||||
if ( inStore==null() != inValue==null())
|
||||
{
|
||||
if ( inValue!=null() )
|
||||
GCAddRoot(&inStore.mPtr);
|
||||
else
|
||||
GCRemoveRoot(&inStore.mPtr);
|
||||
}
|
||||
inStore = inValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void CriticalErrorHandler(String inErr, bool allowFixup)
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (allowFixup && __hxcpp_dbg_fix_critical_error(inErr))
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (sCriticalErrorHandler!=null())
|
||||
sCriticalErrorHandler(inErr);
|
||||
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *ctx = hx::StackContext::getCurrent();
|
||||
ctx->beginCatch(true);
|
||||
ctx->dumpExceptionStack();
|
||||
#endif
|
||||
|
||||
DBGLOG("Critical Error: %s\n", inErr.utf8_str());
|
||||
|
||||
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
|
||||
MessageBoxA(0, inErr.utf8_str(), "Critial Error - program must terminate",
|
||||
MB_ICONEXCLAMATION|MB_OK);
|
||||
#endif
|
||||
|
||||
// Good when using gdb, and to collect a core ...
|
||||
#if __has_builtin(__builtin_trap)
|
||||
__builtin_trap();
|
||||
#else
|
||||
(* (int *) 0) = 0;
|
||||
#endif
|
||||
|
||||
// Just in case that didn't do it ...
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void CriticalError(const String &inErr, bool inAllowFixup)
|
||||
{
|
||||
CriticalErrorHandler(inErr, inAllowFixup);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HXCPP_CATCH_SEGV
|
||||
class hxSehException : public hx::Object
|
||||
{
|
||||
public:
|
||||
int code;
|
||||
|
||||
inline void *operator new( size_t inSize )
|
||||
{
|
||||
return hx::InternalCreateConstBuffer(0,(int)inSize);
|
||||
}
|
||||
void operator delete( void *) { }
|
||||
|
||||
hxSehException(int inCode) : code(inCode) { }
|
||||
|
||||
String __ToString() const { return HX_CSTRING("hxSehException"); }
|
||||
|
||||
int __GetType() const { return vtObject; }
|
||||
};
|
||||
|
||||
static hx::Object *sException = new hxSehException(1);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
void __cdecl hxSignalFunction(unsigned int, struct _EXCEPTION_POINTERS* )
|
||||
{
|
||||
hx::Throw(sException);
|
||||
}
|
||||
#else
|
||||
void hxSignalFunction(int)
|
||||
{
|
||||
hx::Throw(sException);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
String FormatStack(const char *file, const char *clazz, const char *func, int line, bool display)
|
||||
{
|
||||
// Not sure if the following is even possible but the old debugger did it so ...
|
||||
char buf[1024];
|
||||
if (!file || file[0]=='?')
|
||||
{
|
||||
if (display)
|
||||
snprintf(buf, sizeof(buf), "%s::%s", clazz, func);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s::%s::%d", clazz, func,line);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Old-style combined file::class...
|
||||
if (!clazz || !clazz[0])
|
||||
{
|
||||
if (line>0 || !display)
|
||||
snprintf(buf, sizeof(buf), display ? "%s %s line %d" : "%s::%s::%d", func, file, line);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s %s", func, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line>0 || !display)
|
||||
snprintf(buf, sizeof(buf), display ? "%s::%s %s line %d" : "%s::%s::%s::%d", clazz, func, file, line);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s::%s %s", clazz, func, file);
|
||||
}
|
||||
}
|
||||
return ::String(buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
StackContext::StackContext()
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
mIsUnwindingException = false;
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_TELEMETRY
|
||||
//mTelemetry = tlmCreate(this);
|
||||
// Do not automatically start
|
||||
mTelemetry = 0;
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
mDebugger = 0;
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_PROFILER
|
||||
mProfiler = 0;
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
stack = new unsigned char[128*1024];
|
||||
pointer = &stack[0];
|
||||
push((hx::Object *)0);
|
||||
frame = pointer;
|
||||
exception = 0;
|
||||
breakContReturn = 0;
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_COMBINE_STRINGS
|
||||
stringSet = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
StackContext::~StackContext()
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (mDebugger)
|
||||
dbgCtxDestroy(mDebugger);
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_TELEMETRY
|
||||
if (mTelemetry)
|
||||
tlmDestroy(mTelemetry);
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_PROFILER
|
||||
if (mProfiler)
|
||||
profDestroy(mProfiler);
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
delete [] stack;
|
||||
#endif
|
||||
}
|
||||
|
||||
void StackContext::onThreadAttach()
|
||||
{
|
||||
#ifdef HXCPP_STACK_IDS
|
||||
mThreadId = __hxcpp_GetCurrentThreadNumber();
|
||||
|
||||
sStackMapMutex.Lock();
|
||||
sStackMap[mThreadId] = this;
|
||||
sStackMapMutex.Unlock();
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (!mDebugger)
|
||||
mDebugger = dbgCtxCreate(this);
|
||||
if (mDebugger)
|
||||
dbgCtxAttach(mDebugger,this);
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_TELEMETRY
|
||||
if (mTelemetry)
|
||||
tlmAttach(mTelemetry,this);
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_PROFILER
|
||||
if (mProfiler)
|
||||
profAttach(mProfiler,this);
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_CATCH_SEGV
|
||||
#ifdef _MSC_VER
|
||||
mOldSignalFunc = _set_se_translator( hxSignalFunction );
|
||||
#else
|
||||
mOldSignalFunc = signal( SIGSEGV, hxSignalFunction );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void StackContext::onThreadDetach()
|
||||
{
|
||||
#ifdef HXCPP_CATCH_SEGV
|
||||
#ifdef _MSC_VER
|
||||
_set_se_translator( mOldSignalFunc );
|
||||
#else
|
||||
signal( SIGSEGV, mOldSignalFunc );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (mDebugger)
|
||||
dbgCtxDetach(mDebugger);
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_TELEMETRY
|
||||
if (mTelemetry)
|
||||
tlmDetach(mTelemetry);
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_PROFILER
|
||||
if (mProfiler)
|
||||
profDetach(mProfiler,this);
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_STACK_IDS
|
||||
sStackMapMutex.Lock();
|
||||
sStackMap.erase(mThreadId);
|
||||
sStackMapMutex.Unlock();
|
||||
mThreadId = 0;
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_COMBINE_STRINGS
|
||||
stringSet = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HXCPP_STACK_IDS
|
||||
void StackContext::getAllStackIds( QuickVec<int> &outIds )
|
||||
{
|
||||
outIds.clear();
|
||||
sStackMapMutex.Lock();
|
||||
for(StackMap::iterator i=sStackMap.begin(); i!=sStackMap.end(); ++i)
|
||||
outIds.push(i->first);
|
||||
sStackMapMutex.Unlock();
|
||||
}
|
||||
|
||||
StackContext *StackContext::getStackForId(int id)
|
||||
{
|
||||
sStackMapMutex.Lock();
|
||||
StackContext *result = sStackMap[id];
|
||||
sStackMapMutex.Unlock();
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HXCPP_STACK_TRACE // {
|
||||
|
||||
void StackContext::tracePosition( )
|
||||
{
|
||||
StackFrame *frame = mStackFrames[mStackFrames.size()-1];
|
||||
#ifdef HXCPP_STACK_LINE
|
||||
DBGLOG("%s::%s : %d\n", frame->position->className, frame->position->functionName, frame->lineNumber);
|
||||
#else
|
||||
DBGLOG("%s::%s\n", frame->position->className, frame->position->functionName);
|
||||
#endif
|
||||
}
|
||||
|
||||
void StackContext::getCurrentCallStackAsStrings(Array<String> result, bool skipLast)
|
||||
{
|
||||
int n = mStackFrames.size() - (skipLast ? 1 : 0);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
// Reverse call stack to match exception stack
|
||||
StackFrame *frame = mStackFrames[n-1-i];
|
||||
result->push(frame->toString());
|
||||
}
|
||||
}
|
||||
|
||||
void StackContext::getCurrentExceptionStackAsStrings(Array<String> result)
|
||||
{
|
||||
int size = mExceptionStack.size();
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
result->push(mExceptionStack[i].toString());
|
||||
}
|
||||
}
|
||||
|
||||
void StackContext::beginCatch(bool inAll)
|
||||
{
|
||||
if (inAll)
|
||||
{
|
||||
mExceptionStack.clear();
|
||||
// Copy remaineder of stack frames to exception stack...
|
||||
// This will use the default operator=, which will copy the pointers.
|
||||
// This is what we want, since the pointers are pointers to constant data
|
||||
for(int i=mStackFrames.size()-1;i>=0;--i)
|
||||
mExceptionStack.push( *mStackFrames[i] );
|
||||
}
|
||||
// Lock-in the excpetion stack
|
||||
mIsUnwindingException = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Called when a throw occurs
|
||||
void StackContext::setLastException()
|
||||
{
|
||||
mExceptionStack.clear();
|
||||
mIsUnwindingException = true;
|
||||
}
|
||||
|
||||
|
||||
// Called when a throw occurs
|
||||
void StackContext::pushLastException()
|
||||
{
|
||||
mIsUnwindingException = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void StackContext::dumpExceptionStack()
|
||||
{
|
||||
#ifdef ANDROID
|
||||
#define EXCEPTION_PRINT(...) \
|
||||
__android_log_print(ANDROID_LOG_ERROR, "HXCPP", __VA_ARGS__)
|
||||
#else
|
||||
#define EXCEPTION_PRINT(...) \
|
||||
printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
int size = mExceptionStack.size();
|
||||
for(int i = size - 1; i >= 0; i--)
|
||||
{
|
||||
EXCEPTION_PRINT("Called from %s\n", mExceptionStack[i].toDisplay().utf8_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---- StackFrame -------
|
||||
|
||||
|
||||
::String StackFrame::toDisplay()
|
||||
{
|
||||
#ifndef HXCPP_STACK_LINE
|
||||
int lineNumber=0;
|
||||
#endif
|
||||
return FormatStack(position->fileName, position->className, position->functionName, lineNumber,true);
|
||||
}
|
||||
|
||||
|
||||
::String StackFrame::toString()
|
||||
{
|
||||
#ifndef HXCPP_STACK_LINE
|
||||
int lineNumber=0;
|
||||
#endif
|
||||
|
||||
return FormatStack(position->fileName, position->className, position->functionName, lineNumber,false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ExceptionStackFrame::ExceptionStackFrame(const StackFrame &inFrame)
|
||||
{
|
||||
// It is safe to use the pointer in 331+
|
||||
#if HXCPP_API_LEVEL > 330
|
||||
position = inFrame.position;
|
||||
#else
|
||||
// Must copy the pointer values
|
||||
className = inFrame.position->className;
|
||||
functionName = inFrame.position->functionName;
|
||||
fileName = inFrame.position->fileName;
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_STACK_LINE
|
||||
line = inFrame.lineNumber;
|
||||
#endif
|
||||
}
|
||||
|
||||
::String ExceptionStackFrame::format(bool inForDisplay)
|
||||
{
|
||||
#ifndef HXCPP_STACK_LINE
|
||||
int line=0;
|
||||
#endif
|
||||
|
||||
#if HXCPP_API_LEVEL > 330
|
||||
const char *fileName = position->fileName;
|
||||
const char *className = position->className;
|
||||
const char *functionName = position->functionName;
|
||||
#endif
|
||||
|
||||
return FormatStack(fileName, className, functionName, line, inForDisplay);
|
||||
}
|
||||
|
||||
::String ExceptionStackFrame::toDisplay() { return format(true); }
|
||||
::String ExceptionStackFrame::toString() { return format(false); }
|
||||
|
||||
|
||||
#endif // } HXCPP_STACK_TRACE
|
||||
|
||||
|
||||
HXCPP_EXTERN_CLASS_ATTRIBUTES void NullReference(const char *type, bool allowFixup)
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
String err(HX_CSTRING("Null ") + String(type) + HX_CSTRING(" Reference"));
|
||||
if (__hxcpp_dbg_fix_critical_error(err))
|
||||
return;
|
||||
#endif
|
||||
|
||||
__hxcpp_dbg_checkedThrow(HX_CSTRING("Null Object Reference"));
|
||||
}
|
||||
|
||||
|
||||
} // end namspace hx
|
||||
|
||||
#ifndef HXCPP_DEBUGGER
|
||||
void __hxcpp_execution_trace(int inLevel) { }
|
||||
#endif
|
||||
|
||||
|
||||
void __hx_dump_stack()
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *ctx = hx::StackContext::getCurrent();
|
||||
ctx->beginCatch(false);
|
||||
ctx->dumpExceptionStack();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void __hx_stack_set_last_exception()
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *ctx = hx::StackContext::getCurrent();
|
||||
ctx->setLastException();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void __hx_stack_push_last_exception()
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *ctx = hx::StackContext::getCurrent();
|
||||
ctx->pushLastException();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void __hxcpp_stack_begin_catch()
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *ctx = hx::StackContext::getCurrent();
|
||||
ctx->beginCatch(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Array<String> __hxcpp_get_call_stack(bool inSkipLast)
|
||||
{
|
||||
Array<String> result = Array_obj<String>::__new();
|
||||
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *ctx = hx::StackContext::getCurrent();
|
||||
ctx->getCurrentCallStackAsStrings(result,inSkipLast);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Array<String> __hxcpp_get_exception_stack()
|
||||
{
|
||||
Array<String> result = Array_obj<String>::__new();
|
||||
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *ctx = hx::StackContext::getCurrent();
|
||||
ctx->getCurrentExceptionStackAsStrings(result);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void __hxcpp_set_critical_error_handler(Dynamic inHandler)
|
||||
{
|
||||
hx::setStaticHandler(hx::sCriticalErrorHandler,inHandler);
|
||||
}
|
||||
|
||||
#ifndef HXCPP_DEBUGGER
|
||||
void __hxcpp_set_debugger_info(const char **inAllClasses, const char **inFullPaths) { }
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HXCPP_PROFILER
|
||||
void __hxcpp_start_profiler(::String inDumpFile)
|
||||
{
|
||||
DBGLOG("Warning - profiler has no effect without HXCPP_PROFILER\n");
|
||||
}
|
||||
void __hxcpp_stop_profiler() { }
|
||||
#endif
|
||||
|
||||
|
||||
1520
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Debugger.cpp
Normal file
1520
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Debugger.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1263
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Hash.cpp
Normal file
1263
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Hash.cpp
Normal file
File diff suppressed because it is too large
Load Diff
828
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Hash.h
Normal file
828
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Hash.h
Normal file
@ -0,0 +1,828 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HXCPP_TELEMETRY
|
||||
extern void __hxt_new_hash(void* obj, int size);
|
||||
#endif
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
inline unsigned int HashCalcHash(int inKey) { return inKey; }
|
||||
inline unsigned int HashCalcHash(cpp::Int64 inKey) { return (unsigned int)((inKey >> 32) ^ inKey); }
|
||||
inline unsigned int HashCalcHash(const String &inKey) { return inKey.hash(); }
|
||||
inline unsigned int HashCalcHash(const Dynamic &inKey)
|
||||
{
|
||||
return __hxcpp_obj_hash(inKey);
|
||||
}
|
||||
|
||||
inline void HashClear(int &ioValue) { }
|
||||
inline void HashClear(Dynamic &ioValue) { ioValue=null(); }
|
||||
inline void HashClear(String &ioValue) { ioValue=String(); }
|
||||
inline void HashClear(Float &ioValue) { }
|
||||
inline void HashClear(cpp::Int64 &ioValue) { }
|
||||
|
||||
template<typename T>
|
||||
struct NeedsMarking { enum { Yes = 0 }; };
|
||||
template<> struct NeedsMarking<Dynamic> { enum { Yes = 1 }; };
|
||||
template<> struct NeedsMarking<String> { enum { Yes = 1 }; };
|
||||
|
||||
// An int element has key = hash
|
||||
template<typename VALUE>
|
||||
struct TIntElement
|
||||
{
|
||||
typedef int Key;
|
||||
typedef VALUE Value;
|
||||
|
||||
enum { IgnoreHash = 1 };
|
||||
enum { WeakKeys = 0 };
|
||||
enum { ManageKeys = 0 };
|
||||
|
||||
typedef TIntElement<int> IntValue;
|
||||
typedef TIntElement<Float> FloatValue;
|
||||
typedef TIntElement<Dynamic> DynamicValue;
|
||||
typedef TIntElement<String> StringValue;
|
||||
typedef TIntElement<cpp::Int64> Int64Value;
|
||||
|
||||
public:
|
||||
inline void setKey(int inKey, unsigned int )
|
||||
{
|
||||
key = inKey;
|
||||
}
|
||||
inline unsigned int getHash() { return key; }
|
||||
|
||||
Value value;
|
||||
Key key;
|
||||
TIntElement<VALUE> *next;
|
||||
};
|
||||
|
||||
//
|
||||
template<typename VALUE>
|
||||
struct TInt64Element
|
||||
{
|
||||
typedef cpp::Int64 Key;
|
||||
typedef VALUE Value;
|
||||
|
||||
enum { IgnoreHash = 0 };
|
||||
enum { WeakKeys = 0 };
|
||||
enum { ManageKeys = 1 };
|
||||
|
||||
typedef TInt64Element<int> IntValue;
|
||||
typedef TInt64Element<Float> FloatValue;
|
||||
typedef TInt64Element<Dynamic> DynamicValue;
|
||||
typedef TInt64Element<String> StringValue;
|
||||
typedef TInt64Element<cpp::Int64> Int64Value;
|
||||
|
||||
public:
|
||||
inline void setKey(cpp::Int64 inKey, unsigned int inHash)
|
||||
{
|
||||
key = inKey;
|
||||
hash = inHash;
|
||||
}
|
||||
inline unsigned int getHash() { return hash; }
|
||||
|
||||
Value value;
|
||||
Key key;
|
||||
unsigned int hash;
|
||||
TInt64Element<VALUE> *next;
|
||||
};
|
||||
|
||||
// An string element gets hash from string or calculates it
|
||||
template<typename VALUE>
|
||||
struct TStringElement
|
||||
{
|
||||
typedef String Key;
|
||||
typedef VALUE Value;
|
||||
|
||||
enum { IgnoreHash = 0 };
|
||||
enum { WeakKeys = 0 };
|
||||
enum { ManageKeys = 1 };
|
||||
|
||||
typedef TStringElement<int> IntValue;
|
||||
typedef TStringElement<Float> FloatValue;
|
||||
typedef TStringElement<Dynamic> DynamicValue;
|
||||
typedef TStringElement<String> StringValue;
|
||||
typedef TStringElement<cpp::Int64> Int64Value;
|
||||
|
||||
|
||||
public:
|
||||
inline void setKey(String inKey, unsigned int inHash)
|
||||
{
|
||||
key = inKey;
|
||||
hash = inHash;
|
||||
}
|
||||
inline unsigned int getHash() { return hash; }
|
||||
|
||||
Value value;
|
||||
Key key;
|
||||
unsigned int hash;
|
||||
TStringElement<VALUE> *next;
|
||||
};
|
||||
|
||||
|
||||
struct TWeakStringSet
|
||||
{
|
||||
typedef null Value;
|
||||
typedef String Key;
|
||||
|
||||
enum { IgnoreHash = 0 };
|
||||
enum { WeakKeys = 1 };
|
||||
enum { ManageKeys = 1 };
|
||||
|
||||
typedef TWeakStringSet IntValue;
|
||||
typedef TWeakStringSet FloatValue;
|
||||
typedef TWeakStringSet DynamicValue;
|
||||
typedef TWeakStringSet StringValue;
|
||||
typedef TWeakStringSet Int64Value;
|
||||
|
||||
|
||||
public:
|
||||
inline void setKey(String inKey, unsigned int inHash)
|
||||
{
|
||||
key = inKey;
|
||||
hash = inHash;
|
||||
}
|
||||
inline unsigned int getHash() { return hash; }
|
||||
|
||||
Key key;
|
||||
unsigned int hash;
|
||||
Value value;
|
||||
TWeakStringSet *next;
|
||||
};
|
||||
|
||||
|
||||
struct TNonGcStringSet
|
||||
{
|
||||
typedef null Value;
|
||||
typedef String Key;
|
||||
|
||||
enum { IgnoreHash = 0 };
|
||||
enum { WeakKeys = 1 };
|
||||
enum { ManageKeys = 0 };
|
||||
|
||||
typedef TNonGcStringSet IntValue;
|
||||
typedef TNonGcStringSet FloatValue;
|
||||
typedef TNonGcStringSet DynamicValue;
|
||||
typedef TNonGcStringSet StringValue;
|
||||
typedef TNonGcStringSet Int64Value;
|
||||
|
||||
|
||||
public:
|
||||
inline void setKey(String inKey, unsigned int inHash)
|
||||
{
|
||||
key = inKey;
|
||||
hash = inHash;
|
||||
}
|
||||
inline unsigned int getHash() { return hash; }
|
||||
|
||||
Key key;
|
||||
unsigned int hash;
|
||||
Value value;
|
||||
TNonGcStringSet *next;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// An Dyanamic element must use the GC code to get a hash
|
||||
template<typename VALUE,bool WEAK>
|
||||
struct TDynamicElement
|
||||
{
|
||||
typedef Dynamic Key;
|
||||
typedef VALUE Value;
|
||||
|
||||
enum { IgnoreHash = 0 };
|
||||
enum { WeakKeys = WEAK };
|
||||
enum { ManageKeys = 1 };
|
||||
|
||||
typedef TDynamicElement<int,WEAK> IntValue;
|
||||
typedef TDynamicElement<Float,WEAK> FloatValue;
|
||||
typedef TDynamicElement<Dynamic,WEAK> DynamicValue;
|
||||
typedef TDynamicElement<String,WEAK> StringValue;
|
||||
typedef TDynamicElement<cpp::Int64,WEAK> Int64Value;
|
||||
|
||||
public:
|
||||
inline void setKey(Dynamic inKey, unsigned int inHash)
|
||||
{
|
||||
key = inKey;
|
||||
hash = inHash;
|
||||
}
|
||||
inline unsigned int getHash() { return hash; }
|
||||
|
||||
Value value;
|
||||
Key key;
|
||||
unsigned int hash;
|
||||
TDynamicElement<VALUE,WEAK> *next;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
enum HashStore
|
||||
{
|
||||
hashInt,
|
||||
hashFloat,
|
||||
hashString,
|
||||
hashObject,
|
||||
hashNull,
|
||||
hashInt64
|
||||
};
|
||||
template<typename T> struct StoreOf{ enum {store=hashObject}; };
|
||||
template<> struct StoreOf<int> { enum {store=hashInt}; };
|
||||
template<> struct StoreOf< ::String> { enum {store=hashString}; };
|
||||
template<> struct StoreOf<Float> { enum {store=hashFloat}; };
|
||||
template<> struct StoreOf<null> { enum {store=hashNull}; };
|
||||
template<> struct StoreOf<cpp::Int64> { enum {store=hashInt64}; };
|
||||
|
||||
namespace
|
||||
{
|
||||
inline void CopyValue(Dynamic &outValue, const Dynamic &inValue) { outValue = inValue; }
|
||||
inline void CopyValue(String &outValue, const String &inValue) { outValue = inValue; }
|
||||
inline void CopyValue(String &outValue, Float inValue) { }
|
||||
inline void CopyValue(String &outValue, const Dynamic &inValue) { outValue = inValue; }
|
||||
inline void CopyValue(int &outValue, int inValue) { outValue = inValue; }
|
||||
inline void CopyValue(int &outValue, cpp::Int64 inValue) { }
|
||||
inline void CopyValue(int &outValue, Float inValue) { outValue = inValue; }
|
||||
inline void CopyValue(int &outValue, const Dynamic &inValue) { outValue = inValue; }
|
||||
inline void CopyValue(int &outValue, const String &inValue) { }
|
||||
inline void CopyValue(Float &outValue, Float inValue) { outValue = inValue; }
|
||||
inline void CopyValue(Float &outValue, const Dynamic &inValue) { outValue = inValue; }
|
||||
inline void CopyValue(Float &outValue, const String &inValue) { }
|
||||
inline void CopyValue(cpp::Int64 &outValue, cpp::Int64 inValue) { outValue = inValue; }
|
||||
inline void CopyValue(cpp::Int64 &outValue, int inValue) { outValue = inValue; }
|
||||
inline void CopyValue(cpp::Int64 &outValue, Float inValue) { }
|
||||
inline void CopyValue(cpp::Int64 &outValue, const Dynamic &inValue) { outValue = inValue; }
|
||||
inline void CopyValue(cpp::Int64 &outValue, const String &inValue) { }
|
||||
inline void CopyValue(null &, const null &) { }
|
||||
template<typename T> inline void CopyValue(T &outValue, const null &) { }
|
||||
template<typename T> inline void CopyValue(null &, const T &) { }
|
||||
}
|
||||
|
||||
|
||||
struct HashRoot : public Object
|
||||
{
|
||||
HashStore store;
|
||||
int size;
|
||||
int mask;
|
||||
int bucketCount;
|
||||
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdHash };
|
||||
|
||||
virtual void updateAfterGc() = 0;
|
||||
|
||||
inline int getSize() { return size; }
|
||||
};
|
||||
|
||||
template<typename KEY>
|
||||
struct HashBase : public HashRoot
|
||||
{
|
||||
HashBase(int inStore)
|
||||
{
|
||||
store = (HashStore)inStore;
|
||||
size = 0;
|
||||
mask = 0;
|
||||
bucketCount = 0;
|
||||
}
|
||||
|
||||
|
||||
virtual bool query(KEY inKey,int &outValue) = 0;
|
||||
virtual bool query(KEY inKey,::String &outValue) = 0;
|
||||
virtual bool query(KEY inKey,Float &outValue) = 0;
|
||||
virtual bool query(KEY inKey,Dynamic &outValue) = 0;
|
||||
virtual bool query(KEY inKey,cpp::Int64 &outValue) = 0;
|
||||
|
||||
virtual void set(KEY inKey, const int &inValue) = 0;
|
||||
virtual void set(KEY inKey, const ::String &inValue) = 0;
|
||||
virtual void set(KEY inKey, const Float &inValue) = 0;
|
||||
virtual void set(KEY inKey, const Dynamic &inValue) = 0;
|
||||
virtual void set(KEY inKey, const cpp::Int64 &inValue) = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual HashBase<KEY> *convertStore(HashStore inStore) = 0;
|
||||
|
||||
virtual bool remove(KEY inKey) = 0;
|
||||
virtual bool exists(KEY inKey) = 0;
|
||||
virtual Array<KEY> keys() = 0;
|
||||
virtual Dynamic values() = 0;
|
||||
|
||||
virtual ::String toStringRaw() { return toString(); }
|
||||
};
|
||||
|
||||
extern void RegisterWeakHash(HashBase<Dynamic> *);
|
||||
extern void RegisterWeakHash(HashBase< ::String> *);
|
||||
|
||||
inline void RegisterWeakHash(HashBase<int> *) { };
|
||||
inline void RegisterWeakHash(HashBase<cpp::Int64> *) { };
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct ArrayValueOf{ typedef T Value; };
|
||||
template<> struct ArrayValueOf<null> { typedef Dynamic Value; };
|
||||
|
||||
template<typename ELEMENT>
|
||||
struct Hash : public HashBase< typename ELEMENT::Key >
|
||||
{
|
||||
using HashRoot::size;
|
||||
using HashRoot::mask;
|
||||
using HashRoot::bucketCount;
|
||||
using HashRoot::getSize;
|
||||
|
||||
typedef typename ELEMENT::Key Key;
|
||||
typedef typename ELEMENT::Value Value;
|
||||
typedef typename ArrayValueOf<Value>::Value ArrayValue;
|
||||
|
||||
typedef ELEMENT Element;
|
||||
enum { IgnoreHash = Element::IgnoreHash };
|
||||
|
||||
|
||||
ELEMENT **bucket;
|
||||
|
||||
|
||||
Hash() : HashBase<Key>( StoreOf<Value>::store )
|
||||
{
|
||||
bucket = 0;
|
||||
if (ELEMENT::WeakKeys && Element::ManageKeys)
|
||||
RegisterWeakHash(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool TIsWeakRefValid(T &) { return true; }
|
||||
bool TIsWeakRefValid(Dynamic &key) { return IsWeakRefValid(key.mPtr); }
|
||||
bool TIsWeakRefValid(String &key) { return IsWeakRefValid(key.raw_ptr()); }
|
||||
|
||||
|
||||
void updateAfterGc()
|
||||
{
|
||||
if (Element::WeakKeys && Element::ManageKeys)
|
||||
{
|
||||
for(int b=0;b<bucketCount;b++)
|
||||
{
|
||||
Element **headPtr = &bucket[b];
|
||||
while(*headPtr)
|
||||
{
|
||||
Element &el = **headPtr;
|
||||
if (!TIsWeakRefValid(el.key))
|
||||
{
|
||||
*headPtr = el.next;
|
||||
size--;
|
||||
}
|
||||
else
|
||||
headPtr = &el.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rebucket(int inNewCount)
|
||||
{
|
||||
#ifdef HXCPP_TELEMETRY
|
||||
bool is_new = bucket==0;
|
||||
#endif
|
||||
mask = inNewCount-1;
|
||||
//printf("expand %d -> %d\n",bucketCount, inNewCount);
|
||||
bucket = (Element **)InternalRealloc(bucketCount*sizeof(ELEMENT *), bucket,inNewCount*sizeof(ELEMENT *));
|
||||
HX_OBJ_WB_GET(this, bucket);
|
||||
//for(int b=bucketCount;b<inNewCount;b++)
|
||||
// bucket[b] = 0;
|
||||
|
||||
#ifdef HXCPP_TELEMETRY
|
||||
if (is_new) __hxt_new_hash(bucket, inNewCount*sizeof(ELEMENT *));
|
||||
#endif
|
||||
|
||||
|
||||
for(int b=0;b<bucketCount;b++)
|
||||
{
|
||||
Element **head = &bucket[b];
|
||||
while(*head)
|
||||
{
|
||||
Element &e = **head;
|
||||
int newBucket = e.getHash()&mask;
|
||||
if ( newBucket != b )
|
||||
{
|
||||
*head = e.next;
|
||||
e.next = bucket[newBucket];
|
||||
bucket[newBucket] = &e;
|
||||
}
|
||||
else
|
||||
head = &e.next;
|
||||
}
|
||||
}
|
||||
|
||||
bucketCount = inNewCount;
|
||||
}
|
||||
|
||||
void reserve(int inSize)
|
||||
{
|
||||
if (inSize<8)
|
||||
inSize = 8;
|
||||
|
||||
expandBuckets(inSize);
|
||||
}
|
||||
|
||||
void compact()
|
||||
{
|
||||
int origSize = bucketCount;
|
||||
int newSize = bucketCount>>1;
|
||||
// printf("compact -> %d\n", newSize);
|
||||
mask = newSize-1;
|
||||
for(int b=newSize; b<bucketCount; b++)
|
||||
{
|
||||
Element *head = bucket[b];
|
||||
if (head)
|
||||
{
|
||||
Element *oldHead = bucket[b-newSize];
|
||||
bucket[b-newSize] = head;
|
||||
|
||||
if (oldHead)
|
||||
{
|
||||
// Append to last element
|
||||
Element **lastPtr = &(head->next);
|
||||
while(*lastPtr)
|
||||
lastPtr = & (*lastPtr)->next;
|
||||
*lastPtr = oldHead;
|
||||
}
|
||||
bucket[b] = 0;
|
||||
}
|
||||
}
|
||||
bucketCount = newSize;
|
||||
bucket = (Element **)InternalRealloc(origSize*sizeof(ELEMENT *),bucket, sizeof(ELEMENT *)*bucketCount );
|
||||
HX_OBJ_WB_GET(this, bucket);
|
||||
}
|
||||
|
||||
bool remove(Key inKey)
|
||||
{
|
||||
if (!bucket)
|
||||
return false;
|
||||
unsigned int hash = HashCalcHash(inKey);
|
||||
Element **head = bucket + (hash&mask);
|
||||
while(*head)
|
||||
{
|
||||
Element &el = **head;
|
||||
if ( (IgnoreHash || el.getHash()==hash) && el.key==inKey)
|
||||
{
|
||||
*head = el.next;
|
||||
size--;
|
||||
if (bucketCount>8 && size < (bucketCount>>1) )
|
||||
compact();
|
||||
return true;
|
||||
}
|
||||
head = &el.next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ELEMENT *allocElement()
|
||||
{
|
||||
ELEMENT *result = (ELEMENT *)InternalNew( sizeof(ELEMENT), false );
|
||||
size++;
|
||||
expandBuckets(size);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void expandBuckets(int inSize)
|
||||
{
|
||||
// Trades memory vs bucket occupancy - more memory is used for elements anyhow, so not too critical
|
||||
enum { LOG_ELEMS_PER_BUCKET = 1 };
|
||||
if ( inSize > (bucketCount<<LOG_ELEMS_PER_BUCKET) )
|
||||
{
|
||||
int newCount = bucketCount;
|
||||
if (newCount==0)
|
||||
newCount = 2;
|
||||
else
|
||||
while( inSize > (newCount<<LOG_ELEMS_PER_BUCKET) )
|
||||
newCount<<=1;
|
||||
if (newCount!=bucketCount)
|
||||
rebucket(newCount);
|
||||
}
|
||||
}
|
||||
|
||||
Element *find(int inHash, Key inKey)
|
||||
{
|
||||
if (!bucket) return 0;
|
||||
Element *head = bucket[inHash & mask];
|
||||
while(head)
|
||||
{
|
||||
if ( (IgnoreHash || head->getHash()==inHash) && head->key==inKey)
|
||||
return head;
|
||||
head = head->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool exists(Key inKey) { return find( HashCalcHash(inKey), inKey ); }
|
||||
|
||||
|
||||
HashBase<Key> *convertStore(HashStore inStore)
|
||||
{
|
||||
switch(inStore)
|
||||
{
|
||||
case hashInt:
|
||||
return TConvertStore< typename ELEMENT::IntValue >();
|
||||
case hashFloat:
|
||||
return TConvertStore< typename ELEMENT::FloatValue >();
|
||||
case hashString:
|
||||
return TConvertStore< typename ELEMENT::StringValue >();
|
||||
case hashObject:
|
||||
return TConvertStore< typename ELEMENT::DynamicValue >();
|
||||
case hashInt64:
|
||||
return TConvertStore< typename ELEMENT::Int64Value >();
|
||||
case hashNull:
|
||||
;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template<typename OUT_VALUE>
|
||||
bool TQuery(Key inKey,OUT_VALUE &outValue)
|
||||
{
|
||||
Element *result = find( HashCalcHash(inKey), inKey );
|
||||
if (!result)
|
||||
return false;
|
||||
CopyValue(outValue,result->value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool query(Key inKey,int &outValue) { return TQuery(inKey,outValue); }
|
||||
bool query(Key inKey,::String &outValue) { return TQuery(inKey,outValue); }
|
||||
bool query(Key inKey,Float &outValue) { return TQuery(inKey,outValue); }
|
||||
bool query(Key inKey,Dynamic &outValue) { return TQuery(inKey,outValue); }
|
||||
bool query(Key inKey,cpp::Int64 &outValue) { return TQuery(inKey, outValue); }
|
||||
|
||||
|
||||
Value get(Key inKey)
|
||||
{
|
||||
Element *result = find( HashCalcHash(inKey), inKey );
|
||||
if (result)
|
||||
return result->value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template<typename Finder>
|
||||
bool findEquivalentKey(Key &outKey, int inHash, const Finder &inFinder)
|
||||
{
|
||||
if (!bucket) return false;
|
||||
Element *head = bucket[inHash & mask];
|
||||
while(head)
|
||||
{
|
||||
if ( (IgnoreHash || head->getHash()==inHash) && inFinder==head->key)
|
||||
{
|
||||
outKey = head->key;
|
||||
return true;
|
||||
}
|
||||
head = head->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool IsNursery(const void *inPtr)
|
||||
{
|
||||
return inPtr && !(((unsigned char *)inPtr)[ HX_ENDIAN_MARK_ID_BYTE]);
|
||||
}
|
||||
|
||||
template<typename SET>
|
||||
void TSet(Key inKey, const SET &inValue)
|
||||
{
|
||||
unsigned int hash = HashCalcHash(inKey);
|
||||
Element *el = find(hash,inKey);
|
||||
if (el)
|
||||
{
|
||||
CopyValue(el->value,inValue);
|
||||
if (hx::ContainsPointers<Value>()) {
|
||||
HX_OBJ_WB_GET(this,hx::PointerOf(el->value))
|
||||
}
|
||||
return;
|
||||
}
|
||||
el = allocElement();
|
||||
el->setKey(inKey,hash);
|
||||
CopyValue(el->value,inValue);
|
||||
el->next = bucket[hash&mask];
|
||||
bucket[hash&mask] = el;
|
||||
|
||||
#ifdef HXCPP_GC_GENERATIONAL
|
||||
unsigned char &mark = ((unsigned char *)(this))[ HX_ENDIAN_MARK_ID_BYTE];
|
||||
if (mark == hx::gByteMarkID)
|
||||
{
|
||||
// Look for nursery objects...
|
||||
if ( IsNursery(el) || IsNursery(hx::PointerOf(el->key)) ||
|
||||
(hx::ContainsPointers<Value>() && IsNursery(hx::PointerOf(el->value)) ) )
|
||||
{
|
||||
mark|=HX_GC_REMEMBERED;
|
||||
(HX_CTX_GET)->pushReferrer(this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void set(Key inKey, const int &inValue) { TSet(inKey, inValue); }
|
||||
void set(Key inKey, const ::String &inValue) { TSet(inKey, inValue); }
|
||||
void set(Key inKey, const Float &inValue) { TSet(inKey, inValue); }
|
||||
void set(Key inKey, const Dynamic &inValue) { TSet(inKey, inValue); }
|
||||
void set(Key inKey, const null &inValue) { TSet(inKey, inValue); }
|
||||
void set(Key inKey, const cpp::Int64 &inValue) { TSet(inKey, inValue); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
bucket = 0;
|
||||
size = 0;
|
||||
mask = 0;
|
||||
bucketCount = 0;
|
||||
}
|
||||
|
||||
|
||||
template<typename F>
|
||||
void iterate(F &inFunc)
|
||||
{
|
||||
for(int b=0;b<bucketCount;b++)
|
||||
{
|
||||
Element *el = bucket[b];
|
||||
while(el)
|
||||
{
|
||||
inFunc(el);
|
||||
el = el->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert
|
||||
template<typename NEW>
|
||||
struct Converter
|
||||
{
|
||||
NEW *result;
|
||||
|
||||
Converter(NEW *inResult) : result(inResult) { }
|
||||
|
||||
void operator()(typename Hash::Element *elem)
|
||||
{
|
||||
result->set(elem->key,elem->value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename NEW_ELEM>
|
||||
HashBase<Key> *TConvertStore()
|
||||
{
|
||||
Hash<NEW_ELEM> *result = new Hash<NEW_ELEM>();
|
||||
|
||||
result->reserve(getSize()*3/2);
|
||||
|
||||
Converter< Hash<NEW_ELEM> > converter(result);
|
||||
|
||||
iterate(converter);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Keys ...
|
||||
struct KeyBuilder
|
||||
{
|
||||
Array<Key> array;
|
||||
|
||||
KeyBuilder(int inReserve = 0)
|
||||
{
|
||||
array = Array<Key>(0,inReserve);
|
||||
}
|
||||
void operator()(typename Hash::Element *elem)
|
||||
{
|
||||
array->push(elem->key);
|
||||
}
|
||||
};
|
||||
Array<Key> keys()
|
||||
{
|
||||
KeyBuilder builder(getSize());
|
||||
iterate(builder);
|
||||
return builder.array;;
|
||||
}
|
||||
|
||||
|
||||
// Values...
|
||||
struct ValueBuilder
|
||||
{
|
||||
Array<ArrayValue> array;
|
||||
ValueBuilder(int inReserve = 0)
|
||||
{
|
||||
array = Array<ArrayValue>(0,inReserve);
|
||||
}
|
||||
|
||||
void operator()(typename Hash::Element *elem)
|
||||
{
|
||||
array->push(elem->value);
|
||||
}
|
||||
};
|
||||
Dynamic values()
|
||||
{
|
||||
ValueBuilder builder(getSize());
|
||||
iterate(builder);
|
||||
return builder.array;;
|
||||
}
|
||||
|
||||
|
||||
// Strings ...
|
||||
struct StringBuilder
|
||||
{
|
||||
Array<String> array;
|
||||
bool raw;
|
||||
|
||||
StringBuilder(int inReserve = 0,bool inRaw=false)
|
||||
{
|
||||
raw = inRaw;
|
||||
array = Array<String>(0,inReserve*4+1);
|
||||
if (!raw) {
|
||||
#if (HXCPP_API_LEVEL >= 430)
|
||||
array->push(HX_CSTRING("["));
|
||||
#else
|
||||
array->push(HX_CSTRING("{ "));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void operator()(typename Hash::Element *elem)
|
||||
{
|
||||
if (array->length>1)
|
||||
array->push(HX_CSTRING(", "));
|
||||
array->push(String(elem->key));
|
||||
array->push(HX_CSTRING(" => "));
|
||||
array->push(String(elem->value));
|
||||
}
|
||||
::String toString()
|
||||
{
|
||||
if (!raw) {
|
||||
#if (HXCPP_API_LEVEL >= 430)
|
||||
array->push(HX_CSTRING("]"));
|
||||
#else
|
||||
array->push(HX_CSTRING(" }"));
|
||||
#endif
|
||||
}
|
||||
return array->length==0 ? String() : array->join(HX_CSTRING(""));
|
||||
}
|
||||
};
|
||||
|
||||
String toString()
|
||||
{
|
||||
StringBuilder builder(getSize());
|
||||
iterate(builder);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
String toStringRaw()
|
||||
{
|
||||
StringBuilder builder(getSize(),true);
|
||||
iterate(builder);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
|
||||
// Mark ...
|
||||
struct HashMarker
|
||||
{
|
||||
hx::MarkContext *__inCtx;
|
||||
HashMarker(hx::MarkContext *ctx) : __inCtx(ctx) { }
|
||||
void operator()(typename Hash::Element *inElem)
|
||||
{
|
||||
HX_MARK_ARRAY(inElem);
|
||||
if (!Hash::Element::WeakKeys)
|
||||
{
|
||||
HX_MARK_MEMBER(inElem->key);
|
||||
}
|
||||
HX_MARK_MEMBER(inElem->value);
|
||||
}
|
||||
};
|
||||
|
||||
void __Mark(hx::MarkContext *__inCtx)
|
||||
{
|
||||
HX_MARK_ARRAY(bucket);
|
||||
|
||||
HashMarker marker(__inCtx);
|
||||
iterate(marker);
|
||||
}
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
|
||||
void __Visit(hx::VisitContext *__inCtx)
|
||||
{
|
||||
//printf(" visit hash %p\n", this);
|
||||
HX_VISIT_ARRAY(bucket);
|
||||
for(int b=0;b<bucketCount;b++)
|
||||
{
|
||||
HX_VISIT_ARRAY(bucket[b]);
|
||||
Element *el = bucket[b];
|
||||
while(el)
|
||||
{
|
||||
HX_VISIT_MEMBER(el->key);
|
||||
HX_VISIT_MEMBER(el->value);
|
||||
HX_VISIT_ARRAY(el->next);
|
||||
el = el->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
100
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Interface.cpp
Normal file
100
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Interface.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include <hxcpp.h>
|
||||
#if (HXCPP_API_LEVEL < 330)
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
void Interface::__Mark(hx::MarkContext *__inCtx)
|
||||
{
|
||||
Object *obj = __GetRealObject();
|
||||
HX_MARK_OBJECT(obj);
|
||||
}
|
||||
|
||||
hx::Object *Interface::__ToInterface(const hx::type_info &i)
|
||||
{
|
||||
return __GetRealObject()->__ToInterface(i);
|
||||
}
|
||||
int Interface::__GetType() const
|
||||
{
|
||||
return const_cast<Interface *>(this)->__GetRealObject()->__GetType();
|
||||
}
|
||||
|
||||
void *Interface::__GetHandle() const
|
||||
{
|
||||
return const_cast<Interface *>(this)->__GetRealObject()->__GetHandle();
|
||||
}
|
||||
|
||||
hx::FieldRef Interface::__FieldRef(const ::String &s)
|
||||
{
|
||||
return __GetRealObject()->__FieldRef(s);
|
||||
}
|
||||
|
||||
::String Interface::__ToString() const
|
||||
{
|
||||
return const_cast<Interface *>(this)->__GetRealObject()->__ToString();
|
||||
}
|
||||
|
||||
int Interface::__ToInt() const
|
||||
{
|
||||
return const_cast<Interface *>(this)->__GetRealObject()->__ToInt();
|
||||
}
|
||||
|
||||
double Interface::__ToDouble() const
|
||||
{
|
||||
return const_cast<Interface *>(this)->__GetRealObject()->__ToDouble();
|
||||
}
|
||||
|
||||
const char * Interface::__CStr() const
|
||||
{
|
||||
return const_cast<Interface *>(this)->__GetRealObject()->__CStr();
|
||||
}
|
||||
|
||||
::String Interface::toString()
|
||||
{
|
||||
return __GetRealObject()->toString();
|
||||
}
|
||||
|
||||
bool Interface::__HasField(const ::String &s)
|
||||
{
|
||||
return __GetRealObject()->__HasField(s);
|
||||
}
|
||||
|
||||
hx::Val Interface::__Field(const ::String &s, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
return __GetRealObject()->__Field(s,inCallProp);
|
||||
}
|
||||
|
||||
Dynamic Interface::__IField(int i)
|
||||
{
|
||||
return __GetRealObject()->__IField( i);
|
||||
}
|
||||
|
||||
hx::Val Interface::__SetField(const ::String &s,const hx::Val &d, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
return __GetRealObject()->__SetField(s,d,inCallProp);
|
||||
}
|
||||
|
||||
void Interface::__SetThis(Dynamic d)
|
||||
{
|
||||
return __GetRealObject()->__SetThis(d);
|
||||
}
|
||||
|
||||
void Interface::__GetFields(Array< ::String> &a)
|
||||
{
|
||||
return __GetRealObject()->__GetFields(a);
|
||||
}
|
||||
|
||||
hx::Class Interface::__GetClass() const
|
||||
{
|
||||
return const_cast<Interface *>(this)->__GetRealObject()->__GetClass();
|
||||
}
|
||||
|
||||
int Interface::__Compare(const hx::Object *o) const
|
||||
{
|
||||
return const_cast<Interface *>(this)->__GetRealObject()->__Compare(o);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
#endif // HXCPP_API_LEVEL 330
|
||||
788
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Lib.cpp
Normal file
788
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Lib.cpp
Normal file
@ -0,0 +1,788 @@
|
||||
#include <hxcpp.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if (defined (IPHONE) || defined(EMSCRIPTEN) || defined(STATIC_LINK) || defined(APPLETV) ) && \
|
||||
!defined(HXCPP_DLL_IMPORT) && (!defined(HXCPP_DLL_EXPORT) || defined(HXCPP_SCRIPTABLE) )
|
||||
#define HXCPP_NO_DYNAMIC_LOADING
|
||||
#elif !defined(ANDROID) && !defined(HX_WINRT) && !defined(IPHONE) && !defined(EMSCRIPTEN) && \
|
||||
!defined(STATIC_LINK) && !defined(APPLETV)
|
||||
#define HXCPP_TRY_HAXELIB
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_TRY_HAXELIB
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if defined(BLACKBERRY)
|
||||
using namespace std;
|
||||
#endif
|
||||
#ifdef HXCPP_LOAD_DEBUG
|
||||
bool gLoadDebug = true;
|
||||
#else
|
||||
bool gLoadDebug = false;
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_NO_DYNAMIC_LOADING
|
||||
|
||||
typedef void *Module;
|
||||
Module hxLoadLibrary(const String &) { return 0; }
|
||||
void hxFreeLibrary(Module) { }
|
||||
|
||||
#elif defined _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
typedef HMODULE Module;
|
||||
|
||||
#ifdef HX_WINRT
|
||||
Module hxLoadLibrary(String inLib) { return LoadPackagedLibrary(inLib.__WCStr(),0); }
|
||||
#else // Windows, not WinRT
|
||||
Module hxLoadLibrary(String inLib)
|
||||
{
|
||||
HMODULE result = LoadLibraryW(inLib.__WCStr());
|
||||
if (gLoadDebug)
|
||||
{
|
||||
if (result)
|
||||
printf("Loaded module : %S.\n", inLib.__WCStr());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *hxFindSymbol(Module inModule, const char *inSymbol) { return (void *)GetProcAddress(inModule,inSymbol); }
|
||||
|
||||
void hxFreeLibrary(Module inModule) { FreeLibrary(inModule); }
|
||||
|
||||
#else
|
||||
|
||||
typedef void *Module;
|
||||
|
||||
#include <dlfcn.h>
|
||||
typedef void *Module;
|
||||
Module hxLoadLibrary(String inLib)
|
||||
{
|
||||
int flags = RTLD_GLOBAL;
|
||||
#if defined(HXCPP_RTLD_LAZY) || defined(IPHONE) || defined(EMSCRIPTEN) || defined(STATIC_LINK) || defined(APPLETV)
|
||||
flags |= RTLD_LAZY;
|
||||
#else
|
||||
flags |= RTLD_NOW;
|
||||
#endif
|
||||
|
||||
Module result = dlopen(inLib.__CStr(), flags);
|
||||
if (gLoadDebug)
|
||||
{
|
||||
#ifdef HX_WINRT
|
||||
if (result)
|
||||
WINRT_LOG("Loaded : %s.\n", inLib.__CStr());
|
||||
else
|
||||
WINRT_LOG("Error loading library: (%s) %s\n", inLib.__CStr(), dlerror());
|
||||
#else
|
||||
if (result)
|
||||
printf("Loaded : %s.\n", inLib.__CStr());
|
||||
else
|
||||
printf("Error loading library: (%s) %s\n", inLib.__CStr(), dlerror());
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void *hxFindSymbol(Module inModule, const char *inSymbol) { return dlsym(inModule,inSymbol); }
|
||||
|
||||
void hxFreeLibrary(Module inModule) { dlclose(inModule); }
|
||||
|
||||
#endif
|
||||
|
||||
typedef std::map<std::string,Module> LoadedModule;
|
||||
|
||||
static LoadedModule sgLoadedModule;
|
||||
typedef std::vector<Module> ModuleList;
|
||||
static ModuleList sgOrderedModules;
|
||||
|
||||
typedef hx::Object * (*prim_0)();
|
||||
typedef hx::Object * (*prim_1)(hx::Object *);
|
||||
typedef hx::Object * (*prim_2)(hx::Object *,hx::Object *);
|
||||
typedef hx::Object * (*prim_3)(hx::Object *,hx::Object *,hx::Object *);
|
||||
typedef hx::Object * (*prim_4)(hx::Object *,hx::Object *,hx::Object *,hx::Object *);
|
||||
typedef hx::Object * (*prim_5)(hx::Object *,hx::Object *,hx::Object *,hx::Object *,hx::Object *);
|
||||
typedef hx::Object * (*prim_mult)(hx::Object **inArray,int inArgs);
|
||||
|
||||
typedef void *(*FundFunc)();
|
||||
|
||||
|
||||
class ExternalPrimitive : public hx::Object
|
||||
{
|
||||
public:
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdExternalPrimitive };
|
||||
|
||||
inline void *operator new( size_t inSize )
|
||||
{ return hx::InternalCreateConstBuffer(0,(int)inSize); }
|
||||
void operator delete( void *) { }
|
||||
|
||||
ExternalPrimitive(void *inProc,int inArgCount,const String &inName) :
|
||||
mProc(inProc), mArgCount(inArgCount), mName(inName.makePermanent())
|
||||
{
|
||||
functionName = ("extern::cffi "+mName).makePermanent().raw_ptr();
|
||||
}
|
||||
|
||||
virtual int __GetType() const { return vtFunction; }
|
||||
String __ToString() const { return mName; }
|
||||
|
||||
Dynamic __run()
|
||||
{
|
||||
HX_STACK_FRAME(hx::EXTERN_CLASS_NAME, "cffi",0, functionName, __FILE__, __LINE__,0);
|
||||
if (mArgCount!=0) throw HX_INVALID_ARG_COUNT;
|
||||
if (mProc==0) hx::Throw( HX_NULL_FUNCTION_POINTER );
|
||||
return ((prim_0)mProc)();
|
||||
}
|
||||
Dynamic __run(D a)
|
||||
{
|
||||
HX_STACK_FRAME(hx::EXTERN_CLASS_NAME, "cffi",0, functionName, __FILE__, __LINE__,0);
|
||||
if (mArgCount!=1) throw HX_INVALID_ARG_COUNT;
|
||||
if (mProc==0) hx::Throw( HX_NULL_FUNCTION_POINTER );
|
||||
return ((prim_1)mProc)(a.GetPtr());
|
||||
}
|
||||
Dynamic __run(D a,D b)
|
||||
{
|
||||
HX_STACK_FRAME(hx::EXTERN_CLASS_NAME, "cffi",0, functionName, __FILE__, __LINE__,0);
|
||||
if (mArgCount!=2) throw HX_INVALID_ARG_COUNT;
|
||||
if (mProc==0) hx::Throw( HX_NULL_FUNCTION_POINTER );
|
||||
return ((prim_2)mProc)(a.GetPtr(),b.GetPtr());
|
||||
}
|
||||
Dynamic __run(D a,D b,D c)
|
||||
{
|
||||
HX_STACK_FRAME(hx::EXTERN_CLASS_NAME, "cffi",0, functionName, __FILE__, __LINE__,0);
|
||||
if (mArgCount!=3) throw HX_INVALID_ARG_COUNT;
|
||||
if (mProc==0) hx::Throw( HX_NULL_FUNCTION_POINTER );
|
||||
return ((prim_3)mProc)(a.GetPtr(),b.GetPtr(),c.GetPtr());
|
||||
}
|
||||
Dynamic __run(D a,D b,D c,D d)
|
||||
{
|
||||
HX_STACK_FRAME(hx::EXTERN_CLASS_NAME, "cffi",0, functionName, __FILE__, __LINE__,0);
|
||||
if (mArgCount!=4) throw HX_INVALID_ARG_COUNT;
|
||||
if (mProc==0) hx::Throw( HX_NULL_FUNCTION_POINTER );
|
||||
return ((prim_4)mProc)(a.GetPtr(),b.GetPtr(),c.GetPtr(),d.GetPtr());
|
||||
}
|
||||
Dynamic __run(D a,D b,D c,D d,D e)
|
||||
{
|
||||
HX_STACK_FRAME(hx::EXTERN_CLASS_NAME, "cffi",0, functionName, __FILE__, __LINE__,0);
|
||||
if (mArgCount!=5) throw HX_INVALID_ARG_COUNT;
|
||||
if (mProc==0) hx::Throw( HX_NULL_FUNCTION_POINTER );
|
||||
return ((prim_5)mProc)(a.GetPtr(),b.GetPtr(),c.GetPtr(),d.GetPtr(),e.GetPtr());
|
||||
}
|
||||
|
||||
Dynamic __Run(const Array<Dynamic> &inArgs)
|
||||
{
|
||||
HX_STACK_FRAME(hx::EXTERN_CLASS_NAME, "cffi",0, functionName, __FILE__, __LINE__,0);
|
||||
if (mArgCount!=-1 && mArgCount!=inArgs->length)
|
||||
throw HX_INVALID_ARG_COUNT;
|
||||
if (mProc==0) hx::Throw( HX_NULL_FUNCTION_POINTER );
|
||||
return ((prim_mult)mProc)( (hx::Object **)inArgs->GetBase(), inArgs->length );
|
||||
}
|
||||
|
||||
int __Compare(const hx::Object *inRHS) const
|
||||
{
|
||||
const ExternalPrimitive *other = dynamic_cast<const ExternalPrimitive *>(inRHS);
|
||||
if (!other)
|
||||
return -1;
|
||||
return mProc==other->mProc;
|
||||
}
|
||||
|
||||
|
||||
void *mProc;
|
||||
int mArgCount;
|
||||
String mName;
|
||||
const char* functionName;
|
||||
};
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
typedef std::map<String,ExternalPrimitive *> LoadedMap;
|
||||
LoadedMap sLoadedMap;
|
||||
}
|
||||
|
||||
|
||||
typedef void (*SetLoaderProcFunc)(void *(*)(const char *));
|
||||
typedef void *(*GetNekoEntryFunc)();
|
||||
typedef void (*NekoEntryFunc)();
|
||||
|
||||
|
||||
#ifdef HXCPP_TRY_HAXELIB
|
||||
|
||||
static String GetFileContents(String inFile)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
FILE *file = fopen(inFile.__CStr(),"rb");
|
||||
#else
|
||||
FILE *file = _wfopen(inFile.__WCStr(),L"rb");
|
||||
#endif
|
||||
if (!file)
|
||||
{
|
||||
// printf("Could not open %S\n", inFile.__s);
|
||||
return null();
|
||||
}
|
||||
|
||||
char buf[2049];
|
||||
int bytes = fread(buf,1,2048,file);
|
||||
fclose(file);
|
||||
if (bytes<1)
|
||||
return null();
|
||||
buf[bytes]='\0';
|
||||
return String::create(buf);
|
||||
}
|
||||
|
||||
static String GetEnv(const char *inPath)
|
||||
{
|
||||
const char *env = getenv(inPath);
|
||||
String result(env,env?strlen(env):0);
|
||||
return result;
|
||||
}
|
||||
|
||||
static String FindHaxelib(String inLib)
|
||||
{
|
||||
bool loadDebug = getenv("HXCPP_LOAD_DEBUG");
|
||||
|
||||
// printf("FindHaxelib %S\n", inLib.__s);
|
||||
|
||||
String haxepath;
|
||||
hx::strbuf convertBuf;
|
||||
hx::strbuf convertBuf1;
|
||||
|
||||
struct stat s;
|
||||
if ( (stat(".haxelib",&s)==0 && (s.st_mode & S_IFDIR) ) )
|
||||
haxepath = HX_CSTRING(".haxelib");
|
||||
if (loadDebug)
|
||||
printf( haxepath.length ? "Found local .haxelib\n" : "No local .haxelib\n");
|
||||
|
||||
if (haxepath.length==0)
|
||||
{
|
||||
haxepath = GetEnv("HAXELIB_PATH");
|
||||
if (loadDebug)
|
||||
printf("HAXELIB_PATH env:%s\n", haxepath.out_str(&convertBuf));
|
||||
}
|
||||
|
||||
if (haxepath.length==0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
String home = GetEnv("HOMEDRIVE") + GetEnv("HOMEPATH") + HX_CSTRING("/.haxelib");
|
||||
#else
|
||||
String home = GetEnv("HOME") + HX_CSTRING("/.haxelib");
|
||||
#endif
|
||||
haxepath = GetFileContents(home);
|
||||
if (loadDebug)
|
||||
printf("HAXEPATH home:%s\n", haxepath.out_str(&convertBuf));
|
||||
}
|
||||
|
||||
if (haxepath.length==0)
|
||||
{
|
||||
haxepath = GetEnv("HAXEPATH");
|
||||
if (loadDebug)
|
||||
printf("HAXEPATH env:%s\n", haxepath.out_str(&convertBuf));
|
||||
if (haxepath.length>0)
|
||||
{
|
||||
haxepath += HX_CSTRING("/lib");
|
||||
}
|
||||
}
|
||||
|
||||
if (loadDebug)
|
||||
printf("HAXEPATH dir:%s\n", haxepath.out_str(&convertBuf));
|
||||
|
||||
if (haxepath.length==0)
|
||||
{
|
||||
haxepath = GetFileContents(HX_CSTRING("/etc/.haxepath"));
|
||||
if (loadDebug) printf("HAXEPATH etc:%s\n", haxepath.out_str(&convertBuf));
|
||||
}
|
||||
|
||||
if (haxepath.length==0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
haxepath = HX_CSTRING("C:\\HaxeToolkit\\haxe\\lib");
|
||||
#else
|
||||
haxepath = HX_CSTRING("/usr/lib/haxe/lib");
|
||||
#endif
|
||||
if (loadDebug) printf("HAXEPATH default:%s\n", haxepath.out_str(&convertBuf));
|
||||
}
|
||||
|
||||
String dir = haxepath + HX_CSTRING("/") + inLib + HX_CSTRING("/");
|
||||
|
||||
|
||||
String dev = dir + HX_CSTRING(".dev");
|
||||
String path = GetFileContents(dev);
|
||||
if (loadDebug) printf("Read dev location from file :%s, got %s\n", dev.out_str(&convertBuf), path.out_str(&convertBuf1));
|
||||
if (path.length==0)
|
||||
{
|
||||
path = GetFileContents(dir + HX_CSTRING(".current"));
|
||||
if (path.length==0)
|
||||
return null();
|
||||
// Replace "." with "," ...
|
||||
String with_commas;
|
||||
for(int i=0;i<path.length;i++)
|
||||
if (path.getChar(i)=='.')
|
||||
with_commas += HX_CSTRING(",");
|
||||
else
|
||||
with_commas += path.substr(i,1);
|
||||
|
||||
path = dir + with_commas + HX_CSTRING("/");
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
#endif // HXCPP_TRY_HAXELIB
|
||||
|
||||
|
||||
typedef std::map<std::string,void *> RegistrationMap;
|
||||
RegistrationMap *sgRegisteredPrims=0;
|
||||
|
||||
|
||||
|
||||
static std::vector<String> sgLibPath;
|
||||
|
||||
static bool sgLibPathIsInit = false;
|
||||
|
||||
String __hxcpp_get_bin_dir()
|
||||
{
|
||||
return
|
||||
#if defined(HX_WINRT)
|
||||
#ifdef HXCPP_M64
|
||||
HX_CSTRING("WinRT64");
|
||||
#else
|
||||
HX_CSTRING("WinRT");
|
||||
#endif
|
||||
#elif defined(_WIN32)
|
||||
#ifdef HXCPP_M64
|
||||
HX_CSTRING("Windows64");
|
||||
#else
|
||||
HX_CSTRING("Windows");
|
||||
#endif
|
||||
// Unix...
|
||||
#elif defined(__APPLE__)
|
||||
#ifdef HXCPP_ARM64
|
||||
HX_CSTRING("MacArm64");
|
||||
#elif defined(HXCPP_M64)
|
||||
HX_CSTRING("Mac64");
|
||||
#else
|
||||
HX_CSTRING("Mac");
|
||||
#endif
|
||||
#elif defined (ANDROID)
|
||||
HX_CSTRING("Android");
|
||||
#elif defined(WEBOS)
|
||||
HX_CSTRING("webOS");
|
||||
#elif defined(BLACKBERRY)
|
||||
HX_CSTRING("BlackBerry");
|
||||
#elif defined(RASPBERRYPI)
|
||||
HX_CSTRING("RPi");
|
||||
#elif defined(EMSCRIPTEN)
|
||||
HX_CSTRING("Emscripten");
|
||||
#elif defined(TIZEN)
|
||||
HX_CSTRING("Tizen");
|
||||
#elif defined(IPHONESIM)
|
||||
HX_CSTRING("IPhoneSim");
|
||||
#elif defined(IPHONEOS)
|
||||
HX_CSTRING("IPhoneOs");
|
||||
#elif defined(APPLETVSIM)
|
||||
HX_CSTRING("AppleTVSim");
|
||||
#elif defined(APPLETVOS)
|
||||
HX_CSTRING("AppleTVOS");
|
||||
#else
|
||||
#ifdef HXCPP_M64
|
||||
HX_CSTRING("Linux64");
|
||||
#else
|
||||
HX_CSTRING("Linux");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
String __hxcpp_get_dll_extension()
|
||||
{
|
||||
return
|
||||
#if defined(_WIN32) || defined(HX_WINRT)
|
||||
HX_CSTRING(".dll");
|
||||
#elif defined(IPHONEOS)
|
||||
HX_CSTRING(".ios.dylib");
|
||||
#elif defined(IPHONESIM)
|
||||
HX_CSTRING(".sim.dylib");
|
||||
#elif defined(APPLETVOS)
|
||||
HX_CSTRING(".tvos.dylib");
|
||||
#elif defined(APPLETVSIM)
|
||||
HX_CSTRING(".sim.dylib");
|
||||
#elif defined(__APPLE__)
|
||||
HX_CSTRING(".dylib");
|
||||
#elif defined(ANDROID) || defined(GPH) || defined(WEBOS) || defined(BLACKBERRY) || defined(EMSCRIPTEN) || defined(TIZEN)
|
||||
HX_CSTRING(".so");
|
||||
#else
|
||||
HX_CSTRING(".dso");
|
||||
#endif
|
||||
}
|
||||
|
||||
void __hxcpp_push_dll_path(String inPath)
|
||||
{
|
||||
int last = inPath.length-1;
|
||||
int lastCode = (last>0) ? inPath.cca(last) : -1;
|
||||
|
||||
if ( lastCode!='\\' && lastCode!='/')
|
||||
sgLibPath.push_back( (inPath + HX_CSTRING("/")).makePermanent() );
|
||||
else
|
||||
sgLibPath.push_back( inPath.makePermanent() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef HXCPP_NO_DYNAMIC_LOADING
|
||||
|
||||
Dynamic __loadprim(String inLib, String inPrim,int inArgCount)
|
||||
{
|
||||
String full_name = inPrim;
|
||||
switch(inArgCount)
|
||||
{
|
||||
case 0: full_name += HX_CSTRING("__0"); break;
|
||||
case 1: full_name += HX_CSTRING("__1"); break;
|
||||
case 2: full_name += HX_CSTRING("__2"); break;
|
||||
case 3: full_name += HX_CSTRING("__3"); break;
|
||||
case 4: full_name += HX_CSTRING("__4"); break;
|
||||
case 5: full_name += HX_CSTRING("__5"); break;
|
||||
default:
|
||||
full_name += HX_CSTRING("__MULT");
|
||||
}
|
||||
|
||||
String libString = inLib + HX_CSTRING("_") + full_name;
|
||||
ExternalPrimitive *prim = sLoadedMap[libString];
|
||||
if (prim)
|
||||
return Dynamic(prim);
|
||||
|
||||
if (sgRegisteredPrims)
|
||||
{
|
||||
void *registered = (*sgRegisteredPrims)[full_name.__CStr()];
|
||||
// Try with lib name ...
|
||||
if (!registered)
|
||||
{
|
||||
registered = (*sgRegisteredPrims)[libString.__CStr()];
|
||||
if (registered)
|
||||
full_name = libString;
|
||||
}
|
||||
|
||||
if (registered)
|
||||
{
|
||||
libString = libString.makePermanent();
|
||||
prim = new ExternalPrimitive(registered,inArgCount,libString);
|
||||
sLoadedMap[libString] = prim;
|
||||
return Dynamic(prim);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Primitive not found : %s\n", full_name.__CStr() );
|
||||
return null();
|
||||
}
|
||||
|
||||
void *__hxcpp_get_proc_address(String inLib, String inPrim,bool ,bool inQuietFail)
|
||||
{
|
||||
if (sgRegisteredPrims)
|
||||
return (*sgRegisteredPrims)[inPrim.__CStr()];
|
||||
|
||||
if (!inQuietFail)
|
||||
printf("Primitive not found : %s\n", inPrim.__CStr() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __hxcpp_unload_all_libraries() { return 0; }
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
extern "C" void *hx_cffi(const char *inName);
|
||||
|
||||
|
||||
void *__hxcpp_get_proc_address(String inLib, String full_name,bool inNdllProc,bool inQuietFail)
|
||||
{
|
||||
String bin = __hxcpp_get_bin_dir();
|
||||
String deviceExt = __hxcpp_get_dll_extension();
|
||||
|
||||
|
||||
#ifdef HX_ANDROID
|
||||
String module_name = HX_CSTRING("lib") + inLib;
|
||||
#else
|
||||
String module_name = inLib;
|
||||
#endif
|
||||
|
||||
#if defined(HX_WINRT) && defined(HXCPP_DEBUG)
|
||||
gLoadDebug = true;
|
||||
#elif defined(IPHONE) || defined(APPLETV)
|
||||
gLoadDebug = true;
|
||||
setenv("DYLD_PRINT_APIS","1",true);
|
||||
|
||||
#elif !defined(HX_WINRT)
|
||||
gLoadDebug = gLoadDebug || getenv("HXCPP_LOAD_DEBUG");
|
||||
#endif
|
||||
|
||||
if (!sgLibPathIsInit)
|
||||
{
|
||||
sgLibPathIsInit = true;
|
||||
#ifndef HX_WINRT
|
||||
sgLibPath.push_back( HX_CSTRING("./") );
|
||||
#endif
|
||||
#ifdef HX_MACOS
|
||||
sgLibPath.push_back( HX_CSTRING("@executable_path/") );
|
||||
#endif
|
||||
sgLibPath.push_back( HX_CSTRING("") );
|
||||
|
||||
#ifdef HXCPP_TRY_HAXELIB
|
||||
String hxcpp = GetEnv("HXCPP");
|
||||
if (hxcpp.length==0)
|
||||
hxcpp = FindHaxelib( HX_CSTRING("hxcpp") );
|
||||
if (hxcpp.length!=0)
|
||||
__hxcpp_push_dll_path(hxcpp+HX_CSTRING("/bin/") + bin + HX_CSTRING("/"));
|
||||
#endif
|
||||
}
|
||||
|
||||
hx::strbuf convertBuf;
|
||||
|
||||
|
||||
Module module = sgLoadedModule[module_name.utf8_str()];
|
||||
|
||||
bool new_module = module==0;
|
||||
|
||||
if (!module && sgRegisteredPrims)
|
||||
{
|
||||
void *registered = (*sgRegisteredPrims)[full_name.__CStr()];
|
||||
// Try with lib name ...
|
||||
if (!registered)
|
||||
{
|
||||
String libString = inLib + HX_CSTRING("_") + full_name;
|
||||
registered = (*sgRegisteredPrims)[libString.__CStr()];
|
||||
}
|
||||
|
||||
if (registered)
|
||||
return registered;
|
||||
}
|
||||
|
||||
if (!module && gLoadDebug)
|
||||
{
|
||||
#ifdef HX_WINRT
|
||||
WINRT_LOG("Searching for %s...\n", inLib.out_str(&convertBuf));
|
||||
#elif defined(ANDROID)
|
||||
__android_log_print(ANDROID_LOG_INFO, "loader", "Searching for %s...", module_name.out_str(&convertBuf));
|
||||
#else
|
||||
printf("Searching for %s...\n", inLib.out_str(&convertBuf));
|
||||
#endif
|
||||
}
|
||||
|
||||
String haxelibPath;
|
||||
|
||||
#ifdef HX_WINRT
|
||||
for(int e=0; module==0 && e<1; e++) //only accept DLL
|
||||
#else
|
||||
for(int e=0; module==0 && e<3; e++)
|
||||
#endif
|
||||
{
|
||||
String extension = e==0 ? deviceExt : e==1 ? HX_CSTRING(".ndll") : HX_CSTRING("");
|
||||
|
||||
for(int path=0;path<sgLibPath.size();path++)
|
||||
{
|
||||
#ifdef HX_WINRT
|
||||
String testPath = module_name + extension;
|
||||
#else
|
||||
String testPath = sgLibPath[path] + module_name + extension;
|
||||
#endif
|
||||
if (gLoadDebug)
|
||||
{
|
||||
#ifdef HX_WINRT
|
||||
WINRT_LOG(" try %s...\n", testPath.out_str(&convertBuf));
|
||||
#elif !defined(ANDROID)
|
||||
printf(" try %s...\n", testPath.out_str(&convertBuf));
|
||||
#else
|
||||
__android_log_print(ANDROID_LOG_INFO, "loader", "Try %s", testPath.out_str(&convertBuf));
|
||||
#endif
|
||||
}
|
||||
module = hxLoadLibrary(testPath);
|
||||
if (module)
|
||||
{
|
||||
if (gLoadDebug)
|
||||
{
|
||||
#ifdef HX_WINRT
|
||||
WINRT_LOG("Found %s\n", testPath.out_str(&convertBuf));
|
||||
#elif !defined(ANDROID)
|
||||
printf("Found %s\n", testPath.out_str(&convertBuf));
|
||||
#else
|
||||
__android_log_print(ANDROID_LOG_INFO, "loader", "Found %s", testPath.out_str(&convertBuf));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HXCPP_TRY_HAXELIB
|
||||
if (!module)
|
||||
{
|
||||
if (e==0)
|
||||
haxelibPath = FindHaxelib(inLib);
|
||||
|
||||
if (haxelibPath.length!=0)
|
||||
{
|
||||
String testPath = haxelibPath + HX_CSTRING("/ndll/") + bin + HX_CSTRING("/") + inLib + extension;
|
||||
if (gLoadDebug)
|
||||
printf(" try %s...\n", testPath.out_str(&convertBuf));
|
||||
module = hxLoadLibrary(testPath);
|
||||
if (module && gLoadDebug)
|
||||
{
|
||||
printf("Found %s\n", testPath.out_str(&convertBuf));
|
||||
}
|
||||
|
||||
|
||||
#if defined(HX_MACOS) && defined(HXCPP_ARM64)
|
||||
if (!module)
|
||||
{
|
||||
// Fat binary?
|
||||
String testPath = haxelibPath + HX_CSTRING("/ndll/Mac64/") + inLib + extension;
|
||||
if (gLoadDebug)
|
||||
printf(" try %s...\n", testPath.out_str(&convertBuf));
|
||||
module = hxLoadLibrary(testPath);
|
||||
if (module && gLoadDebug)
|
||||
{
|
||||
printf("Found %s\n", testPath.out_str(&convertBuf));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!module)
|
||||
{
|
||||
hx::Throw(HX_CSTRING("Could not load module ") + inLib + HX_CSTRING("@") + full_name);
|
||||
}
|
||||
|
||||
|
||||
if (new_module)
|
||||
{
|
||||
sgLoadedModule[module_name.utf8_str()] = module;
|
||||
|
||||
sgOrderedModules.push_back(module);
|
||||
|
||||
SetLoaderProcFunc set_loader = (SetLoaderProcFunc)hxFindSymbol(module,"hx_set_loader");
|
||||
if (set_loader)
|
||||
set_loader(hx_cffi);
|
||||
|
||||
GetNekoEntryFunc func = (GetNekoEntryFunc)hxFindSymbol(module,"__neko_entry_point");
|
||||
if (func)
|
||||
{
|
||||
NekoEntryFunc entry = (NekoEntryFunc)func();
|
||||
if (entry)
|
||||
entry();
|
||||
}
|
||||
}
|
||||
|
||||
FundFunc proc_query = (FundFunc)hxFindSymbol(module,full_name.__CStr());
|
||||
if (!proc_query)
|
||||
proc_query = (FundFunc)hxFindSymbol(module, (inLib + HX_CSTRING("_") + full_name).__CStr());
|
||||
|
||||
if (!proc_query && !inQuietFail)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
__android_log_print(ANDROID_LOG_ERROR, "loader", "Could not find primitive %s in %p",
|
||||
full_name.__CStr(), module);
|
||||
#else
|
||||
fprintf(stderr,"Could not find primitive %s.\n", full_name.__CStr());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!inNdllProc)
|
||||
return (void *)proc_query;
|
||||
|
||||
void *proc = proc_query();
|
||||
if (!proc && !inQuietFail)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
__android_log_print(ANDROID_LOG_ERROR, "loader", "Could not identify primitive %s in %s",
|
||||
full_name.__CStr(), inLib.__CStr() );
|
||||
#else
|
||||
fprintf(stderr,"Could not identify primitive %s in %s\n", full_name.__CStr(),inLib.__CStr());
|
||||
#endif
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
int __hxcpp_unload_all_libraries()
|
||||
{
|
||||
int unloaded = 0;
|
||||
while(sgOrderedModules.size())
|
||||
{
|
||||
Module module = sgOrderedModules.back();
|
||||
sgOrderedModules.pop_back();
|
||||
hxFreeLibrary(module);
|
||||
unloaded++;
|
||||
}
|
||||
return unloaded;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Dynamic __loadprim(String inLib, String inPrim,int inArgCount)
|
||||
{
|
||||
String full_name = inPrim;
|
||||
switch(inArgCount)
|
||||
{
|
||||
case 0: full_name += HX_CSTRING("__0"); break;
|
||||
case 1: full_name += HX_CSTRING("__1"); break;
|
||||
case 2: full_name += HX_CSTRING("__2"); break;
|
||||
case 3: full_name += HX_CSTRING("__3"); break;
|
||||
case 4: full_name += HX_CSTRING("__4"); break;
|
||||
case 5: full_name += HX_CSTRING("__5"); break;
|
||||
default:
|
||||
full_name += HX_CSTRING("__MULT");
|
||||
}
|
||||
|
||||
String primName = inLib+HX_CSTRING("@")+full_name;
|
||||
ExternalPrimitive *saved = sLoadedMap[primName];
|
||||
if (saved)
|
||||
return Dynamic(saved);
|
||||
|
||||
void *proc = __hxcpp_get_proc_address(inLib,full_name,true);
|
||||
if (proc)
|
||||
{
|
||||
primName = primName.makePermanent();
|
||||
|
||||
saved = new ExternalPrimitive(proc,inArgCount,primName);
|
||||
sLoadedMap[primName] = saved;
|
||||
return Dynamic(saved);
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
#endif // not HXCPP_NO_DYNAMIC_LOADING
|
||||
|
||||
void __hxcpp_run_dll(String inLib, String inFunc)
|
||||
{
|
||||
typedef void (*VoidVoid)();
|
||||
|
||||
void *result = __hxcpp_get_proc_address(inLib,inFunc,false);
|
||||
if (result)
|
||||
((VoidVoid)result)();
|
||||
}
|
||||
|
||||
// This can be used to find symbols in static libraries
|
||||
|
||||
int __hxcpp_register_prim(const char *inName,void *inProc)
|
||||
{
|
||||
if (sgRegisteredPrims==0)
|
||||
sgRegisteredPrims = new RegistrationMap();
|
||||
void * &proc = (*sgRegisteredPrims)[inName];
|
||||
if (proc)
|
||||
{
|
||||
printf("Warning : duplicate symbol %s\n", inName);
|
||||
}
|
||||
proc = inProc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
14
Kha/Backends/Kore-hxcpp/khacpp/src/hx/NoFiles.cpp
Normal file
14
Kha/Backends/Kore-hxcpp/khacpp/src/hx/NoFiles.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include <hxcpp.h>
|
||||
|
||||
namespace hx {
|
||||
const char *__hxcpp_all_files[] = {
|
||||
0 };
|
||||
|
||||
const char *__hxcpp_all_files_fullpath[] = {
|
||||
0 };
|
||||
|
||||
const char *__hxcpp_all_classes[] = {
|
||||
0 };
|
||||
} // namespace hx
|
||||
void __files__boot() { __hxcpp_set_debugger_info(hx::__hxcpp_all_classes, hx::__hxcpp_all_files_fullpath); }
|
||||
|
||||
222
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Object.cpp
Normal file
222
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Object.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
#include <hxcpp.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <hxMath.h>
|
||||
//#include <hxMacros.h>
|
||||
#include <cpp/CppInt32__.h>
|
||||
#include <map>
|
||||
|
||||
#ifdef KINC_CONSOLE
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
// Stoopid windows ...
|
||||
#ifdef RegisterClass
|
||||
#undef RegisterClass
|
||||
#endif
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <wchar.h>
|
||||
#ifndef EMSCRIPTEN
|
||||
typedef int64_t __int64;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
#include <hx/Scriptable.h>
|
||||
#endif
|
||||
|
||||
|
||||
// --- hxObject -----------------------------------------
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
String sNone[] = { String(null()) };
|
||||
|
||||
#if (HXCPP_API_LEVEL>=332)
|
||||
bool Object::_hx_isInstanceOf(int inClassId)
|
||||
{
|
||||
return inClassId == hx::Object::_hx_ClassId;
|
||||
}
|
||||
#endif
|
||||
|
||||
Dynamic Object::__IField(int inFieldID)
|
||||
{
|
||||
return __Field( __hxcpp_field_from_id(inFieldID), HX_PROP_DYNAMIC );
|
||||
}
|
||||
|
||||
double Object::__INumField(int inFieldID)
|
||||
{
|
||||
return __Field( __hxcpp_field_from_id(inFieldID), HX_PROP_DYNAMIC );
|
||||
}
|
||||
|
||||
Dynamic *Object::__GetFieldMap() { return 0; }
|
||||
|
||||
|
||||
int Object::__Compare(const Object *inRHS) const
|
||||
{
|
||||
#if (HXCPP_API_LEVEL<331)
|
||||
hx::Object *real = const_cast<Object *>(this)->__GetRealObject();
|
||||
#else
|
||||
hx::Object *real = const_cast<Object *>(this);
|
||||
#endif
|
||||
return real < inRHS ? -1 : real==inRHS ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
hx::Val Object::__Field(const String &inString, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
#if 0
|
||||
// Will be true for 'Implements dynamic'
|
||||
if (inCallProp && __GetFieldMap())
|
||||
{
|
||||
Dynamic resolve = __Field(HX_CSTRING("resolve"), false);
|
||||
if (resolve.mPtr)
|
||||
return resolve(inString);
|
||||
}
|
||||
#endif
|
||||
return null();
|
||||
}
|
||||
|
||||
bool Object::__HasField(const String &inString)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Dynamic Object::__Run(const Array<Dynamic> &inArgs) { return 0; }
|
||||
Dynamic Object::__GetItem(int inIndex) const { return null(); }
|
||||
Dynamic Object::__SetItem(int inIndex,Dynamic) { return null(); }
|
||||
|
||||
|
||||
void Object::__SetThis(Dynamic inThis) { }
|
||||
|
||||
#if (HXCPP_API_LEVEL<331)
|
||||
bool Object::__Is(Dynamic inClass ) const { return __Is(inClass.GetPtr()); }
|
||||
#endif
|
||||
|
||||
hx::Class Object__mClass;
|
||||
|
||||
bool AlwaysCast(Object *inPtr) { return inPtr!=0; }
|
||||
|
||||
#if (HXCPP_API_LEVEL < 330)
|
||||
DynamicArray Object::__EnumParams() { return DynamicArray(); }
|
||||
String Object::__Tag() const { return HX_CSTRING("<not enum>"); }
|
||||
int Object::__Index() const { return -1; }
|
||||
#endif
|
||||
|
||||
#if (HXCPP_API_LEVEL >= 330) && !defined(HXCPP_SCRIPTABLE)
|
||||
// Other implementation is in Cppia.cpp
|
||||
void *hx::Object::_hx_getInterface(int inId)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
|
||||
class Object__scriptable : public hx::Object {
|
||||
typedef Object__scriptable __ME;
|
||||
void __construct() { }
|
||||
typedef hx::Object super;
|
||||
typedef hx::Object __superString;
|
||||
HX_DEFINE_SCRIPTABLE(HX_ARR_LIST0);
|
||||
HX_DEFINE_SCRIPTABLE_DYNAMIC;
|
||||
};
|
||||
|
||||
hx::ScriptFunction Object::__script_construct;
|
||||
|
||||
static void CPPIA_CALL __s_toString(hx::CppiaCtx *ctx) {
|
||||
ctx->returnString((ctx->getThis())->toString());
|
||||
}
|
||||
static hx::ScriptNamedFunction __scriptableFunctions[] = {
|
||||
hx::ScriptNamedFunction("toString",__s_toString,"s"),
|
||||
hx::ScriptNamedFunction(0,0,0) };
|
||||
|
||||
#endif
|
||||
|
||||
void Object::__boot()
|
||||
{
|
||||
Static(Object__mClass) = hx::_hx_RegisterClass(HX_CSTRING("Dynamic"),AlwaysCast,sNone,sNone,0,0, 0, 0 );
|
||||
|
||||
#ifdef HXCPP_SCRIPTABLE
|
||||
hx::ScriptableRegisterClass( HX_CSTRING("hx.Object"), (int)sizeof(hx::Object__scriptable), __scriptableFunctions, Object__scriptable::__script_create, Object::__script_construct );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
hx::Class &Object::__SGetClass() { return Object__mClass; }
|
||||
|
||||
hx::Class Object::__GetClass() const { return Object__mClass; }
|
||||
|
||||
hx::FieldRef Object::__FieldRef(const String &inString) { return hx::FieldRef(this,inString); }
|
||||
|
||||
String Object::__ToString() const { return HX_CSTRING("Object"); }
|
||||
|
||||
const char * Object::__CStr() const { return __ToString().__CStr(); }
|
||||
|
||||
|
||||
hx::Val Object::__SetField(const String &inField,const hx::Val &inValue, hx::PropertyAccess inCallProp)
|
||||
{
|
||||
hx::Throw( HX_CSTRING("Invalid field:") + inField );
|
||||
return null();
|
||||
}
|
||||
|
||||
Dynamic Object::__run()
|
||||
{
|
||||
return __Run(Array_obj<Dynamic>::__new());
|
||||
}
|
||||
|
||||
Dynamic Object::__run(D a)
|
||||
{
|
||||
return __Run( Array_obj<Dynamic>::__new(0,1) << a );
|
||||
}
|
||||
|
||||
Dynamic Object::__run(D a,D b)
|
||||
{
|
||||
return __Run( Array_obj<Dynamic>::__new(0,2) << a << b );
|
||||
}
|
||||
|
||||
Dynamic Object::__run(D a,D b,D c)
|
||||
{
|
||||
return __Run( Array_obj<Dynamic>::__new(0,3) << a << b << c);
|
||||
}
|
||||
Dynamic Object::__run(D a,D b,D c,D d)
|
||||
{
|
||||
return __Run( Array_obj<Dynamic>::__new(0,4) << a << b << c << d);
|
||||
}
|
||||
Dynamic Object::__run(D a,D b,D c,D d,D e)
|
||||
{
|
||||
return __Run( Array_obj<Dynamic>::__new(0,5) << a << b << c << d << e);
|
||||
}
|
||||
|
||||
void Object::__GetFields(Array<String> &outFields)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
String Object::toString()
|
||||
{
|
||||
Dynamic *m = __GetFieldMap();
|
||||
if (m)
|
||||
{
|
||||
Dynamic func;
|
||||
if (FieldMapGet(m,HX_CSTRING("toString"),func))
|
||||
return func();
|
||||
}
|
||||
return __ToString();
|
||||
}
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
|
||||
|
||||
|
||||
286
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Profiler.cpp
Normal file
286
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Profiler.cpp
Normal file
@ -0,0 +1,286 @@
|
||||
#include <hxcpp.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <hx/Thread.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
|
||||
|
||||
#ifdef HX_WINRT
|
||||
#define PROFILE_PRINT WINRT_LOG
|
||||
#else
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include <android/log.h>
|
||||
#define DBGLOG(...) __android_log_print(ANDROID_LOG_INFO, "HXCPP", __VA_ARGS__)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define DBGLOG printf
|
||||
#endif
|
||||
|
||||
#define PROFILE_PRINT(...) \
|
||||
if (out) { \
|
||||
fprintf(out, __VA_ARGS__); \
|
||||
} \
|
||||
else { \
|
||||
DBGLOG(__VA_ARGS__); \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
// Profiler functionality separated into this class
|
||||
class Profiler
|
||||
{
|
||||
public:
|
||||
|
||||
Profiler(const String &inDumpFile)
|
||||
: mT0(0)
|
||||
{
|
||||
mDumpFile = inDumpFile;
|
||||
|
||||
// When a profiler exists, the profiler thread needs to exist
|
||||
gThreadMutex.Lock();
|
||||
|
||||
gThreadRefCount += 1;
|
||||
|
||||
if (gThreadRefCount == 1) {
|
||||
HxCreateDetachedThread(ProfileMainLoop, 0);
|
||||
}
|
||||
|
||||
gThreadMutex.Unlock();
|
||||
}
|
||||
|
||||
~Profiler()
|
||||
{
|
||||
gThreadMutex.Lock();
|
||||
|
||||
gThreadRefCount -= 1;
|
||||
|
||||
gThreadMutex.Unlock();
|
||||
}
|
||||
|
||||
void sample(hx::StackContext *stack)
|
||||
{
|
||||
if (mT0 == gProfileClock) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Latch the profile clock and calculate the time since the last profile
|
||||
// clock tick
|
||||
int clock = gProfileClock;
|
||||
int delta = clock - mT0;
|
||||
if (delta < 0) {
|
||||
delta = 1;
|
||||
}
|
||||
mT0 = clock;
|
||||
|
||||
int depth = stack->getDepth();
|
||||
|
||||
std::map<const char *, bool> alreadySeen;
|
||||
|
||||
// Add children time in to each stack element
|
||||
for (int i = 0; i < (depth - 1); i++) {
|
||||
const char *fullName = stack->getFullNameAtDepth(i);
|
||||
ProfileEntry &pe = mProfileStats[fullName];
|
||||
if (!alreadySeen.count(fullName)) {
|
||||
pe.total += delta;
|
||||
alreadySeen[fullName] = true;
|
||||
}
|
||||
// For everything except the very bottom of the stack, add the time to
|
||||
// that child's total with this entry
|
||||
pe.children[stack->getFullNameAtDepth(i + 1)] += delta;
|
||||
}
|
||||
|
||||
// Add the time into the actual function being executed
|
||||
if (depth > 0) {
|
||||
mProfileStats[stack->getFullNameAtDepth(depth - 1)].self += delta;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DumpStats()
|
||||
{
|
||||
FILE *out = 0;
|
||||
if (mDumpFile.length > 0)
|
||||
{
|
||||
out = fopen(mDumpFile.c_str(), "wb");
|
||||
if (!out)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ResultsEntry> results;
|
||||
|
||||
results.reserve(mProfileStats.size());
|
||||
|
||||
int total = 0;
|
||||
std::map<const char *, ProfileEntry>::iterator iter =
|
||||
mProfileStats.begin();
|
||||
while (iter != mProfileStats.end()) {
|
||||
ProfileEntry &pe = iter->second;
|
||||
ResultsEntry re;
|
||||
re.fullName = iter->first;
|
||||
re.self = pe.self;
|
||||
re.total = pe.total;
|
||||
re.childrenPlusSelf = re.self;
|
||||
ChildEntry internal;
|
||||
internal.fullName = "(internal)";
|
||||
internal.self = re.self;
|
||||
std::map<const char *, int>::iterator childIter =
|
||||
pe.children.begin();
|
||||
int childTotal = 0;
|
||||
while (childIter != pe.children.end()) {
|
||||
ChildEntry ce;
|
||||
ce.fullName = childIter->first;
|
||||
ce.self = childIter->second;
|
||||
re.childrenPlusSelf += ce.self;
|
||||
re.children.push_back(ce);
|
||||
childIter++;
|
||||
}
|
||||
re.children.push_back(internal);
|
||||
std::sort(re.children.begin(), re.children.end());
|
||||
results.push_back(re);
|
||||
total += re.self;
|
||||
iter++;
|
||||
}
|
||||
|
||||
std::sort(results.begin(), results.end());
|
||||
|
||||
double scale = total ? (100.0 / total) : 1.0;
|
||||
|
||||
int size = results.size();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
ResultsEntry &re = results[i];
|
||||
PROFILE_PRINT("%s %.2f%%/%.2f%%\n", re.fullName, re.total * scale,
|
||||
re.self * scale);
|
||||
if (re.children.size() == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int childrenSize = re.children.size();
|
||||
for (int j = 0; j < childrenSize; j++) {
|
||||
ChildEntry &ce = re.children[j];
|
||||
PROFILE_PRINT(" %s %.1f%%\n", ce.fullName,
|
||||
(100.0 * ce.self) / re.childrenPlusSelf);
|
||||
}
|
||||
}
|
||||
|
||||
if (out) {
|
||||
fclose(out);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct ProfileEntry
|
||||
{
|
||||
ProfileEntry()
|
||||
: self(0), total(0)
|
||||
{
|
||||
}
|
||||
|
||||
int self;
|
||||
std::map<const char *, int> children;
|
||||
int total;
|
||||
};
|
||||
|
||||
struct ChildEntry
|
||||
{
|
||||
bool operator <(const ChildEntry &inRHS) const
|
||||
{
|
||||
return self > inRHS.self;
|
||||
}
|
||||
|
||||
const char *fullName;
|
||||
int self;
|
||||
};
|
||||
|
||||
struct ResultsEntry
|
||||
{
|
||||
bool operator <(const ResultsEntry &inRHS) const
|
||||
{
|
||||
return ((total > inRHS.total) ||
|
||||
((total == inRHS.total) && (self < inRHS.self)));
|
||||
}
|
||||
|
||||
const char *fullName;
|
||||
int self;
|
||||
std::vector<ChildEntry> children;
|
||||
int total;
|
||||
int childrenPlusSelf;
|
||||
};
|
||||
|
||||
static THREAD_FUNC_TYPE ProfileMainLoop(void *)
|
||||
{
|
||||
int millis = 1;
|
||||
|
||||
while (gThreadRefCount > 0) {
|
||||
HxSleep(millis);
|
||||
|
||||
int count = gProfileClock + 1;
|
||||
gProfileClock = (count < 0) ? 0 : count;
|
||||
}
|
||||
|
||||
THREAD_FUNC_RET
|
||||
}
|
||||
|
||||
String mDumpFile;
|
||||
int mT0;
|
||||
std::map<const char *, ProfileEntry> mProfileStats;
|
||||
|
||||
static HxMutex gThreadMutex;
|
||||
static int gThreadRefCount;
|
||||
static int gProfileClock;
|
||||
};
|
||||
/* static */ HxMutex Profiler::gThreadMutex;
|
||||
/* static */ int Profiler::gThreadRefCount;
|
||||
/* static */ int Profiler::gProfileClock;
|
||||
|
||||
void profDestroy(Profiler * prof)
|
||||
{
|
||||
delete prof;
|
||||
}
|
||||
void profAttach(Profiler *prof, StackContext *ctx)
|
||||
{
|
||||
}
|
||||
void profDetach(Profiler *, StackContext *ctx)
|
||||
{
|
||||
delete ctx->mProfiler;
|
||||
ctx->mProfiler = 0;
|
||||
}
|
||||
void profSample(Profiler *prof, StackContext *ctx)
|
||||
{
|
||||
prof->sample(ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
|
||||
|
||||
void __hxcpp_start_profiler(String inDumpFile)
|
||||
{
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
delete stack->mProfiler;
|
||||
stack->mProfiler = new hx::Profiler(inDumpFile);
|
||||
}
|
||||
|
||||
|
||||
void __hxcpp_stop_profiler()
|
||||
{
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
stack->mProfiler->DumpStats();
|
||||
delete stack->mProfiler;
|
||||
stack->mProfiler = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
38
Kha/Backends/Kore-hxcpp/khacpp/src/hx/RunLibs.cpp
Normal file
38
Kha/Backends/Kore-hxcpp/khacpp/src/hx/RunLibs.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Use the "hxRunLibrary" code to run the static version of the code
|
||||
*/
|
||||
#include <hxcpp.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void __hxcpp_lib_main();
|
||||
int std_register_prims();
|
||||
int regexp_register_prims();
|
||||
int zlib_register_prims();
|
||||
|
||||
|
||||
std::string sgResultBuffer;
|
||||
|
||||
HXCPP_EXTERN_CLASS_ATTRIBUTES const HX_CHAR *hxRunLibrary()
|
||||
{
|
||||
#if (HXCPP_API_LEVEL<330)
|
||||
std_register_prims();
|
||||
regexp_register_prims();
|
||||
//zlib_register_prims();
|
||||
#endif
|
||||
|
||||
try {
|
||||
__hxcpp_lib_main();
|
||||
return 0;
|
||||
}
|
||||
catch ( Dynamic d ) {
|
||||
sgResultBuffer = d->toString().__s;
|
||||
return sgResultBuffer.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
838
Kha/Backends/Kore-hxcpp/khacpp/src/hx/StdLibs.cpp
Normal file
838
Kha/Backends/Kore-hxcpp/khacpp/src/hx/StdLibs.cpp
Normal file
@ -0,0 +1,838 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hxMath.h>
|
||||
#include <hx/Memory.h>
|
||||
#include <hx/Thread.h>
|
||||
|
||||
#ifdef KINC_CONSOLE
|
||||
|
||||
#elif defined(HX_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
#include <sys/time.h>
|
||||
#ifndef EMSCRIPTEN
|
||||
typedef int64_t __int64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
#ifdef WEBOS
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
#ifdef TIZEN
|
||||
#include <dlog.h>
|
||||
#endif
|
||||
#if defined(BLACKBERRY) || defined(GCW0)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <kinc/log.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <clocale>
|
||||
|
||||
|
||||
#ifdef HX_ANDROID
|
||||
#define rand() lrand48()
|
||||
#define srand(x) srand48(x)
|
||||
#endif
|
||||
|
||||
#ifdef KORE
|
||||
#define PRINTF(fmt, ...) kinc_log(KINC_LOG_LEVEL_INFO, fmt, __VA_ARGS__);
|
||||
#elif HX_WINRT
|
||||
#define PRINTF WINRT_PRINTF
|
||||
#elif defined(TIZEN)
|
||||
#define PRINTF(fmt, ...) dlog_dprint(DLOG_INFO, "trace", fmt, __VA_ARGS__);
|
||||
#elif defined(HX_ANDROID) && !defined(HXCPP_EXE_LINK)
|
||||
#define PRINTF(fmt, ...) __android_log_print(ANDROID_LOG_INFO, "trace", fmt, __VA_ARGS__);
|
||||
#elif defined(WEBOS)
|
||||
#define PRINTF(fmt, ...) syslog(LOG_INFO, "trace", fmt, __VA_ARGS__);
|
||||
#else
|
||||
#define PRINTF printf
|
||||
#endif
|
||||
|
||||
void __hx_stack_set_last_exception();
|
||||
void __hx_stack_push_last_exception();
|
||||
|
||||
int _hxcpp_argc = 0;
|
||||
char **_hxcpp_argv = 0;
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
Dynamic Throw(Dynamic inDynamic)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
__hx_stack_set_last_exception();
|
||||
#endif
|
||||
throw inDynamic;
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
Dynamic Rethrow(Dynamic inDynamic)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
__hx_stack_push_last_exception();
|
||||
#endif
|
||||
throw inDynamic;
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
null NullArithmetic(const char *inErr)
|
||||
{
|
||||
Throw( String::create(inErr) );
|
||||
return null();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -------- Resources ---------------------------------------
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
//typedef std::map<std::wstring,Resource> ResourceSet;
|
||||
//static ResourceSet sgResources;
|
||||
|
||||
Resource *sgResources = 0;
|
||||
Resource *sgSecondResources = 0;
|
||||
|
||||
void RegisterResources(Resource *inResources)
|
||||
{
|
||||
if (sgResources)
|
||||
sgSecondResources = inResources;
|
||||
else
|
||||
sgResources = inResources;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using namespace hx;
|
||||
|
||||
Array<String> __hxcpp_resource_names()
|
||||
{
|
||||
Array<String> result(0,0);
|
||||
|
||||
if (sgResources)
|
||||
for(Resource *reso = sgResources; reso->mData; reso++)
|
||||
result->push( reso->mName );
|
||||
|
||||
if (sgSecondResources)
|
||||
for(Resource *reso = sgSecondResources; reso->mData; reso++)
|
||||
result->push( reso->mName );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
String __hxcpp_resource_string(String inName)
|
||||
{
|
||||
if (sgResources)
|
||||
for(Resource *reso = sgResources; reso->mData; reso++)
|
||||
{
|
||||
if (reso->mName == inName)
|
||||
#if (HXCPP_API_LEVEL > 0)
|
||||
{
|
||||
#ifdef HX_SMART_STRINGS
|
||||
const unsigned char *p = reso->mData;
|
||||
for(int i=0;i<reso->mDataLength;i++)
|
||||
if (p[i]>127)
|
||||
return String::create((const char *)p, reso->mDataLength);
|
||||
#endif
|
||||
return String((const char *) reso->mData, reso->mDataLength );
|
||||
}
|
||||
#else
|
||||
return String::create((const char *) reso->mData, reso->mDataLength );
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sgSecondResources)
|
||||
{
|
||||
for(Resource *reso = sgSecondResources; reso->mData; reso++)
|
||||
if (reso->mName == inName)
|
||||
{
|
||||
#ifdef HX_SMART_STRINGS
|
||||
const unsigned char *p = reso->mData;
|
||||
for(int i=0;i<reso->mDataLength;i++)
|
||||
if (p[i]>127)
|
||||
return _hx_utf8_to_utf16(p, reso->mDataLength,false);
|
||||
#endif
|
||||
return String((const char *) reso->mData, reso->mDataLength );
|
||||
|
||||
return String((const char *) reso->mData, reso->mDataLength );
|
||||
}
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
Array<unsigned char> __hxcpp_resource_bytes(String inName)
|
||||
{
|
||||
if (sgResources)
|
||||
for(Resource *reso = sgResources; reso->mData; reso++)
|
||||
{
|
||||
if (reso->mName == inName)
|
||||
{
|
||||
int len = reso->mDataLength;
|
||||
Array<unsigned char> result( len, 0);
|
||||
memcpy( result->GetBase() , reso->mData, len );
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (sgSecondResources)
|
||||
for(Resource *reso = sgSecondResources; reso->mData; reso++)
|
||||
{
|
||||
if (reso->mName == inName)
|
||||
{
|
||||
int len = reso->mDataLength;
|
||||
Array<unsigned char> result( len, 0);
|
||||
memcpy( result->GetBase() , reso->mData, len );
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null();
|
||||
}
|
||||
|
||||
// -- hx::Native -------
|
||||
|
||||
#if HXCPP_API_LEVEL >= 330
|
||||
extern "C" void __hxcpp_lib_main();
|
||||
namespace hx
|
||||
{
|
||||
const char *Init()
|
||||
{
|
||||
try
|
||||
{
|
||||
__hxcpp_lib_main();
|
||||
return 0;
|
||||
}
|
||||
catch(Dynamic e)
|
||||
{
|
||||
HX_TOP_OF_STACK
|
||||
return e->toString().utf8_str();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// --- System ---------------------------------------------------------------------
|
||||
|
||||
// --- Maths ---------------------------------------------------------
|
||||
static double rand_scale = 1.0 / (1<<16) / (1<<16);
|
||||
double __hxcpp_drand()
|
||||
{
|
||||
unsigned int lo = rand() & 0xfff;
|
||||
unsigned int mid = rand() & 0xfff;
|
||||
unsigned int hi = rand() & 0xff;
|
||||
double result = (lo | (mid<<12) | (hi<<24) ) * rand_scale;
|
||||
return result;
|
||||
}
|
||||
|
||||
int __hxcpp_irand(int inMax)
|
||||
{
|
||||
unsigned int lo = rand() & 0xfff;
|
||||
unsigned int mid = rand() & 0xfff;
|
||||
unsigned int hi = rand() & 0xff;
|
||||
return (lo | (mid<<12) | (hi<<24) ) % inMax;
|
||||
}
|
||||
|
||||
void __hxcpp_stdlibs_boot()
|
||||
{
|
||||
#if defined(_MSC_VER) && !defined(HX_WINRT) && !defined(KINC_CONSOLE)
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32");
|
||||
if (kernel32)
|
||||
{
|
||||
typedef BOOL (WINAPI *AttachConsoleFunc)(DWORD);
|
||||
typedef HWND (WINAPI *GetConsoleWindowFunc)(void);
|
||||
AttachConsoleFunc attach = (AttachConsoleFunc)GetProcAddress(kernel32,"AttachConsole");
|
||||
GetConsoleWindowFunc getConsole = (GetConsoleWindowFunc)GetProcAddress(kernel32,"GetConsoleWindow");
|
||||
if (attach && getConsole)
|
||||
{
|
||||
if (!attach( /*ATTACH_PARENT_PROCESS*/ (DWORD)-1 ))
|
||||
{
|
||||
//printf("Could not attach to parent console : %d\n",GetLastError());
|
||||
}
|
||||
else if (getConsole())
|
||||
{
|
||||
if (_fileno(stdout) < 0 || _get_osfhandle(fileno(stdout)) < 0)
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
if (_fileno(stderr) < 0 || _get_osfhandle(fileno(stderr)) < 0)
|
||||
freopen("CONOUT$", "w", stderr);
|
||||
if (_fileno(stdin) < 0 || _get_osfhandle(fileno(stdin)) < 0)
|
||||
freopen("CONIN$", "r", stdin);
|
||||
}
|
||||
}
|
||||
}
|
||||
//_setmode(_fileno(stdout), 0x00040000); // _O_U8TEXT
|
||||
//_setmode(_fileno(stderr), 0x00040000); // _O_U8TEXT
|
||||
//_setmode(_fileno(stdin), 0x00040000); // _O_U8TEXT
|
||||
#endif
|
||||
|
||||
// This is necessary for UTF-8 output to work correctly.
|
||||
setlocale(LC_ALL, "");
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
|
||||
// I think this does more harm than good.
|
||||
// It does not cause fread to return immediately - as perhaps desired.
|
||||
// But it does cause some new-line characters to be lost.
|
||||
//setbuf(stdin, 0);
|
||||
setbuf(stdout, 0);
|
||||
setbuf(stderr, 0);
|
||||
}
|
||||
|
||||
void __trace(Dynamic inObj, Dynamic info)
|
||||
{
|
||||
String text;
|
||||
if (inObj != null())
|
||||
text = inObj->toString();
|
||||
|
||||
|
||||
hx::strbuf convertBuf;
|
||||
if (info==null())
|
||||
{
|
||||
PRINTF("?? %s", text.raw_ptr() ? text.out_str(&convertBuf) : "null");
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *filename = Dynamic((info)->__Field(HX_CSTRING("fileName"), HX_PROP_DYNAMIC))->toString().utf8_str(0,false);
|
||||
int line = Dynamic((info)->__Field( HX_CSTRING("lineNumber") , HX_PROP_DYNAMIC))->__ToInt();
|
||||
|
||||
hx::strbuf convertBuf;
|
||||
//PRINTF("%s:%d: %s\n", filename, line, text.raw_ptr() ? text.out_str(&convertBuf) : "null");
|
||||
PRINTF("%s:%d: %s", filename, line, text.raw_ptr() ? text.out_str(&convertBuf) : "null");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __hxcpp_exit(int inExitCode)
|
||||
{
|
||||
exit(inExitCode);
|
||||
}
|
||||
|
||||
double __time_stamp()
|
||||
{
|
||||
#if defined(KINC_CONSOLE)
|
||||
return 0;
|
||||
#elif defined(HX_WINDOWS)
|
||||
static __int64 t0=0;
|
||||
static double period=0;
|
||||
__int64 now;
|
||||
|
||||
if (QueryPerformanceCounter((LARGE_INTEGER*)&now))
|
||||
{
|
||||
if (t0==0)
|
||||
{
|
||||
t0 = now;
|
||||
__int64 freq;
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
||||
if (freq!=0)
|
||||
period = 1.0/freq;
|
||||
}
|
||||
if (period!=0)
|
||||
return (now-t0)*period;
|
||||
}
|
||||
return (double)clock() / ( (double)CLOCKS_PER_SEC);
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
static double t0 = 0;
|
||||
struct timeval tv;
|
||||
if( gettimeofday(&tv,0) )
|
||||
throw Dynamic("Could not get time");
|
||||
double t = ( tv.tv_sec + ((double)tv.tv_usec) / 1000000.0 );
|
||||
if (t0==0) t0 = t;
|
||||
return t-t0;
|
||||
#else
|
||||
return (double)clock() / ( (double)CLOCKS_PER_SEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HX_WINDOWS) && !defined(HX_WINRT)
|
||||
|
||||
/*
|
||||
ISWHITE and ParseCommandLine are based on the implementation of the
|
||||
.NET Core runtime, CoreCLR, which is licensed under the MIT license:
|
||||
Copyright (c) Microsoft. All rights reserved.
|
||||
See LICENSE file in the CoreCLR project root for full license information.
|
||||
|
||||
The original source code of ParseCommandLine can be found in
|
||||
https://github.com/dotnet/coreclr/blob/master/src/vm/util.cpp
|
||||
*/
|
||||
|
||||
#define ISWHITE(x) ((x)==(' ') || (x)==('\t') || (x)==('\n') || (x)==('\r') )
|
||||
|
||||
static void ParseCommandLine(LPWSTR psrc, Array<String> &out)
|
||||
{
|
||||
unsigned int argcount = 1; // discovery of arg0 is unconditional, below
|
||||
|
||||
bool fInQuotes;
|
||||
int iSlash;
|
||||
|
||||
/* A quoted program name is handled here. The handling is much
|
||||
simpler than for other arguments. Basically, whatever lies
|
||||
between the leading double-quote and next one, or a terminal null
|
||||
character is simply accepted. Fancier handling is not required
|
||||
because the program name must be a legal NTFS/HPFS file name.
|
||||
Note that the double-quote characters are not copied, nor do they
|
||||
contribute to numchars.
|
||||
|
||||
This "simplification" is necessary for compatibility reasons even
|
||||
though it leads to mishandling of certain cases. For example,
|
||||
"c:\tests\"test.exe will result in an arg0 of c:\tests\ and an
|
||||
arg1 of test.exe. In any rational world this is incorrect, but
|
||||
we need to preserve compatibility.
|
||||
*/
|
||||
|
||||
LPWSTR pStart = psrc;
|
||||
bool skipQuote = false;
|
||||
|
||||
// Pairs of double-quotes vanish...
|
||||
while(psrc[0]=='\"' && psrc[1]=='\"')
|
||||
psrc += 2;
|
||||
|
||||
if (*psrc == '\"')
|
||||
{
|
||||
// scan from just past the first double-quote through the next
|
||||
// double-quote, or up to a null, whichever comes first
|
||||
psrc++;
|
||||
while ((*psrc!= '\"') && (*psrc != '\0'))
|
||||
{
|
||||
psrc++;
|
||||
// Pairs of double-quotes vanish...
|
||||
while(psrc[0]=='\"' && psrc[1]=='\"')
|
||||
psrc += 2;
|
||||
}
|
||||
|
||||
skipQuote = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not a quoted program name */
|
||||
|
||||
while (!ISWHITE(*psrc) && *psrc != '\0')
|
||||
psrc++;
|
||||
}
|
||||
|
||||
// We have now identified arg0 as pStart (or pStart+1 if we have a leading
|
||||
// quote) through psrc-1 inclusive
|
||||
if (skipQuote)
|
||||
pStart++;
|
||||
String arg0("");
|
||||
while (pStart < psrc)
|
||||
{
|
||||
arg0 += String::fromCharCode(*pStart);
|
||||
pStart++;
|
||||
}
|
||||
// out.Add(arg0); // the command isn't part of Sys.args()
|
||||
|
||||
// if we stopped on a double-quote when arg0 is quoted, skip over it
|
||||
if (skipQuote && *psrc == '\"')
|
||||
psrc++;
|
||||
|
||||
while ( *psrc != '\0')
|
||||
{
|
||||
LEADINGWHITE:
|
||||
|
||||
// The outofarg state.
|
||||
while (ISWHITE(*psrc))
|
||||
psrc++;
|
||||
|
||||
if (*psrc == '\0')
|
||||
break;
|
||||
else
|
||||
if (*psrc == '#')
|
||||
{
|
||||
while (*psrc != '\0' && *psrc != '\n')
|
||||
psrc++; // skip to end of line
|
||||
|
||||
goto LEADINGWHITE;
|
||||
}
|
||||
|
||||
argcount++;
|
||||
fInQuotes = FALSE;
|
||||
|
||||
String arg("");
|
||||
|
||||
while ((!ISWHITE(*psrc) || fInQuotes) && *psrc != '\0')
|
||||
{
|
||||
switch (*psrc)
|
||||
{
|
||||
case '\\':
|
||||
iSlash = 0;
|
||||
while (*psrc == '\\')
|
||||
{
|
||||
iSlash++;
|
||||
psrc++;
|
||||
}
|
||||
|
||||
if (*psrc == '\"')
|
||||
{
|
||||
for ( ; iSlash >= 2; iSlash -= 2)
|
||||
{
|
||||
arg += String("\\");
|
||||
}
|
||||
|
||||
if (iSlash & 1)
|
||||
{
|
||||
arg += String::fromCharCode(*psrc);
|
||||
psrc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fInQuotes = !fInQuotes;
|
||||
psrc++;
|
||||
}
|
||||
}
|
||||
else
|
||||
for ( ; iSlash > 0; iSlash--)
|
||||
{
|
||||
arg += String("\\");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
fInQuotes = !fInQuotes;
|
||||
psrc++;
|
||||
break;
|
||||
|
||||
default:
|
||||
arg += String::fromCharCode(*psrc);
|
||||
psrc++;
|
||||
}
|
||||
}
|
||||
|
||||
out.Add(arg);
|
||||
arg = String("");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if !defined(IPHONE) && !defined(APPLETV) && !defined(HX_APPLEWATCH)
|
||||
extern "C" {
|
||||
extern int *_NSGetArgc(void);
|
||||
extern char ***_NSGetArgv(void);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
Array<String> __get_args()
|
||||
{
|
||||
Array<String> result(0,0);
|
||||
if (_hxcpp_argc)
|
||||
{
|
||||
for(int i=1;i<_hxcpp_argc;i++)
|
||||
result->push( String::create(_hxcpp_argv[i],strlen(_hxcpp_argv[i])) );
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef HX_WINRT
|
||||
// Do nothing
|
||||
#elif defined(HX_WINDOWS)
|
||||
LPWSTR str = GetCommandLineW();
|
||||
ParseCommandLine(str, result);
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
|
||||
#if !defined(IPHONE) && !defined(APPLETV) && !defined(HX_APPLEWATCH)
|
||||
int argc = *_NSGetArgc();
|
||||
char **argv = *_NSGetArgv();
|
||||
for(int i=1;i<argc;i++)
|
||||
result->push( String::create(argv[i],strlen(argv[i])) );
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef ANDROID
|
||||
// TODO: Get from java
|
||||
#elif defined(__linux__)
|
||||
char buf[80];
|
||||
#if defined(KINC_CONSOLE) || defined(KINC_PI)
|
||||
sprintf(buf, "/proc/%d/cmdline", 0);
|
||||
#else
|
||||
sprintf(buf, "/proc/%d/cmdline", getpid());
|
||||
#endif
|
||||
FILE *cmd = fopen(buf,"rb");
|
||||
bool real_arg = 0;
|
||||
if (cmd)
|
||||
{
|
||||
hx::QuickVec<char> arg;
|
||||
|
||||
buf[0] = '\0';
|
||||
while (fread(buf, 1, 1, cmd))
|
||||
{
|
||||
if ((unsigned char)buf[0] == 0) // line terminator
|
||||
{
|
||||
if (real_arg)
|
||||
result->push( String::create(arg.mPtr, arg.mSize) );
|
||||
real_arg = true;
|
||||
arg.clear();
|
||||
}
|
||||
else
|
||||
arg.push(buf[0]);
|
||||
}
|
||||
fclose(cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void __hxcpp_print_string(const String &inV)
|
||||
{
|
||||
hx::strbuf convertBuf;
|
||||
PRINTF("%s", inV.out_str(&convertBuf) );
|
||||
}
|
||||
|
||||
void __hxcpp_println_string(const String &inV)
|
||||
{
|
||||
hx::strbuf convertBuf;
|
||||
PRINTF("%s\n", inV.out_str(&convertBuf));
|
||||
}
|
||||
|
||||
|
||||
// --- Casting/Converting ---------------------------------------------------------
|
||||
|
||||
|
||||
bool __instanceof(const Dynamic &inValue, const Dynamic &inType)
|
||||
{
|
||||
if (inValue==null())
|
||||
return false;
|
||||
if (inType==hx::Object::__SGetClass())
|
||||
return true;
|
||||
hx::Class c = inType;
|
||||
if (c==null())
|
||||
return false;
|
||||
return c->CanCast(inValue.GetPtr());
|
||||
}
|
||||
|
||||
|
||||
int __int__(double x)
|
||||
{
|
||||
#ifndef EMSCRIPTEN
|
||||
if (x < -0x7fffffff || x>0x7fffffff )
|
||||
{
|
||||
__int64 big_int = (__int64)(x);
|
||||
return big_int & 0xffffffff;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return (int)x;
|
||||
}
|
||||
|
||||
|
||||
static inline bool is_hex_string(const char *c, int len)
|
||||
{
|
||||
return (len > 2 && c[0] == '0' && (c[1] == 'x' || c[1] == 'X'))
|
||||
|| (len > 3 && (c[0] == '-' || c[0] == '+') && c[1] == '0' && (c[2] == 'x' || c[2] == 'X'));
|
||||
}
|
||||
|
||||
Dynamic __hxcpp_parse_int(const String &inString)
|
||||
{
|
||||
if (!inString.raw_ptr())
|
||||
return null();
|
||||
hx::strbuf buf;
|
||||
const char *str = inString.utf8_str(&buf);
|
||||
|
||||
// On the first non space char check to see if we've got a hex string
|
||||
while (isspace(*str)) ++str;
|
||||
bool isHex = is_hex_string(str, strlen(str));
|
||||
char *end = 0;
|
||||
long result;
|
||||
if (isHex)
|
||||
{
|
||||
bool neg = str[0] == '-';
|
||||
if (neg) str++;
|
||||
result = strtoul(str,&end,16);
|
||||
if (neg) result = -result;
|
||||
}
|
||||
else
|
||||
result = strtol(str,&end,10);
|
||||
#ifdef HX_WINDOWS
|
||||
if (str==end && !isHex)
|
||||
#else
|
||||
if (str==end)
|
||||
#endif
|
||||
return null();
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
|
||||
double __hxcpp_parse_substr_float(const String &inString,int start, int length)
|
||||
{
|
||||
if (start>=inString.length || length<1 || (start+length)>inString.length )
|
||||
return Math_obj::NaN;
|
||||
|
||||
hx::strbuf buf;
|
||||
const char *str = inString.ascii_substr(&buf,start,length);
|
||||
char *end = (char *)str;
|
||||
double result = str ? strtod(str,&end) : 0;
|
||||
|
||||
if (end==str)
|
||||
return Math_obj::NaN;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
double __hxcpp_parse_float(const String &inString)
|
||||
{
|
||||
if (!inString.raw_ptr())
|
||||
return Math_obj::NaN;
|
||||
|
||||
hx::strbuf buf;
|
||||
const char *str = inString.utf8_str(&buf);
|
||||
char *end = (char *)str;
|
||||
double result = str ? strtod(str,&end) : 0;
|
||||
|
||||
if (end==str)
|
||||
return Math_obj::NaN;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool __hxcpp_same_closure(Dynamic &inF1,Dynamic &inF2)
|
||||
{
|
||||
hx::Object *p1 = inF1.GetPtr();
|
||||
hx::Object *p2 = inF2.GetPtr();
|
||||
if (p1==0 || p2==0)
|
||||
return false;
|
||||
if ( (p1->__GetHandle() != p2->__GetHandle()))
|
||||
return false;
|
||||
return p1->__Compare(p2)==0;
|
||||
}
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
struct VarArgFunc : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdClosure };
|
||||
|
||||
VarArgFunc(Dynamic &inFunc) : mRealFunc(inFunc) {
|
||||
HX_OBJ_WB_NEW_MARKED_OBJECT(this)
|
||||
}
|
||||
|
||||
int __GetType() const { return vtFunction; }
|
||||
::String __ToString() const { return mRealFunc->__ToString() ; }
|
||||
|
||||
void __Mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(mRealFunc); }
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(mRealFunc); }
|
||||
#endif
|
||||
|
||||
void *__GetHandle() const { return mRealFunc.GetPtr(); }
|
||||
Dynamic __Run(const Array<Dynamic> &inArgs)
|
||||
{
|
||||
return mRealFunc->__run(inArgs);
|
||||
}
|
||||
|
||||
Dynamic mRealFunc;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Dynamic __hxcpp_create_var_args(Dynamic &inArrayFunc)
|
||||
{
|
||||
return Dynamic(new hx::VarArgFunc(inArrayFunc));
|
||||
}
|
||||
|
||||
// --- CFFI helpers ------------------------------------------------------------------
|
||||
|
||||
|
||||
// Field name management
|
||||
|
||||
|
||||
|
||||
static HxMutex sgFieldMapMutex;
|
||||
|
||||
typedef std::map<std::string,int> StringToField;
|
||||
|
||||
// These need to be pointers because of the unknown order of static object construction.
|
||||
String *sgFieldToString=0;
|
||||
int sgFieldToStringSize=0;
|
||||
int sgFieldToStringAlloc=0;
|
||||
StringToField *sgStringToField=0;
|
||||
|
||||
static String sgNullString;
|
||||
|
||||
|
||||
const String &__hxcpp_field_from_id( int f )
|
||||
{
|
||||
if (!sgFieldToString)
|
||||
return sgNullString;
|
||||
|
||||
return sgFieldToString[f];
|
||||
}
|
||||
|
||||
|
||||
int __hxcpp_field_to_id( const char *inFieldName )
|
||||
{
|
||||
AutoLock lock(sgFieldMapMutex);
|
||||
|
||||
if (!sgFieldToStringAlloc)
|
||||
{
|
||||
sgFieldToStringAlloc = 100;
|
||||
sgFieldToString = (String *)HxAlloc(sgFieldToStringAlloc * sizeof(String));
|
||||
|
||||
sgStringToField = new StringToField;
|
||||
}
|
||||
|
||||
std::string f(inFieldName);
|
||||
StringToField::iterator i = sgStringToField->find(f);
|
||||
if (i!=sgStringToField->end())
|
||||
return i->second;
|
||||
|
||||
int result = sgFieldToStringSize;
|
||||
(*sgStringToField)[f] = result;
|
||||
String str(inFieldName,strlen(inFieldName));
|
||||
|
||||
// Make into "const" string that will not get collected...
|
||||
str = String((char *)hx::InternalCreateConstBuffer(str.raw_ptr(),(str.length+1) * sizeof(char),true), str.length );
|
||||
|
||||
if (sgFieldToStringAlloc<=sgFieldToStringSize+1)
|
||||
{
|
||||
int oldAlloc = sgFieldToStringAlloc;
|
||||
String *oldData = sgFieldToString;
|
||||
sgFieldToStringAlloc *= 2;
|
||||
String *newData = (String *)malloc(sgFieldToStringAlloc*sizeof(String));
|
||||
if (oldAlloc)
|
||||
memcpy(newData, oldData, oldAlloc*sizeof(String));
|
||||
// Let oldData dangle to keep it thread safe, rather than require mutex on id read.
|
||||
sgFieldToString = newData;
|
||||
}
|
||||
sgFieldToString[sgFieldToStringSize++] = str;
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- haxe.Int32 ---------------------------------------------------------------------
|
||||
void __hxcpp_check_overflow(int x)
|
||||
{
|
||||
if( (((x) >> 30) & 1) != ((unsigned int)(x) >> 31) )
|
||||
throw Dynamic(HX_CSTRING("Overflow ")+x);
|
||||
}
|
||||
|
||||
// --- Memory ---------------------------------------------------------------------
|
||||
|
||||
unsigned char *__hxcpp_memory = 0;
|
||||
|
||||
void __hxcpp_memory_memset(Array<unsigned char> &inBuffer ,int pos, int len, int value)
|
||||
{
|
||||
if (pos<inBuffer->length)
|
||||
{
|
||||
if (pos+len>inBuffer->length)
|
||||
len = inBuffer->length - pos;
|
||||
if (len>0)
|
||||
memset( inBuffer->Pointer() + pos, value, len);
|
||||
}
|
||||
}
|
||||
|
||||
691
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Telemetry.cpp
Normal file
691
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Telemetry.cpp
Normal file
@ -0,0 +1,691 @@
|
||||
#include <hxcpp.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <hx/Debug.h>
|
||||
#include <hx/Thread.h>
|
||||
#include <hx/Telemetry.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
inline unsigned int __hxt_ptr_id(void* obj)
|
||||
{
|
||||
#if defined(HXCPP_M64)
|
||||
size_t h64 = (size_t)obj;
|
||||
// Note, using >> 1 since Strings can be small, down to 2 bytes, causing collisions
|
||||
return (unsigned int)(h64>>1) ^ (unsigned int)(h64>>32);
|
||||
#else
|
||||
// Note, using >> 1 since Strings can be small, down to 2 bytes, causing collisions
|
||||
return ((unsigned int)obj) >> 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct AllocStackIdMapEntry
|
||||
{
|
||||
int terminationStackId;
|
||||
std::map<int, AllocStackIdMapEntry*> children;
|
||||
};
|
||||
|
||||
|
||||
// Telemetry functionality
|
||||
class Telemetry
|
||||
{
|
||||
public:
|
||||
|
||||
Telemetry(StackContext *inStack, bool profiler_en, bool allocs_en)
|
||||
: mT0(0)
|
||||
{
|
||||
stack = inStack;
|
||||
names.push_back("1-indexed");
|
||||
namesStashed = 1;
|
||||
ignoreAllocs = allocs_en ? 0 : 1;
|
||||
allocStacksStashed = 0;
|
||||
allocStackIdNext = 0;
|
||||
allocStackIdMapRoot.terminationStackId = 0;
|
||||
gcTimer = 0;
|
||||
gcTimerTemp = 0;
|
||||
gcOverhead = 0;
|
||||
_last_obj = 0;
|
||||
|
||||
profiler_enabled = profiler_en;
|
||||
allocations_enabled = profiler_en && allocs_en;
|
||||
|
||||
samples = 0;
|
||||
allocation_data = 0;
|
||||
|
||||
// Push a blank (destroyed on first Dump)
|
||||
Stash();
|
||||
|
||||
// When a profiler exists, the profiler thread needs to exist
|
||||
gThreadMutex.Lock();
|
||||
|
||||
gThreadRefCount += 1;
|
||||
if (gThreadRefCount == 1) {
|
||||
HxCreateDetachedThread(ProfileMainLoop, 0);
|
||||
}
|
||||
|
||||
gThreadMutex.Unlock();
|
||||
}
|
||||
|
||||
~Telemetry()
|
||||
{
|
||||
gThreadMutex.Lock();
|
||||
|
||||
gThreadRefCount -= 1;
|
||||
|
||||
gThreadMutex.Unlock();
|
||||
}
|
||||
|
||||
// todo
|
||||
void attach(StackContext *ctx) { stack = ctx; }
|
||||
void detach() { }
|
||||
|
||||
void StackUpdate(StackFrame *frame);
|
||||
inline void sampleEnter(StackFrame *frame)
|
||||
{
|
||||
StackUpdate(frame);
|
||||
}
|
||||
inline void sampleExit()
|
||||
{
|
||||
StackUpdate(0);
|
||||
}
|
||||
|
||||
void HXTAllocation(void* obj, size_t inSize, const char* type=0);
|
||||
void HXTRealloc(void* old_obj, void* new_obj, int new_Size);
|
||||
|
||||
void Stash()
|
||||
{
|
||||
TelemetryFrame *stash = new TelemetryFrame();
|
||||
|
||||
IgnoreAllocs(1);
|
||||
|
||||
stash->gctime = gcTimer*1000000; // usec
|
||||
gcTimer = 0;
|
||||
|
||||
stash->gcoverhead = gcOverhead*1000000; // usec
|
||||
gcOverhead = 0;
|
||||
|
||||
alloc_mutex.Lock();
|
||||
|
||||
if (_last_obj!=0) lookup_last_object_type();
|
||||
|
||||
stash->allocation_data = allocation_data;
|
||||
stash->samples = samples;
|
||||
|
||||
samples = profiler_enabled ? new std::vector<int>() : 0;
|
||||
if (allocations_enabled) {
|
||||
allocation_data = new std::vector<int>();
|
||||
}
|
||||
|
||||
alloc_mutex.Unlock();
|
||||
|
||||
int i,size;
|
||||
stash->names = 0;
|
||||
if (profiler_enabled) {
|
||||
stash->names = new std::vector<const char*>();
|
||||
size = names.size();
|
||||
for (i=namesStashed; i<size; i++) {
|
||||
stash->names->push_back(names.at(i));
|
||||
}
|
||||
//printf("Stash pushed %d names, %d\n", (size-namesStashed), stash->names->size());
|
||||
namesStashed = names.size();
|
||||
}
|
||||
|
||||
stash->stacks = 0;
|
||||
if (allocations_enabled) {
|
||||
stash->stacks = new std::vector<int>();
|
||||
size = allocStacks.size();
|
||||
for (i=allocStacksStashed; i<size; i++) {
|
||||
stash->stacks->push_back(allocStacks.at(i));
|
||||
}
|
||||
allocStacksStashed = allocStacks.size();
|
||||
}
|
||||
|
||||
gStashMutex.Lock();
|
||||
stashed.push_back(*stash);
|
||||
gStashMutex.Unlock();
|
||||
|
||||
IgnoreAllocs(-1);
|
||||
}
|
||||
|
||||
TelemetryFrame* Dump()
|
||||
{
|
||||
gStashMutex.Lock();
|
||||
if (stashed.size()<1) {
|
||||
gStashMutex.Unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Destroy item that was dumped last call
|
||||
TelemetryFrame *front = &stashed.front();
|
||||
if (front->samples!=0) delete front->samples;
|
||||
if (front->names!=0) delete front->names;
|
||||
if (front->allocation_data!=0) delete front->allocation_data;
|
||||
if (front->stacks!=0) delete front->stacks;
|
||||
//delete front; // delete happens via pop_front:
|
||||
stashed.pop_front(); // Destroy item that was Dumped last call
|
||||
|
||||
front = &stashed.front();
|
||||
gStashMutex.Unlock();
|
||||
|
||||
//printf(" -- dumped stash, allocs=%d, alloc[max]=%d\n", front->allocations->size(), front->allocations->size()>0 ? front->allocations->at(front->allocations->size()-1) : 0);
|
||||
|
||||
return front;
|
||||
}
|
||||
|
||||
void IgnoreAllocs(int delta)
|
||||
{
|
||||
ignoreAllocs += delta;
|
||||
}
|
||||
|
||||
void GCStart()
|
||||
{
|
||||
gcTimerTemp = __hxcpp_time_stamp();
|
||||
}
|
||||
|
||||
void GCEnd()
|
||||
{
|
||||
gcTimer += __hxcpp_time_stamp() - gcTimerTemp;
|
||||
}
|
||||
|
||||
void lookup_last_object_type()
|
||||
{
|
||||
if (_last_obj==0) return;
|
||||
|
||||
const char* type = "_uninitialized";
|
||||
|
||||
int obj_id = __hxt_ptr_id(_last_obj);
|
||||
alloc_mutex.Lock();
|
||||
std::map<void*, hx::Telemetry*>::iterator exist = alloc_map.find(_last_obj);
|
||||
if (exist != alloc_map.end() && _last_obj!=(NULL)) {
|
||||
type = "_unknown";
|
||||
int vtt = _last_obj->__GetType();
|
||||
if (vtt==vtInt || vtt==vtFloat || vtt==vtBool) type = "_non_class";
|
||||
else if (vtt==vtObject ||
|
||||
vtt==vtString ||
|
||||
vtt==vtArray ||
|
||||
vtt==vtClass ||
|
||||
vtt==vtFunction ||
|
||||
vtt==vtEnum ||
|
||||
vtt==vtAbstractBase) {
|
||||
//printf("About to resolve...\n");
|
||||
type = _last_obj->__GetClass()->mName; //__CStr();
|
||||
//printf("Updating last allocation %016lx type to %s\n", _last_obj, type);
|
||||
}
|
||||
}
|
||||
alloc_mutex.Unlock();
|
||||
allocation_data->at(_last_loc+2) = GetNameIdx(type);
|
||||
_last_obj = 0;
|
||||
}
|
||||
|
||||
void reclaim(int id)
|
||||
{
|
||||
if (!allocations_enabled) return;
|
||||
|
||||
allocation_data->push_back(1); // collect flag
|
||||
allocation_data->push_back(id);
|
||||
}
|
||||
|
||||
static void HXTReclaimInternal(void* obj)
|
||||
{
|
||||
int obj_id = __hxt_ptr_id(obj);
|
||||
std::map<void*, hx::Telemetry*>::iterator exist = alloc_map.find(obj);
|
||||
if (exist != alloc_map.end()) {
|
||||
Telemetry* telemetry = exist->second;
|
||||
if (telemetry) {
|
||||
telemetry->reclaim(obj_id);
|
||||
alloc_map.erase(exist);
|
||||
//printf("Tracking collection %016lx, id=%016lx\n", obj, obj_id);
|
||||
} else {
|
||||
printf("HXT ERR: we shouldn't get: Telemetry lookup failed!\n");
|
||||
}
|
||||
} else {
|
||||
// Ignore, assume object was already reclaimed
|
||||
//printf("HXT ERR: we shouldn't get: Reclaim a non-tracked object %016lx, id=%016lx -- was there an object ID collision?\n", obj, obj_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void HXTAfterMark(int gByteMarkID, int ENDIAN_MARK_ID_BYTE)
|
||||
{
|
||||
double t0 = __hxcpp_time_stamp();
|
||||
|
||||
Telemetry* telemetry = 0;
|
||||
alloc_mutex.Lock();
|
||||
std::map<void*, hx::Telemetry*>::iterator iter = alloc_map.begin();
|
||||
while (iter != alloc_map.end()) {
|
||||
void* obj = iter->first;
|
||||
unsigned char mark = ((unsigned char *)obj)[ENDIAN_MARK_ID_BYTE];
|
||||
if ( mark!=gByteMarkID ) {
|
||||
// not marked, deallocated
|
||||
telemetry = iter->second;
|
||||
if (telemetry) {
|
||||
int obj_id = __hxt_ptr_id(obj);
|
||||
telemetry->reclaim(obj_id);
|
||||
}
|
||||
alloc_map.erase(iter++);
|
||||
} else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
alloc_mutex.Unlock();
|
||||
|
||||
// Report overhead on one of the telemetry instances
|
||||
// TODO: something better?
|
||||
if (telemetry) {
|
||||
telemetry->gcOverhead += __hxcpp_time_stamp() - t0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void push_callstack_ids_into(std::vector<int> *list);
|
||||
int GetNameIdx(const char *fullName);
|
||||
int ComputeCallStackId();
|
||||
|
||||
static THREAD_FUNC_TYPE ProfileMainLoop(void *)
|
||||
{
|
||||
int millis = 1;
|
||||
|
||||
while (gThreadRefCount > 0) {
|
||||
#ifdef HX_WINDOWS
|
||||
Sleep(millis);
|
||||
#else
|
||||
struct timespec t;
|
||||
struct timespec tmp;
|
||||
t.tv_sec = 0;
|
||||
t.tv_nsec = millis * 1000000;
|
||||
nanosleep(&t, &tmp);
|
||||
#endif
|
||||
|
||||
int count = gProfileClock + 1;
|
||||
gProfileClock = (count < 0) ? 0 : count;
|
||||
}
|
||||
|
||||
THREAD_FUNC_RET
|
||||
}
|
||||
|
||||
StackContext *stack;
|
||||
int mT0;
|
||||
|
||||
std::list<TelemetryFrame> stashed;
|
||||
|
||||
std::map<const char *, int> nameMap;
|
||||
std::vector<const char *> names;
|
||||
std::vector<int> *samples;
|
||||
int namesStashed;
|
||||
|
||||
bool profiler_enabled;
|
||||
bool allocations_enabled;
|
||||
|
||||
std::vector<int> allocStacks;
|
||||
int allocStacksStashed;
|
||||
int allocStackIdNext;
|
||||
AllocStackIdMapEntry allocStackIdMapRoot;
|
||||
|
||||
double gcTimer;
|
||||
double gcTimerTemp;
|
||||
double gcOverhead;
|
||||
|
||||
int ignoreAllocs;
|
||||
|
||||
hx::Object* _last_obj;
|
||||
int _last_loc;
|
||||
|
||||
std::vector<int> *allocation_data;
|
||||
|
||||
static HxMutex gStashMutex;
|
||||
static HxMutex gThreadMutex;
|
||||
static int gThreadRefCount;
|
||||
static int gProfileClock;
|
||||
|
||||
static HxMutex alloc_mutex;
|
||||
static std::map<void*, Telemetry*> alloc_map;
|
||||
};
|
||||
/* static */ HxMutex Telemetry::gStashMutex;
|
||||
/* static */ HxMutex Telemetry::gThreadMutex;
|
||||
/* static */ int Telemetry::gThreadRefCount;
|
||||
/* static */ int Telemetry::gProfileClock;
|
||||
/* static */ HxMutex Telemetry::alloc_mutex;
|
||||
/* static */ std::map<void*, Telemetry*> Telemetry::alloc_map;
|
||||
|
||||
|
||||
|
||||
Telemetry *tlmCreate(StackContext *inStack)
|
||||
{
|
||||
return new Telemetry(inStack, true, false);
|
||||
}
|
||||
|
||||
void tlmDestroy(Telemetry *inTelemetry)
|
||||
{
|
||||
delete inTelemetry;
|
||||
}
|
||||
|
||||
void tlmAttach(Telemetry *inTelemetry, StackContext *inStack)
|
||||
{
|
||||
inTelemetry->attach(inStack);
|
||||
}
|
||||
|
||||
void tlmDetach(Telemetry *inTelemetry)
|
||||
{
|
||||
inTelemetry->detach();
|
||||
}
|
||||
|
||||
void tlmSampleEnter(Telemetry *inTelemetry, StackFrame *inFrame)
|
||||
{
|
||||
inTelemetry->sampleEnter(inFrame);
|
||||
}
|
||||
|
||||
void tlmSampleExit(Telemetry *inTelemetry)
|
||||
{
|
||||
inTelemetry->sampleExit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void hx::Telemetry::push_callstack_ids_into(std::vector<int> *list)
|
||||
{
|
||||
int size = stack->getDepth();
|
||||
for (int i = 0; i < size; i++) {
|
||||
const char *fullName = stack->getFullNameAtDepth(i);
|
||||
list->push_back(GetNameIdx(fullName));
|
||||
}
|
||||
}
|
||||
|
||||
int hx::Telemetry::GetNameIdx(const char *fullName) {
|
||||
int idx = nameMap[fullName];
|
||||
if (idx==0) {
|
||||
idx = names.size();
|
||||
nameMap[fullName] = idx;
|
||||
names.push_back(fullName);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
int hx::Telemetry::ComputeCallStackId() {
|
||||
std::vector<int> callstack;
|
||||
int stackId;
|
||||
|
||||
push_callstack_ids_into(&callstack);
|
||||
int size = callstack.size();
|
||||
|
||||
AllocStackIdMapEntry *asime = &allocStackIdMapRoot;
|
||||
|
||||
int i=0;
|
||||
while (i<size) {
|
||||
int name_id = callstack.at(i++);
|
||||
//printf("Finding child with id=%d, asime now %#010x\n", name_id, asime);
|
||||
std::map<int, AllocStackIdMapEntry*>::iterator lb = asime->children.lower_bound(name_id);
|
||||
|
||||
if (lb != asime->children.end() && !(asime->children.key_comp()(name_id, lb->first)))
|
||||
{ // key already exists
|
||||
asime = lb->second;
|
||||
} else {
|
||||
// the key does not exist in the map, add it
|
||||
AllocStackIdMapEntry *newEntry = new AllocStackIdMapEntry();
|
||||
newEntry->terminationStackId = -1;
|
||||
asime->children.insert(lb, std::map<int, AllocStackIdMapEntry*>::value_type(name_id, newEntry));
|
||||
asime = newEntry;
|
||||
}
|
||||
}
|
||||
|
||||
if (asime->terminationStackId == -1) {
|
||||
// This is a new stackId, store call stack id's in allocStacks
|
||||
stackId = asime->terminationStackId = allocStackIdNext;
|
||||
allocStacks.push_back(size);
|
||||
int i = size-1;
|
||||
while (i>=0) allocStacks.push_back(callstack.at(i--));
|
||||
//printf("new callstackid %d\n", allocStackIdNext);
|
||||
allocStackIdNext++;
|
||||
} else {
|
||||
stackId = asime->terminationStackId;
|
||||
//printf("existing callstackid %d\n", stackId);
|
||||
}
|
||||
|
||||
return stackId;
|
||||
}
|
||||
|
||||
void hx::Telemetry::StackUpdate(StackFrame *pushed_frame)
|
||||
{
|
||||
if (mT0 == gProfileClock || !profiler_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Latch the profile clock and calculate the time since the last profile
|
||||
// clock tick
|
||||
int clock = gProfileClock;
|
||||
int delta = clock - mT0;
|
||||
if (delta < 0) {
|
||||
delta = 1;
|
||||
}
|
||||
mT0 = clock;
|
||||
|
||||
int size = stack->getDepth();
|
||||
|
||||
// Collect function names and callstacks (as indexes into the names vector)
|
||||
samples->push_back(size);
|
||||
push_callstack_ids_into(samples);
|
||||
samples->push_back(delta);
|
||||
}
|
||||
|
||||
void hx::Telemetry::HXTAllocation(void* obj, size_t inSize, const char* type)
|
||||
{
|
||||
if (ignoreAllocs>0 || !allocations_enabled) return;
|
||||
|
||||
// Optionally ignore from extern::cffi - very expensive to track allocs
|
||||
// for every external call, hashes for every SDL event (Lime's
|
||||
// ExternalInterface.external_handler()), etc
|
||||
#ifndef HXCPP_PROFILE_EXTERNS
|
||||
if (stack->getCurrentStackFrame()->position->className==hx::EXTERN_CLASS_NAME) {
|
||||
alloc_mutex.Unlock();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int obj_id = __hxt_ptr_id(obj);
|
||||
|
||||
alloc_mutex.Lock();
|
||||
|
||||
// HXT debug: Check for id collision
|
||||
#ifdef HXCPP_TELEMETRY_DEBUG
|
||||
std::map<void*, hx::Telemetry*>::iterator exist = alloc_map.find(obj);
|
||||
if (exist != alloc_map.end()) {
|
||||
printf("HXT ERR: Object id collision! at on %016lx, id=%016lx\n", obj, obj_id);
|
||||
throw "uh oh";
|
||||
alloc_mutex.Unlock();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int stackid = ComputeCallStackId();
|
||||
|
||||
if (_last_obj!=0) lookup_last_object_type();
|
||||
if (type==0) {
|
||||
_last_obj = (hx::Object*)obj;
|
||||
_last_loc = allocation_data->size();
|
||||
type = "_unresolved";
|
||||
}
|
||||
|
||||
allocation_data->push_back(0); // alloc flag
|
||||
allocation_data->push_back(obj_id);
|
||||
allocation_data->push_back(GetNameIdx(type)); // defer lookup
|
||||
allocation_data->push_back((int)inSize);
|
||||
allocation_data->push_back(stackid);
|
||||
|
||||
alloc_map[obj] = this;
|
||||
|
||||
//__hxcpp_set_hxt_finalizer(obj, (void*)Telemetry::HXTReclaim);
|
||||
|
||||
//printf("Tracking alloc %s at %016lx, id=%016lx, s=%d for telemetry %016lx, ts=%f\n", type, obj, obj_id, inSize, this, __hxcpp_time_stamp());
|
||||
|
||||
alloc_mutex.Unlock();
|
||||
}
|
||||
|
||||
void hx::Telemetry::HXTRealloc(void* old_obj, void* new_obj, int new_size)
|
||||
{
|
||||
if (!allocations_enabled) return;
|
||||
int old_obj_id = __hxt_ptr_id(old_obj);
|
||||
int new_obj_id = __hxt_ptr_id(new_obj);
|
||||
|
||||
alloc_mutex.Lock();
|
||||
|
||||
// Only track reallocations of objects currently known to be allocated
|
||||
std::map<void*, hx::Telemetry*>::iterator exist = alloc_map.find(old_obj);
|
||||
if (exist != alloc_map.end()) {
|
||||
Telemetry* t = exist->second;
|
||||
t->allocation_data->push_back(2); // realloc flag (necessary?)
|
||||
t->allocation_data->push_back(old_obj_id);
|
||||
t->allocation_data->push_back(new_obj_id);
|
||||
t->allocation_data->push_back(new_size);
|
||||
|
||||
//printf("Object at %016lx moving to %016lx, new_size = %d bytes\n", old_obj, new_obj, new_size);
|
||||
|
||||
// HXT debug: Check for id collision
|
||||
#ifdef HXCPP_TELEMETRY_DEBUG
|
||||
std::map<void*, hx::Telemetry*>::iterator exist_new = alloc_map.find(new_obj);
|
||||
if (exist_new != alloc_map.end()) {
|
||||
printf("HXT ERR: Object id collision (reloc)! at on %016lx, id=%016lx\n", (unsigned long)new_obj, (unsigned long)new_obj_id);
|
||||
throw "uh oh";
|
||||
}
|
||||
#endif
|
||||
|
||||
//__hxcpp_set_hxt_finalizer(old_obj, (void*)0); // remove old finalizer -- should GCInternal.InternalRealloc do this?
|
||||
HXTReclaimInternal(old_obj); // count old as reclaimed
|
||||
} else {
|
||||
//printf("Not tracking re-alloc of untracked %016lx, id=%016lx\n", old_obj, old_obj_id);
|
||||
alloc_mutex.Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
alloc_map[new_obj] = this;
|
||||
//__hxcpp_set_hxt_finalizer(new_obj, (void*)HXTReclaim);
|
||||
|
||||
//printf("Tracking re-alloc from %016lx, id=%016lx to %016lx, id=%016lx at %f\n", old_obj, old_obj_id, new_obj, new_obj_id, __hxcpp_time_stamp());
|
||||
|
||||
alloc_mutex.Unlock();
|
||||
}
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
// These globals are called by HXTelemetry.hx
|
||||
|
||||
int __hxcpp_hxt_start_telemetry(bool profiler, bool allocations)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
delete stack->mTelemetry;
|
||||
stack->mTelemetry = new hx::Telemetry(stack, profiler, allocations);
|
||||
return stack->mThreadId;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __hxcpp_hxt_stash_telemetry()
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
// Operates on the current thread, no mutexes needed
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->Stash();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Operates on the socket writer thread
|
||||
TelemetryFrame* __hxcpp_hxt_dump_telemetry(int thread_num)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getStackForId(thread_num);
|
||||
if (!stack || !stack->mTelemetry)
|
||||
return 0;
|
||||
return stack->mTelemetry->Dump();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __hxcpp_hxt_ignore_allocs(int delta)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->IgnoreAllocs(delta);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// These globals are called by other cpp files
|
||||
|
||||
|
||||
|
||||
|
||||
void __hxt_new_string(void* obj, int inSize)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTAllocation(obj, inSize, (const char *)"String");
|
||||
#endif
|
||||
}
|
||||
void __hxt_new_array(void* obj, int inSize)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTAllocation(obj, inSize, (const char *)"Array");
|
||||
#endif
|
||||
}
|
||||
void __hxt_new_hash(void* obj, int inSize)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTAllocation(obj, inSize, (const char *)"Hash");
|
||||
#endif
|
||||
}
|
||||
void __hxt_gc_new(hx::StackContext *stack, void* obj, int inSize, const char* name)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTAllocation(obj, inSize, name);
|
||||
#endif
|
||||
}
|
||||
void __hxt_gc_realloc(void* old_obj, void* new_obj, int new_size)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTRealloc(old_obj, new_obj, new_size);
|
||||
#endif
|
||||
}
|
||||
void __hxt_gc_start()
|
||||
{
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->GCStart();
|
||||
}
|
||||
void __hxt_gc_end()
|
||||
{
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->GCEnd();
|
||||
}
|
||||
|
||||
void __hxt_gc_after_mark(int gByteMarkID, int ENDIAN_MARK_ID_BYTE)
|
||||
{
|
||||
hx::Telemetry::HXTAfterMark(gByteMarkID, ENDIAN_MARK_ID_BYTE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
956
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Thread.cpp
Normal file
956
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Thread.cpp
Normal file
@ -0,0 +1,956 @@
|
||||
#include <hxcpp.h>
|
||||
|
||||
#include <hx/Thread.h>
|
||||
|
||||
#include <kinc/system.h>
|
||||
|
||||
#ifdef HX_WINDOWS
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#ifndef HX_WINDOWS
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
DECLARE_TLS_DATA(class hxThreadInfo, tlsCurrentThread);
|
||||
|
||||
// g_threadInfoMutex allows atomic access to g_nextThreadNumber
|
||||
static HxMutex g_threadInfoMutex;
|
||||
// Thread number 0 is reserved for the main thread
|
||||
static int g_nextThreadNumber = 1;
|
||||
|
||||
|
||||
// How to manage hxThreadInfo references for non haxe threads (main, extenal)?
|
||||
// HXCPP_THREAD_INFO_PTHREAD - use pthread api
|
||||
// HXCPP_THREAD_INFO_LOCAL - use thread_local storage
|
||||
// HXCPP_THREAD_INFO_SINGLETON - use one structure for all threads. Not ideal.
|
||||
|
||||
#if __cplusplus > 199711L && !defined(__BORLANDC__)
|
||||
#define HXCPP_THREAD_INFO_LOCAL
|
||||
#elif defined (HXCPP_PTHREADS)
|
||||
#define HXCPP_THREAD_INFO_PTHREAD
|
||||
#else
|
||||
#define HXCPP_THREAD_INFO_SINGLETON
|
||||
#endif
|
||||
|
||||
|
||||
// --- Deque ----------------------------------------------------------
|
||||
|
||||
struct Deque : public Array_obj<Dynamic>
|
||||
{
|
||||
Deque() : Array_obj<Dynamic>(0,0) { }
|
||||
|
||||
static Deque *Create()
|
||||
{
|
||||
Deque *result = new Deque();
|
||||
result->mFinalizer = new hx::InternalFinalizer(result,clean);
|
||||
return result;
|
||||
}
|
||||
static void clean(hx::Object *inObj)
|
||||
{
|
||||
Deque *d = dynamic_cast<Deque *>(inObj);
|
||||
if (d) d->Clean();
|
||||
}
|
||||
void Clean()
|
||||
{
|
||||
#ifdef HX_WINDOWS
|
||||
mMutex.Clean();
|
||||
#endif
|
||||
mSemaphore.Clean();
|
||||
}
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx)
|
||||
{
|
||||
Array_obj<Dynamic>::__Visit(__inCtx);
|
||||
mFinalizer->Visit(__inCtx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HX_THREAD_SEMAPHORE_LOCKABLE
|
||||
HxMutex mMutex;
|
||||
void PushBack(Dynamic inValue)
|
||||
{
|
||||
hx::EnterGCFreeZone();
|
||||
AutoLock lock(mMutex);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
push(inValue);
|
||||
mSemaphore.Set();
|
||||
}
|
||||
void PushFront(Dynamic inValue)
|
||||
{
|
||||
hx::EnterGCFreeZone();
|
||||
AutoLock lock(mMutex);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
unshift(inValue);
|
||||
mSemaphore.Set();
|
||||
}
|
||||
|
||||
|
||||
Dynamic PopFront(bool inBlock)
|
||||
{
|
||||
hx::EnterGCFreeZone();
|
||||
AutoLock lock(mMutex);
|
||||
if (!inBlock)
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
return shift();
|
||||
}
|
||||
// Ok - wait for something on stack...
|
||||
while(!length)
|
||||
{
|
||||
mSemaphore.Reset();
|
||||
lock.Unlock();
|
||||
mSemaphore.Wait();
|
||||
lock.Lock();
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
if (length==1)
|
||||
mSemaphore.Reset();
|
||||
return shift();
|
||||
}
|
||||
#else
|
||||
void PushBack(Dynamic inValue)
|
||||
{
|
||||
hx::EnterGCFreeZone();
|
||||
AutoLock lock(mSemaphore);
|
||||
hx::ExitGCFreeZone();
|
||||
push(inValue);
|
||||
mSemaphore.QSet();
|
||||
}
|
||||
void PushFront(Dynamic inValue)
|
||||
{
|
||||
hx::EnterGCFreeZone();
|
||||
AutoLock lock(mSemaphore);
|
||||
hx::ExitGCFreeZone();
|
||||
unshift(inValue);
|
||||
mSemaphore.QSet();
|
||||
}
|
||||
|
||||
|
||||
Dynamic PopFront(bool inBlock)
|
||||
{
|
||||
hx::EnterGCFreeZone();
|
||||
AutoLock lock(mSemaphore);
|
||||
while(inBlock && !length)
|
||||
mSemaphore.QWait();
|
||||
hx::ExitGCFreeZone();
|
||||
Dynamic result = shift();
|
||||
if (length)
|
||||
mSemaphore.QSet();
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
hx::InternalFinalizer *mFinalizer;
|
||||
HxSemaphore mSemaphore;
|
||||
};
|
||||
|
||||
Dynamic __hxcpp_deque_create()
|
||||
{
|
||||
return Deque::Create();
|
||||
}
|
||||
|
||||
void __hxcpp_deque_add(Dynamic q,Dynamic inVal)
|
||||
{
|
||||
Deque *d = dynamic_cast<Deque *>(q.mPtr);
|
||||
if (!d)
|
||||
throw HX_INVALID_OBJECT;
|
||||
d->PushBack(inVal);
|
||||
}
|
||||
|
||||
void __hxcpp_deque_push(Dynamic q,Dynamic inVal)
|
||||
{
|
||||
Deque *d = dynamic_cast<Deque *>(q.mPtr);
|
||||
if (!d)
|
||||
throw HX_INVALID_OBJECT;
|
||||
d->PushFront(inVal);
|
||||
}
|
||||
|
||||
Dynamic __hxcpp_deque_pop(Dynamic q,bool block)
|
||||
{
|
||||
Deque *d = dynamic_cast<Deque *>(q.mPtr);
|
||||
if (!d)
|
||||
throw HX_INVALID_OBJECT;
|
||||
return d->PopFront(block);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --- Thread ----------------------------------------------------------
|
||||
|
||||
class hxThreadInfo : public hx::Object
|
||||
{
|
||||
public:
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdThreadInfo };
|
||||
|
||||
hxThreadInfo(Dynamic inFunction, int inThreadNumber)
|
||||
: mFunction(inFunction), mThreadNumber(inThreadNumber), mTLS(0,0)
|
||||
{
|
||||
mSemaphore = new HxSemaphore;
|
||||
mDeque = Deque::Create();
|
||||
HX_OBJ_WB_NEW_MARKED_OBJECT(this);
|
||||
}
|
||||
hxThreadInfo()
|
||||
{
|
||||
mSemaphore = 0;
|
||||
mDeque = Deque::Create();
|
||||
HX_OBJ_WB_NEW_MARKED_OBJECT(this);
|
||||
}
|
||||
int GetThreadNumber() const
|
||||
{
|
||||
return mThreadNumber;
|
||||
}
|
||||
void CleanSemaphore()
|
||||
{
|
||||
delete mSemaphore;
|
||||
mSemaphore = 0;
|
||||
}
|
||||
void Send(Dynamic inMessage)
|
||||
{
|
||||
mDeque->PushBack(inMessage);
|
||||
}
|
||||
Dynamic ReadMessage(bool inBlocked)
|
||||
{
|
||||
return mDeque->PopFront(inBlocked);
|
||||
}
|
||||
String toString()
|
||||
{
|
||||
return String(GetThreadNumber());
|
||||
}
|
||||
void SetTLS(int inID,Dynamic inVal) {
|
||||
mTLS->__SetItem(inID,inVal);
|
||||
}
|
||||
Dynamic GetTLS(int inID) { return mTLS[inID]; }
|
||||
|
||||
void __Mark(hx::MarkContext *__inCtx)
|
||||
{
|
||||
HX_MARK_MEMBER(mFunction);
|
||||
HX_MARK_MEMBER(mTLS);
|
||||
if (mDeque)
|
||||
HX_MARK_OBJECT(mDeque);
|
||||
}
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx)
|
||||
{
|
||||
HX_VISIT_MEMBER(mFunction);
|
||||
HX_VISIT_MEMBER(mTLS);
|
||||
if (mDeque)
|
||||
HX_VISIT_OBJECT(mDeque);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Array<Dynamic> mTLS;
|
||||
HxSemaphore *mSemaphore;
|
||||
Dynamic mFunction;
|
||||
int mThreadNumber;
|
||||
Deque *mDeque;
|
||||
};
|
||||
|
||||
|
||||
THREAD_FUNC_TYPE hxThreadFunc( void *inInfo )
|
||||
{
|
||||
// info[1] will the the "top of stack" - values under this
|
||||
// (ie info[0] and other stack values) will be in the GC conservative range
|
||||
hxThreadInfo *info[2];
|
||||
info[0] = (hxThreadInfo *)inInfo;
|
||||
info[1] = 0;
|
||||
|
||||
tlsCurrentThread = info[0];
|
||||
|
||||
hx::SetTopOfStack((int *)&info[1], true);
|
||||
|
||||
// Release the creation function
|
||||
info[0]->mSemaphore->Set();
|
||||
|
||||
// Call the debugger function to annouce that a thread has been created
|
||||
//__hxcpp_dbg_threadCreatedOrTerminated(info[0]->GetThreadNumber(), true);
|
||||
|
||||
if ( info[0]->mFunction.GetPtr() )
|
||||
{
|
||||
// Try ... catch
|
||||
info[0]->mFunction->__run();
|
||||
}
|
||||
|
||||
// Call the debugger function to annouce that a thread has terminated
|
||||
//__hxcpp_dbg_threadCreatedOrTerminated(info[0]->GetThreadNumber(), false);
|
||||
|
||||
hx::UnregisterCurrentThread();
|
||||
|
||||
tlsCurrentThread = 0;
|
||||
|
||||
THREAD_FUNC_RET
|
||||
}
|
||||
|
||||
#ifdef KINC_CONSOLE
|
||||
Dynamic __hxcpp_thread_create(Dynamic inStart)
|
||||
{
|
||||
return hx::Throw(HX_CSTRING("Threads are not yet supported on consoles"));
|
||||
}
|
||||
#elif defined(HX_WINRT)
|
||||
Dynamic __hxcpp_thread_create(Dynamic inStart)
|
||||
{
|
||||
return hx::Throw(HX_CSTRING("Threads are not yet supported on WinRT"));
|
||||
}
|
||||
#else
|
||||
Dynamic __hxcpp_thread_create(Dynamic inStart)
|
||||
{
|
||||
#ifdef EMSCRIPTEN
|
||||
return hx::Throw( HX_CSTRING("Threads are not supported on Emscripten") );
|
||||
#else
|
||||
g_threadInfoMutex.Lock();
|
||||
int threadNumber = g_nextThreadNumber++;
|
||||
g_threadInfoMutex.Unlock();
|
||||
|
||||
hxThreadInfo *info = new hxThreadInfo(inStart, threadNumber);
|
||||
|
||||
hx::GCPrepareMultiThreaded();
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
bool ok = HxCreateDetachedThread(hxThreadFunc, info);
|
||||
if (ok)
|
||||
{
|
||||
info->mSemaphore->Wait();
|
||||
}
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
info->CleanSemaphore();
|
||||
|
||||
if (!ok)
|
||||
throw Dynamic( HX_CSTRING("Could not create thread") );
|
||||
return info;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_THREAD_INFO_PTHREAD
|
||||
static pthread_key_t externThreadInfoKey;;
|
||||
static pthread_once_t key_once = PTHREAD_ONCE_INIT;
|
||||
static void destroyThreadInfo(void *i)
|
||||
{
|
||||
hx::Object **threadRoot = (hx::Object **)i;
|
||||
hx::GCRemoveRoot(threadRoot);
|
||||
delete threadRoot;
|
||||
}
|
||||
static void make_key()
|
||||
{
|
||||
pthread_key_create(&externThreadInfoKey, destroyThreadInfo);
|
||||
}
|
||||
#elif defined(HXCPP_THREAD_INFO_LOCAL)
|
||||
struct ThreadInfoHolder
|
||||
{
|
||||
hx::Object **threadRoot;
|
||||
ThreadInfoHolder() : threadRoot(0) { }
|
||||
~ThreadInfoHolder()
|
||||
{
|
||||
if (threadRoot)
|
||||
{
|
||||
hx::GCRemoveRoot(threadRoot);
|
||||
delete threadRoot;
|
||||
}
|
||||
}
|
||||
void set(hx::Object **info) { threadRoot = info; }
|
||||
hxThreadInfo *get() { return threadRoot ? (hxThreadInfo *)*threadRoot : nullptr; }
|
||||
|
||||
};
|
||||
static thread_local ThreadInfoHolder threadHolder;
|
||||
#else
|
||||
static hx::Object **sMainThreadInfoRoot = 0;
|
||||
#endif
|
||||
|
||||
static hxThreadInfo *GetCurrentInfo(bool createNew = true)
|
||||
{
|
||||
hxThreadInfo *info = tlsCurrentThread;
|
||||
if (!info)
|
||||
{
|
||||
#ifdef HXCPP_THREAD_INFO_PTHREAD
|
||||
pthread_once(&key_once, make_key);
|
||||
hxThreadInfo **pp = (hxThreadInfo **)pthread_getspecific(externThreadInfoKey);
|
||||
if (pp)
|
||||
info = *pp;
|
||||
#elif defined(HXCPP_THREAD_INFO_LOCAL)
|
||||
info = threadHolder.get();
|
||||
#else
|
||||
if (sMainThreadInfoRoot)
|
||||
info = (hxThreadInfo *)*sMainThreadInfoRoot;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!info && createNew)
|
||||
{
|
||||
// New, non-haxe thread - might be the first thread, or might be a new
|
||||
// foreign thread.
|
||||
info = new hxThreadInfo(null(), 0);
|
||||
hx::Object **threadRoot = new hx::Object *;
|
||||
*threadRoot = info;
|
||||
hx::GCAddRoot(threadRoot);
|
||||
#ifdef HXCPP_THREAD_INFO_PTHREAD
|
||||
pthread_setspecific(externThreadInfoKey, threadRoot);
|
||||
#elif defined(HXCPP_THREAD_INFO_LOCAL)
|
||||
threadHolder.set(threadRoot);
|
||||
#else
|
||||
sMainThreadInfoRoot = threadRoot;
|
||||
#endif
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
Dynamic __hxcpp_thread_current()
|
||||
{
|
||||
return GetCurrentInfo();
|
||||
}
|
||||
|
||||
void __hxcpp_thread_send(Dynamic inThread, Dynamic inMessage)
|
||||
{
|
||||
hxThreadInfo *info = dynamic_cast<hxThreadInfo *>(inThread.mPtr);
|
||||
if (!info)
|
||||
throw HX_INVALID_OBJECT;
|
||||
info->Send(inMessage);
|
||||
}
|
||||
|
||||
Dynamic __hxcpp_thread_read_message(bool inBlocked)
|
||||
{
|
||||
hxThreadInfo *info = GetCurrentInfo();
|
||||
return info->ReadMessage(inBlocked);
|
||||
}
|
||||
|
||||
bool __hxcpp_is_current_thread(hx::Object *inThread)
|
||||
{
|
||||
hxThreadInfo *info = tlsCurrentThread;
|
||||
return info==inThread;
|
||||
}
|
||||
|
||||
// --- TLS ------------------------------------------------------------
|
||||
|
||||
Dynamic __hxcpp_tls_get(int inID)
|
||||
{
|
||||
return GetCurrentInfo()->GetTLS(inID);
|
||||
}
|
||||
|
||||
void __hxcpp_tls_set(int inID,Dynamic inVal)
|
||||
{
|
||||
GetCurrentInfo()->SetTLS(inID,inVal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --- Mutex ------------------------------------------------------------
|
||||
|
||||
class hxMutex : public hx::Object
|
||||
{
|
||||
public:
|
||||
|
||||
hxMutex()
|
||||
{
|
||||
mFinalizer = new hx::InternalFinalizer(this);
|
||||
mFinalizer->mFinalizer = clean;
|
||||
}
|
||||
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdMutex };
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { mFinalizer->Visit(__inCtx); }
|
||||
#endif
|
||||
|
||||
hx::InternalFinalizer *mFinalizer;
|
||||
|
||||
static void clean(hx::Object *inObj)
|
||||
{
|
||||
hxMutex *m = dynamic_cast<hxMutex *>(inObj);
|
||||
if (m) m->mMutex.Clean();
|
||||
}
|
||||
bool Try()
|
||||
{
|
||||
return mMutex.TryLock();
|
||||
}
|
||||
void Acquire()
|
||||
{
|
||||
hx::EnterGCFreeZone();
|
||||
mMutex.Lock();
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
void Release()
|
||||
{
|
||||
mMutex.Unlock();
|
||||
}
|
||||
|
||||
|
||||
HxMutex mMutex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Dynamic __hxcpp_mutex_create()
|
||||
{
|
||||
return new hxMutex;
|
||||
}
|
||||
void __hxcpp_mutex_acquire(Dynamic inMutex)
|
||||
{
|
||||
hxMutex *mutex = dynamic_cast<hxMutex *>(inMutex.mPtr);
|
||||
if (!mutex)
|
||||
throw HX_INVALID_OBJECT;
|
||||
mutex->Acquire();
|
||||
}
|
||||
bool __hxcpp_mutex_try(Dynamic inMutex)
|
||||
{
|
||||
hxMutex *mutex = dynamic_cast<hxMutex *>(inMutex.mPtr);
|
||||
if (!mutex)
|
||||
throw HX_INVALID_OBJECT;
|
||||
return mutex->Try();
|
||||
}
|
||||
void __hxcpp_mutex_release(Dynamic inMutex)
|
||||
{
|
||||
hxMutex *mutex = dynamic_cast<hxMutex *>(inMutex.mPtr);
|
||||
if (!mutex)
|
||||
throw HX_INVALID_OBJECT;
|
||||
return mutex->Release();
|
||||
}
|
||||
|
||||
#if defined(HX_LINUX) || defined(HX_ANDROID)
|
||||
#define POSIX_SEMAPHORE
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
#if defined(HX_MACOS) || defined(IPHONE) || defined(APPLETV)
|
||||
#define APPLE_SEMAPHORE
|
||||
#include <dispatch/dispatch.h>
|
||||
#endif
|
||||
|
||||
class hxSemaphore : public hx::Object {
|
||||
public:
|
||||
hx::InternalFinalizer *mFinalizer;
|
||||
#ifdef HX_WINDOWS
|
||||
HANDLE sem;
|
||||
#elif defined (POSIX_SEMAPHORE)
|
||||
sem_t sem;
|
||||
#elif defined(APPLE_SEMAPHORE)
|
||||
dispatch_semaphore_t sem;
|
||||
#endif
|
||||
bool valid;
|
||||
|
||||
hxSemaphore(int value) {
|
||||
mFinalizer = new hx::InternalFinalizer(this);
|
||||
mFinalizer->mFinalizer = clean;
|
||||
#ifdef HX_WINDOWS
|
||||
sem = CreateSemaphoreW(NULL, value, 0x7FFFFFFF, NULL);
|
||||
#elif defined(POSIX_SEMAPHORE)
|
||||
sem_init(&sem, 0, value);
|
||||
#elif defined(APPLE_SEMAPHORE)
|
||||
sem = dispatch_semaphore_create(value);
|
||||
#endif
|
||||
valid = true;
|
||||
}
|
||||
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSemaphore };
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { mFinalizer->Visit(__inCtx); }
|
||||
#endif
|
||||
|
||||
void Acquire() {
|
||||
#if HX_WINDOWS
|
||||
WaitForSingleObject(sem, INFINITE);
|
||||
#elif defined(POSIX_SEMAPHORE)
|
||||
sem_wait(&sem);
|
||||
#elif defined(APPLE_SEMAPHORE)
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TryAcquire(double timeout) {
|
||||
#ifdef HX_WINDOWS
|
||||
return WaitForSingleObject(sem, (DWORD)((FLOAT)timeout * 1000.0)) == 0;
|
||||
#elif defined(POSIX_SEMAPHORE)
|
||||
if (timeout == 0) {
|
||||
return sem_trywait(&sem) == 0;
|
||||
} else {
|
||||
struct timeval tv;
|
||||
struct timespec t;
|
||||
double delta = timeout;
|
||||
int idelta = (int)delta, idelta2;
|
||||
delta -= idelta;
|
||||
delta *= 1.0e9;
|
||||
gettimeofday(&tv, NULL);
|
||||
delta += tv.tv_usec * 1000.0;
|
||||
idelta2 = (int)(delta / 1e9);
|
||||
delta -= idelta2 * 1e9;
|
||||
t.tv_sec = tv.tv_sec + idelta + idelta2;
|
||||
t.tv_nsec = (long)delta;
|
||||
return sem_timedwait(&sem, &t) == 0;
|
||||
}
|
||||
#elif defined(APPLE_SEMAPHORE)
|
||||
return dispatch_semaphore_wait(
|
||||
sem,
|
||||
dispatch_time(DISPATCH_TIME_NOW,
|
||||
(int64_t)(timeout * 1000 * 1000 * 1000))) == 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Release() {
|
||||
#if HX_WINDOWS
|
||||
ReleaseSemaphore(sem, 1, NULL);
|
||||
#elif defined(POSIX_SEMAPHORE)
|
||||
sem_post(&sem);
|
||||
#elif defined(APPLE_SEMAPHORE)
|
||||
dispatch_semaphore_signal(sem);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void clean(hx::Object *inObj) {
|
||||
hxSemaphore *l = dynamic_cast<hxSemaphore *>(inObj);
|
||||
if (l) {
|
||||
if(l->valid) {
|
||||
#ifdef HX_WINDOWS
|
||||
CloseHandle(l->sem);
|
||||
#elif defined(POSIX_SEMAPHORE)
|
||||
sem_destroy(&l->sem);
|
||||
#endif
|
||||
l->valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Dynamic __hxcpp_semaphore_create(int value) {
|
||||
return new hxSemaphore(value);
|
||||
}
|
||||
void __hxcpp_semaphore_acquire(Dynamic inSemaphore) {
|
||||
hxSemaphore *semaphore = dynamic_cast<hxSemaphore *>(inSemaphore.mPtr);
|
||||
if (!semaphore)
|
||||
throw HX_INVALID_OBJECT;
|
||||
semaphore->Acquire();
|
||||
}
|
||||
bool __hxcpp_semaphore_try_acquire(Dynamic inSemaphore, double timeout) {
|
||||
hxSemaphore *semaphore = dynamic_cast<hxSemaphore *>(inSemaphore.mPtr);
|
||||
if (!semaphore)
|
||||
throw HX_INVALID_OBJECT;
|
||||
return semaphore->TryAcquire(timeout);
|
||||
}
|
||||
void __hxcpp_semaphore_release(Dynamic inSemaphore) {
|
||||
hxSemaphore *semaphore = dynamic_cast<hxSemaphore *>(inSemaphore.mPtr);
|
||||
if (!semaphore)
|
||||
throw HX_INVALID_OBJECT;
|
||||
semaphore->Release();
|
||||
}
|
||||
|
||||
class hxCondition : public hx::Object {
|
||||
public:
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
CRITICAL_SECTION cs;
|
||||
CONDITION_VARIABLE cond;
|
||||
#endif
|
||||
#else
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
#endif
|
||||
hx::InternalFinalizer *mFinalizer;
|
||||
hxCondition() {
|
||||
mFinalizer = new hx::InternalFinalizer(this);
|
||||
mFinalizer->mFinalizer = clean;
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
InitializeCriticalSection(&cs);
|
||||
InitializeConditionVariable(&cond);
|
||||
#else
|
||||
throw Dynamic(HX_CSTRING("Condition variables are not supported on Windows XP"));
|
||||
#endif
|
||||
#else
|
||||
pthread_condattr_t cond_attr;
|
||||
pthread_condattr_init(&cond_attr);
|
||||
pthread_cond_init(&cond, &cond_attr);
|
||||
pthread_condattr_destroy(&cond_attr);
|
||||
pthread_mutexattr_t mutex_attr;
|
||||
pthread_mutexattr_init(&mutex_attr);
|
||||
pthread_mutex_init(&mutex, &mutex_attr);
|
||||
pthread_mutexattr_destroy(&mutex_attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdCondition };
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { mFinalizer->Visit(__inCtx); }
|
||||
#endif
|
||||
static void clean(hx::Object *inObj) {
|
||||
hxCondition *cond = dynamic_cast<hxCondition *>(inObj);
|
||||
if (cond) {
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
DeleteCriticalSection(&cond->cs);
|
||||
#endif
|
||||
#else
|
||||
pthread_cond_destroy(&cond->cond);
|
||||
pthread_mutex_destroy(&cond->mutex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Acquire() {
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
EnterCriticalSection(&cs);
|
||||
#endif
|
||||
#else
|
||||
pthread_mutex_lock(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TryAcquire() {
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
return (bool)TryEnterCriticalSection(&cs);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#else
|
||||
return pthread_mutex_trylock(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Release() {
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
LeaveCriticalSection(&cs);
|
||||
#endif
|
||||
#else
|
||||
pthread_mutex_unlock(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wait() {
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
SleepConditionVariableCS(&cond,&cs,INFINITE);
|
||||
#endif
|
||||
#else
|
||||
pthread_cond_wait(&cond, &mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TimedWait(double timeout) {
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
return (bool)SleepConditionVariableCS(&cond, &cs, (DWORD)((FLOAT)timeout * 1000.0));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#else
|
||||
struct timeval tv;
|
||||
struct timespec t;
|
||||
double delta = timeout;
|
||||
int idelta = (int)delta, idelta2;
|
||||
delta -= idelta;
|
||||
delta *= 1.0e9;
|
||||
gettimeofday(&tv, NULL);
|
||||
delta += tv.tv_usec * 1000.0;
|
||||
idelta2 = (int)(delta / 1e9);
|
||||
delta -= idelta2 * 1e9;
|
||||
t.tv_sec = tv.tv_sec + idelta + idelta2;
|
||||
t.tv_nsec = (long)delta;
|
||||
return pthread_cond_timedwait(&cond, &mutex, &t);
|
||||
#endif
|
||||
}
|
||||
void Signal() {
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
WakeConditionVariable(&cond);
|
||||
#endif
|
||||
#else
|
||||
pthread_cond_signal(&cond);
|
||||
#endif
|
||||
}
|
||||
void Broadcast() {
|
||||
#ifdef HX_WINDOWS
|
||||
#ifndef HXCPP_WINXP_COMPAT
|
||||
WakeAllConditionVariable(&cond);
|
||||
#endif
|
||||
#else
|
||||
pthread_cond_broadcast(&cond);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
Dynamic __hxcpp_condition_create(void) {
|
||||
return new hxCondition;
|
||||
}
|
||||
void __hxcpp_condition_acquire(Dynamic inCond) {
|
||||
hxCondition *cond = dynamic_cast<hxCondition *>(inCond.mPtr);
|
||||
if (!cond)
|
||||
throw HX_INVALID_OBJECT;
|
||||
cond->Acquire();
|
||||
}
|
||||
bool __hxcpp_condition_try_acquire(Dynamic inCond) {
|
||||
hxCondition *cond = dynamic_cast<hxCondition *>(inCond.mPtr);
|
||||
if (!cond)
|
||||
throw HX_INVALID_OBJECT;
|
||||
return cond->TryAcquire();
|
||||
}
|
||||
void __hxcpp_condition_release(Dynamic inCond) {
|
||||
hxCondition *cond = dynamic_cast<hxCondition *>(inCond.mPtr);
|
||||
if (!cond)
|
||||
throw HX_INVALID_OBJECT;
|
||||
cond->Release();
|
||||
}
|
||||
void __hxcpp_condition_wait(Dynamic inCond) {
|
||||
hxCondition *cond = dynamic_cast<hxCondition *>(inCond.mPtr);
|
||||
if (!cond)
|
||||
throw HX_INVALID_OBJECT;
|
||||
cond->Wait();
|
||||
}
|
||||
bool __hxcpp_condition_timed_wait(Dynamic inCond, double timeout) {
|
||||
hxCondition *cond = dynamic_cast<hxCondition *>(inCond.mPtr);
|
||||
if (!cond)
|
||||
throw HX_INVALID_OBJECT;
|
||||
return cond->TimedWait(timeout);
|
||||
}
|
||||
void __hxcpp_condition_signal(Dynamic inCond) {
|
||||
hxCondition *cond = dynamic_cast<hxCondition *>(inCond.mPtr);
|
||||
if (!cond)
|
||||
throw HX_INVALID_OBJECT;
|
||||
cond->Signal();
|
||||
}
|
||||
void __hxcpp_condition_broadcast(Dynamic inCond) {
|
||||
hxCondition *cond = dynamic_cast<hxCondition *>(inCond.mPtr);
|
||||
if (!cond)
|
||||
throw HX_INVALID_OBJECT;
|
||||
cond->Broadcast();
|
||||
}
|
||||
|
||||
// --- Lock ------------------------------------------------------------
|
||||
|
||||
class hxLock : public hx::Object
|
||||
{
|
||||
public:
|
||||
|
||||
hxLock()
|
||||
{
|
||||
mFinalizer = new hx::InternalFinalizer(this);
|
||||
mFinalizer->mFinalizer = clean;
|
||||
}
|
||||
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdLock };
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { mFinalizer->Visit(__inCtx); }
|
||||
#endif
|
||||
|
||||
hx::InternalFinalizer *mFinalizer;
|
||||
|
||||
double Now()
|
||||
{
|
||||
return kinc_time();
|
||||
}
|
||||
|
||||
static void clean(hx::Object *inObj)
|
||||
{
|
||||
hxLock *l = dynamic_cast<hxLock *>(inObj);
|
||||
if (l)
|
||||
{
|
||||
l->mNotEmpty.Clean();
|
||||
l->mAvailableLock.Clean();
|
||||
}
|
||||
}
|
||||
bool Wait(double inTimeout)
|
||||
{
|
||||
double stop = 0;
|
||||
if (inTimeout>=0)
|
||||
stop = Now() + inTimeout;
|
||||
while(1)
|
||||
{
|
||||
mAvailableLock.Lock();
|
||||
if (mAvailable)
|
||||
{
|
||||
--mAvailable;
|
||||
if (mAvailable>0)
|
||||
mNotEmpty.Set();
|
||||
mAvailableLock.Unlock();
|
||||
return true;
|
||||
}
|
||||
mAvailableLock.Unlock();
|
||||
double wait = 0;
|
||||
if (inTimeout>=0)
|
||||
{
|
||||
wait = stop-Now();
|
||||
if (wait<=0)
|
||||
return false;
|
||||
}
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
if (inTimeout<0)
|
||||
mNotEmpty.Wait( );
|
||||
else
|
||||
mNotEmpty.WaitSeconds(wait);
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
}
|
||||
void Release()
|
||||
{
|
||||
AutoLock lock(mAvailableLock);
|
||||
mAvailable++;
|
||||
mNotEmpty.Set();
|
||||
}
|
||||
|
||||
|
||||
HxSemaphore mNotEmpty;
|
||||
HxMutex mAvailableLock;
|
||||
int mAvailable;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Dynamic __hxcpp_lock_create()
|
||||
{
|
||||
return new hxLock;
|
||||
}
|
||||
bool __hxcpp_lock_wait(Dynamic inlock,double inTime)
|
||||
{
|
||||
hxLock *lock = dynamic_cast<hxLock *>(inlock.mPtr);
|
||||
if (!lock)
|
||||
throw HX_INVALID_OBJECT;
|
||||
return lock->Wait(inTime);
|
||||
}
|
||||
void __hxcpp_lock_release(Dynamic inlock)
|
||||
{
|
||||
hxLock *lock = dynamic_cast<hxLock *>(inlock.mPtr);
|
||||
if (!lock)
|
||||
throw HX_INVALID_OBJECT;
|
||||
lock->Release();
|
||||
}
|
||||
|
||||
|
||||
int __hxcpp_GetCurrentThreadNumber()
|
||||
{
|
||||
// Can't allow GetCurrentInfo() to create the main thread's info
|
||||
// because that can cause a call loop.
|
||||
hxThreadInfo *threadInfo = GetCurrentInfo(false);
|
||||
if (!threadInfo) {
|
||||
return 0;
|
||||
}
|
||||
return threadInfo->GetThreadNumber();
|
||||
}
|
||||
|
||||
// --- Atomic ---
|
||||
|
||||
bool _hx_atomic_exchange_if(::cpp::Pointer<cpp::AtomicInt> inPtr, int test, int newVal )
|
||||
{
|
||||
return _hx_atomic_compare_exchange(inPtr, test, newVal) == test;
|
||||
}
|
||||
|
||||
int _hx_atomic_inc(::cpp::Pointer<cpp::AtomicInt> inPtr )
|
||||
{
|
||||
return _hx_atomic_add(inPtr, 1);
|
||||
}
|
||||
|
||||
int _hx_atomic_dec(::cpp::Pointer<cpp::AtomicInt> inPtr )
|
||||
{
|
||||
return _hx_atomic_sub(inPtr, 1);
|
||||
}
|
||||
|
||||
|
||||
125
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Unicase.h
Executable file
125
Kha/Backends/Kore-hxcpp/khacpp/src/hx/Unicase.h
Executable file
@ -0,0 +1,125 @@
|
||||
#define UL_BITS 6
|
||||
#define UL_SIZE 64
|
||||
static unsigned short _E[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L1[UL_SIZE] = {0,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L3[UL_SIZE] = {224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,0,248,249,250,251,252,253,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L4[UL_SIZE] = {257,0,259,0,261,0,263,0,265,0,267,0,269,0,271,0,273,0,275,0,277,0,279,0,281,0,283,0,285,0,287,0,289,0,291,0,293,0,295,0,297,0,299,0,301,0,303,0,105,0,307,0,309,0,311,0,0,314,0,316,0,318,0,320};
|
||||
static unsigned short L5[UL_SIZE] = {0,322,0,324,0,326,0,328,0,0,331,0,333,0,335,0,337,0,339,0,341,0,343,0,345,0,347,0,349,0,351,0,353,0,355,0,357,0,359,0,361,0,363,0,365,0,367,0,369,0,371,0,373,0,375,0,255,378,0,380,0,382,0,0};
|
||||
static unsigned short L6[UL_SIZE] = {0,595,387,0,389,0,596,392,0,598,599,396,0,0,477,601,603,402,0,608,611,0,617,616,409,0,0,0,623,626,0,629,417,0,419,0,421,0,640,424,0,643,0,0,429,0,648,432,0,650,651,436,0,438,0,658,441,0,0,0,445,0,0,0};
|
||||
static unsigned short L7[UL_SIZE] = {0,0,0,0,454,454,0,457,457,0,460,460,0,462,0,464,0,466,0,468,0,470,0,472,0,474,0,476,0,0,479,0,481,0,483,0,485,0,487,0,489,0,491,0,493,0,495,0,0,499,499,0,501,0,405,447,505,0,507,0,509,0,511,0};
|
||||
static unsigned short L8[UL_SIZE] = {513,0,515,0,517,0,519,0,521,0,523,0,525,0,527,0,529,0,531,0,533,0,535,0,537,0,539,0,541,0,543,0,414,0,547,0,549,0,551,0,553,0,555,0,557,0,559,0,561,0,563,0,0,0,0,0,0,0,11365,572,0,410,11366,0};
|
||||
static unsigned short L9[UL_SIZE] = {0,578,0,384,649,652,583,0,585,0,587,0,589,0,591,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L13[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,881,0,883,0,0,0,887,0,0,0,0,0,0,0,0,1011};
|
||||
static unsigned short L14[UL_SIZE] = {0,0,0,0,0,0,940,0,941,942,943,0,972,0,973,974,0,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,0,963,964,965,966,967,968,969,970,971,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L15[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,983,0,0,0,0,0,0,0,0,985,0,987,0,989,0,991,0,993,0,995,0,997,0,999,0,1001,0,1003,0,1005,0,1007,0,0,0,0,0,952,0,0,1016,0,1010,1019,0,0,891,892,893};
|
||||
static unsigned short L16[UL_SIZE] = {1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L17[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1121,0,1123,0,1125,0,1127,0,1129,0,1131,0,1133,0,1135,0,1137,0,1139,0,1141,0,1143,0,1145,0,1147,0,1149,0,1151,0};
|
||||
static unsigned short L18[UL_SIZE] = {1153,0,0,0,0,0,0,0,0,0,1163,0,1165,0,1167,0,1169,0,1171,0,1173,0,1175,0,1177,0,1179,0,1181,0,1183,0,1185,0,1187,0,1189,0,1191,0,1193,0,1195,0,1197,0,1199,0,1201,0,1203,0,1205,0,1207,0,1209,0,1211,0,1213,0,1215,0};
|
||||
static unsigned short L19[UL_SIZE] = {1231,1218,0,1220,0,1222,0,1224,0,1226,0,1228,0,1230,0,0,1233,0,1235,0,1237,0,1239,0,1241,0,1243,0,1245,0,1247,0,1249,0,1251,0,1253,0,1255,0,1257,0,1259,0,1261,0,1263,0,1265,0,1267,0,1269,0,1271,0,1273,0,1275,0,1277,0,1279,0};
|
||||
static unsigned short L20[UL_SIZE] = {1281,0,1283,0,1285,0,1287,0,1289,0,1291,0,1293,0,1295,0,1297,0,1299,0,1301,0,1303,0,1305,0,1307,0,1309,0,1311,0,1313,0,1315,0,1317,0,1319,0,1321,0,1323,0,1325,0,1327,0,0,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391};
|
||||
static unsigned short L21[UL_SIZE] = {1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L66[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11520,11521,11522,11523,11524,11525,11526,11527,11528,11529,11530,11531,11532,11533,11534,11535,11536,11537,11538,11539,11540,11541,11542,11543,11544,11545,11546,11547,11548,11549,11550,11551};
|
||||
static unsigned short L67[UL_SIZE] = {11552,11553,11554,11555,11556,11557,0,11559,0,0,0,0,0,11565,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L78[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43888,43889,43890,43891,43892,43893,43894,43895,43896,43897,43898,43899,43900,43901,43902,43903,43904,43905,43906,43907,43908,43909,43910,43911,43912,43913,43914,43915,43916,43917,43918,43919};
|
||||
static unsigned short L79[UL_SIZE] = {43920,43921,43922,43923,43924,43925,43926,43927,43928,43929,43930,43931,43932,43933,43934,43935,43936,43937,43938,43939,43940,43941,43942,43943,43944,43945,43946,43947,43948,43949,43950,43951,43952,43953,43954,43955,43956,43957,43958,43959,43960,43961,43962,43963,43964,43965,43966,43967,5112,5113,5114,5115,5116,5117,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L120[UL_SIZE] = {7681,0,7683,0,7685,0,7687,0,7689,0,7691,0,7693,0,7695,0,7697,0,7699,0,7701,0,7703,0,7705,0,7707,0,7709,0,7711,0,7713,0,7715,0,7717,0,7719,0,7721,0,7723,0,7725,0,7727,0,7729,0,7731,0,7733,0,7735,0,7737,0,7739,0,7741,0,7743,0};
|
||||
static unsigned short L121[UL_SIZE] = {7745,0,7747,0,7749,0,7751,0,7753,0,7755,0,7757,0,7759,0,7761,0,7763,0,7765,0,7767,0,7769,0,7771,0,7773,0,7775,0,7777,0,7779,0,7781,0,7783,0,7785,0,7787,0,7789,0,7791,0,7793,0,7795,0,7797,0,7799,0,7801,0,7803,0,7805,0,7807,0};
|
||||
static unsigned short L122[UL_SIZE] = {7809,0,7811,0,7813,0,7815,0,7817,0,7819,0,7821,0,7823,0,7825,0,7827,0,7829,0,0,0,0,0,0,0,0,0,223,0,7841,0,7843,0,7845,0,7847,0,7849,0,7851,0,7853,0,7855,0,7857,0,7859,0,7861,0,7863,0,7865,0,7867,0,7869,0,7871,0};
|
||||
static unsigned short L123[UL_SIZE] = {7873,0,7875,0,7877,0,7879,0,7881,0,7883,0,7885,0,7887,0,7889,0,7891,0,7893,0,7895,0,7897,0,7899,0,7901,0,7903,0,7905,0,7907,0,7909,0,7911,0,7913,0,7915,0,7917,0,7919,0,7921,0,7923,0,7925,0,7927,0,7929,0,7931,0,7933,0,7935,0};
|
||||
static unsigned short L124[UL_SIZE] = {0,0,0,0,0,0,0,0,7936,7937,7938,7939,7940,7941,7942,7943,0,0,0,0,0,0,0,0,7952,7953,7954,7955,7956,7957,0,0,0,0,0,0,0,0,0,0,7968,7969,7970,7971,7972,7973,7974,7975,0,0,0,0,0,0,0,0,7984,7985,7986,7987,7988,7989,7990,7991};
|
||||
static unsigned short L125[UL_SIZE] = {0,0,0,0,0,0,0,0,8000,8001,8002,8003,8004,8005,0,0,0,0,0,0,0,0,0,0,0,8017,0,8019,0,8021,0,8023,0,0,0,0,0,0,0,0,8032,8033,8034,8035,8036,8037,8038,8039,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L126[UL_SIZE] = {0,0,0,0,0,0,0,0,8064,8065,8066,8067,8068,8069,8070,8071,0,0,0,0,0,0,0,0,8080,8081,8082,8083,8084,8085,8086,8087,0,0,0,0,0,0,0,0,8096,8097,8098,8099,8100,8101,8102,8103,0,0,0,0,0,0,0,0,8112,8113,8048,8049,8115,0,0,0};
|
||||
static unsigned short L127[UL_SIZE] = {0,0,0,0,0,0,0,0,8050,8051,8052,8053,8131,0,0,0,0,0,0,0,0,0,0,0,8144,8145,8054,8055,0,0,0,0,0,0,0,0,0,0,0,0,8160,8161,8058,8059,8165,0,0,0,0,0,0,0,0,0,0,0,8056,8057,8060,8061,8179,0,0,0};
|
||||
static unsigned short L132[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,969,0,0,0,107,229,0,0,0,0,0,0,8526,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L133[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8570,8571,8572,8573,8574,8575,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L134[UL_SIZE] = {0,0,0,8580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L146[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9424,9425,9426,9427,9428,9429,9430,9431,9432,9433};
|
||||
static unsigned short L147[UL_SIZE] = {9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446,9447,9448,9449,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L176[UL_SIZE] = {11312,11313,11314,11315,11316,11317,11318,11319,11320,11321,11322,11323,11324,11325,11326,11327,11328,11329,11330,11331,11332,11333,11334,11335,11336,11337,11338,11339,11340,11341,11342,11343,11344,11345,11346,11347,11348,11349,11350,11351,11352,11353,11354,11355,11356,11357,11358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L177[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11361,0,619,7549,637,0,0,11368,0,11370,0,11372,0,593,625,592,594,0,11379,0,0,11382,0,0,0,0,0,0,0,0,575,576};
|
||||
static unsigned short L178[UL_SIZE] = {11393,0,11395,0,11397,0,11399,0,11401,0,11403,0,11405,0,11407,0,11409,0,11411,0,11413,0,11415,0,11417,0,11419,0,11421,0,11423,0,11425,0,11427,0,11429,0,11431,0,11433,0,11435,0,11437,0,11439,0,11441,0,11443,0,11445,0,11447,0,11449,0,11451,0,11453,0,11455,0};
|
||||
static unsigned short L179[UL_SIZE] = {11457,0,11459,0,11461,0,11463,0,11465,0,11467,0,11469,0,11471,0,11473,0,11475,0,11477,0,11479,0,11481,0,11483,0,11485,0,11487,0,11489,0,11491,0,0,0,0,0,0,0,0,11500,0,11502,0,0,0,0,11507,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L665[UL_SIZE] = {42561,0,42563,0,42565,0,42567,0,42569,0,42571,0,42573,0,42575,0,42577,0,42579,0,42581,0,42583,0,42585,0,42587,0,42589,0,42591,0,42593,0,42595,0,42597,0,42599,0,42601,0,42603,0,42605,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L666[UL_SIZE] = {42625,0,42627,0,42629,0,42631,0,42633,0,42635,0,42637,0,42639,0,42641,0,42643,0,42645,0,42647,0,42649,0,42651,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L668[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42787,0,42789,0,42791,0,42793,0,42795,0,42797,0,42799,0,0,0,42803,0,42805,0,42807,0,42809,0,42811,0,42813,0,42815,0};
|
||||
static unsigned short L669[UL_SIZE] = {42817,0,42819,0,42821,0,42823,0,42825,0,42827,0,42829,0,42831,0,42833,0,42835,0,42837,0,42839,0,42841,0,42843,0,42845,0,42847,0,42849,0,42851,0,42853,0,42855,0,42857,0,42859,0,42861,0,42863,0,0,0,0,0,0,0,0,0,0,42874,0,42876,0,7545,42879,0};
|
||||
static unsigned short L670[UL_SIZE] = {42881,0,42883,0,42885,0,42887,0,0,0,0,42892,0,613,0,0,42897,0,42899,0,0,0,42903,0,42905,0,42907,0,42909,0,42911,0,42913,0,42915,0,42917,0,42919,0,42921,0,614,604,609,620,0,0,670,647,669,43859,42933,0,42935,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short L1020[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,0,0,0,0,0};
|
||||
static unsigned short U1[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,0,0,0,0,0};
|
||||
static unsigned short U2[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,924,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U3[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,0,216,217,218,219,220,221,222,376};
|
||||
static unsigned short U4[UL_SIZE] = {0,256,0,258,0,260,0,262,0,264,0,266,0,268,0,270,0,272,0,274,0,276,0,278,0,280,0,282,0,284,0,286,0,288,0,290,0,292,0,294,0,296,0,298,0,300,0,302,0,73,0,306,0,308,0,310,0,0,313,0,315,0,317,0};
|
||||
static unsigned short U5[UL_SIZE] = {319,0,321,0,323,0,325,0,327,0,0,330,0,332,0,334,0,336,0,338,0,340,0,342,0,344,0,346,0,348,0,350,0,352,0,354,0,356,0,358,0,360,0,362,0,364,0,366,0,368,0,370,0,372,0,374,0,0,377,0,379,0,381,83};
|
||||
static unsigned short U6[UL_SIZE] = {579,0,0,386,0,388,0,0,391,0,0,0,395,0,0,0,0,0,401,0,0,502,0,0,0,408,573,0,0,0,544,0,0,416,0,418,0,420,0,0,423,0,0,0,0,428,0,0,431,0,0,0,435,0,437,0,0,440,0,0,0,444,0,503};
|
||||
static unsigned short U7[UL_SIZE] = {0,0,0,0,453,453,453,456,456,456,459,459,459,0,461,0,463,0,465,0,467,0,469,0,471,0,473,0,475,398,0,478,0,480,0,482,0,484,0,486,0,488,0,490,0,492,0,494,0,498,498,498,0,500,0,0,0,504,0,506,0,508,0,510};
|
||||
static unsigned short U8[UL_SIZE] = {0,512,0,514,0,516,0,518,0,520,0,522,0,524,0,526,0,528,0,530,0,532,0,534,0,536,0,538,0,540,0,542,0,0,0,546,0,548,0,550,0,552,0,554,0,556,0,558,0,560,0,562,0,0,0,0,0,0,0,0,571,0,0,11390};
|
||||
static unsigned short U9[UL_SIZE] = {11391,0,577,0,0,0,0,582,0,584,0,586,0,588,0,590,11375,11373,11376,385,390,0,393,394,0,399,0,400,42923,0,0,0,403,42924,0,404,0,42893,42922,0,407,406,0,11362,42925,0,0,412,0,11374,413,0,0,415,0,0,0,0,0,0,0,11364,0,0};
|
||||
static unsigned short U10[UL_SIZE] = {422,0,0,425,0,0,0,42929,430,580,433,434,581,0,0,0,0,0,439,0,0,0,0,0,0,0,0,0,0,42930,42928,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U13[UL_SIZE] = {0,0,0,0,0,921,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0,882,0,0,0,886,0,0,0,1021,1022,1023,0,0};
|
||||
static unsigned short U14[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,902,904,905,906,0,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927};
|
||||
static unsigned short U15[UL_SIZE] = {928,929,931,931,932,933,934,935,936,937,938,939,908,910,911,0,914,920,0,0,0,934,928,975,0,984,0,986,0,988,0,990,0,992,0,994,0,996,0,998,0,1000,0,1002,0,1004,0,1006,922,929,1017,895,0,917,0,0,1015,0,0,1018,0,0,0,0};
|
||||
static unsigned short U16[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055};
|
||||
static unsigned short U17[UL_SIZE] = {1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,0,1120,0,1122,0,1124,0,1126,0,1128,0,1130,0,1132,0,1134,0,1136,0,1138,0,1140,0,1142,0,1144,0,1146,0,1148,0,1150};
|
||||
static unsigned short U18[UL_SIZE] = {0,1152,0,0,0,0,0,0,0,0,0,1162,0,1164,0,1166,0,1168,0,1170,0,1172,0,1174,0,1176,0,1178,0,1180,0,1182,0,1184,0,1186,0,1188,0,1190,0,1192,0,1194,0,1196,0,1198,0,1200,0,1202,0,1204,0,1206,0,1208,0,1210,0,1212,0,1214};
|
||||
static unsigned short U19[UL_SIZE] = {0,0,1217,0,1219,0,1221,0,1223,0,1225,0,1227,0,1229,1216,0,1232,0,1234,0,1236,0,1238,0,1240,0,1242,0,1244,0,1246,0,1248,0,1250,0,1252,0,1254,0,1256,0,1258,0,1260,0,1262,0,1264,0,1266,0,1268,0,1270,0,1272,0,1274,0,1276,0,1278};
|
||||
static unsigned short U20[UL_SIZE] = {0,1280,0,1282,0,1284,0,1286,0,1288,0,1290,0,1292,0,1294,0,1296,0,1298,0,1300,0,1302,0,1304,0,1306,0,1308,0,1310,0,1312,0,1314,0,1316,0,1318,0,1320,0,1322,0,1324,0,1326,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U21[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359};
|
||||
static unsigned short U22[UL_SIZE] = {1360,1361,1362,1363,1364,1365,1366,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U79[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5104,5105,5106,5107,5108,5109,0,0};
|
||||
static unsigned short U117[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42877,0,0,0,11363,0,0};
|
||||
static unsigned short U120[UL_SIZE] = {0,7680,0,7682,0,7684,0,7686,0,7688,0,7690,0,7692,0,7694,0,7696,0,7698,0,7700,0,7702,0,7704,0,7706,0,7708,0,7710,0,7712,0,7714,0,7716,0,7718,0,7720,0,7722,0,7724,0,7726,0,7728,0,7730,0,7732,0,7734,0,7736,0,7738,0,7740,0,7742};
|
||||
static unsigned short U121[UL_SIZE] = {0,7744,0,7746,0,7748,0,7750,0,7752,0,7754,0,7756,0,7758,0,7760,0,7762,0,7764,0,7766,0,7768,0,7770,0,7772,0,7774,0,7776,0,7778,0,7780,0,7782,0,7784,0,7786,0,7788,0,7790,0,7792,0,7794,0,7796,0,7798,0,7800,0,7802,0,7804,0,7806};
|
||||
static unsigned short U122[UL_SIZE] = {0,7808,0,7810,0,7812,0,7814,0,7816,0,7818,0,7820,0,7822,0,7824,0,7826,0,7828,0,0,0,0,0,7776,0,0,0,0,0,7840,0,7842,0,7844,0,7846,0,7848,0,7850,0,7852,0,7854,0,7856,0,7858,0,7860,0,7862,0,7864,0,7866,0,7868,0,7870};
|
||||
static unsigned short U123[UL_SIZE] = {0,7872,0,7874,0,7876,0,7878,0,7880,0,7882,0,7884,0,7886,0,7888,0,7890,0,7892,0,7894,0,7896,0,7898,0,7900,0,7902,0,7904,0,7906,0,7908,0,7910,0,7912,0,7914,0,7916,0,7918,0,7920,0,7922,0,7924,0,7926,0,7928,0,7930,0,7932,0,7934};
|
||||
static unsigned short U124[UL_SIZE] = {7944,7945,7946,7947,7948,7949,7950,7951,0,0,0,0,0,0,0,0,7960,7961,7962,7963,7964,7965,0,0,0,0,0,0,0,0,0,0,7976,7977,7978,7979,7980,7981,7982,7983,0,0,0,0,0,0,0,0,7992,7993,7994,7995,7996,7997,7998,7999,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U125[UL_SIZE] = {8008,8009,8010,8011,8012,8013,0,0,0,0,0,0,0,0,0,0,0,8025,0,8027,0,8029,0,8031,0,0,0,0,0,0,0,0,8040,8041,8042,8043,8044,8045,8046,8047,0,0,0,0,0,0,0,0,8122,8123,8136,8137,8138,8139,8154,8155,8184,8185,8170,8171,8186,8187,0,0};
|
||||
static unsigned short U126[UL_SIZE] = {8072,8073,8074,8075,8076,8077,8078,8079,0,0,0,0,0,0,0,0,8088,8089,8090,8091,8092,8093,8094,8095,0,0,0,0,0,0,0,0,8104,8105,8106,8107,8108,8109,8110,8111,0,0,0,0,0,0,0,0,8120,8121,0,8124,0,0,0,0,0,0,0,0,0,0,921,0};
|
||||
static unsigned short U127[UL_SIZE] = {0,0,0,8140,0,0,0,0,0,0,0,0,0,0,0,0,8152,8153,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8168,8169,0,0,0,8172,0,0,0,0,0,0,0,0,0,0,0,0,0,8188,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U133[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,8498,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559};
|
||||
static unsigned short U134[UL_SIZE] = {0,0,0,0,8579,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U147[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9398,9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U176[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,11274,11275,11276,11277,11278,11279};
|
||||
static unsigned short U177[UL_SIZE] = {11280,11281,11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,11310,0,0,11360,0,0,0,570,574,0,11367,0,11369,0,11371,0,0,0,0,0,0,11378,0,0,11381,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U178[UL_SIZE] = {0,11392,0,11394,0,11396,0,11398,0,11400,0,11402,0,11404,0,11406,0,11408,0,11410,0,11412,0,11414,0,11416,0,11418,0,11420,0,11422,0,11424,0,11426,0,11428,0,11430,0,11432,0,11434,0,11436,0,11438,0,11440,0,11442,0,11444,0,11446,0,11448,0,11450,0,11452,0,11454};
|
||||
static unsigned short U179[UL_SIZE] = {0,11456,0,11458,0,11460,0,11462,0,11464,0,11466,0,11468,0,11470,0,11472,0,11474,0,11476,0,11478,0,11480,0,11482,0,11484,0,11486,0,11488,0,11490,0,0,0,0,0,0,0,0,11499,0,11501,0,0,0,0,11506,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U180[UL_SIZE] = {4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,0,4295,0,0,0,0,0,4301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U665[UL_SIZE] = {0,42560,0,42562,0,42564,0,42566,0,42568,0,42570,0,42572,0,42574,0,42576,0,42578,0,42580,0,42582,0,42584,0,42586,0,42588,0,42590,0,42592,0,42594,0,42596,0,42598,0,42600,0,42602,0,42604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U666[UL_SIZE] = {0,42624,0,42626,0,42628,0,42630,0,42632,0,42634,0,42636,0,42638,0,42640,0,42642,0,42644,0,42646,0,42648,0,42650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U668[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42786,0,42788,0,42790,0,42792,0,42794,0,42796,0,42798,0,0,0,42802,0,42804,0,42806,0,42808,0,42810,0,42812,0,42814};
|
||||
static unsigned short U669[UL_SIZE] = {0,42816,0,42818,0,42820,0,42822,0,42824,0,42826,0,42828,0,42830,0,42832,0,42834,0,42836,0,42838,0,42840,0,42842,0,42844,0,42846,0,42848,0,42850,0,42852,0,42854,0,42856,0,42858,0,42860,0,42862,0,0,0,0,0,0,0,0,0,0,42873,0,42875,0,0,42878};
|
||||
static unsigned short U670[UL_SIZE] = {0,42880,0,42882,0,42884,0,42886,0,0,0,0,42891,0,0,0,0,42896,0,42898,0,0,0,42902,0,42904,0,42906,0,42908,0,42910,0,42912,0,42914,0,42916,0,42918,0,42920,0,0,0,0,0,0,0,0,0,0,0,42932,0,42934,0,0,0,0,0,0,0,0};
|
||||
static unsigned short U685[UL_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42931,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039};
|
||||
static unsigned short U686[UL_SIZE] = {5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103};
|
||||
static unsigned short U1021[UL_SIZE] = {0,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
#define LMAX 1021
|
||||
#define UMAX 1022
|
||||
static unsigned short *LOWER[LMAX] = {_E,L1,_E,L3,L4,L5,L6,L7,L8,L9,_E,_E,_E,L13,L14,L15,L16,L17,L18,L19,L20,L21,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L66,L67,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L78,L79,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L120,L121,L122,L123,L124,L125,L126,L127,_E,_E,_E,_E,L132,L133,L134,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L146,L147,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L176,L177,L178,L179,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L665,L666,_E,L668,L669,L670,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,L1020};
|
||||
static unsigned short *UPPER[UMAX] = {_E,U1,U2,U3,U4,U5,U6,U7,U8,U9,U10,_E,_E,U13,U14,U15,U16,U17,U18,U19,U20,U21,U22,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U79,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U117,_E,_E,U120,U121,U122,U123,U124,U125,U126,U127,_E,_E,_E,_E,_E,U133,U134,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U147,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U176,U177,U178,U179,U180,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U665,U666,_E,U668,U669,U670,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U685,U686,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,_E,U1021};
|
||||
|
||||
|
||||
|
||||
inline int unicase_toupper(int c)
|
||||
{
|
||||
int up = c >> UL_BITS;
|
||||
if( up < UMAX )
|
||||
{
|
||||
unsigned int c2 = UPPER[up][c&((1<<UL_BITS)-1)];
|
||||
if( c2 )
|
||||
return c2;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
inline int unicase_tolower(int c)
|
||||
{
|
||||
int up = c >> UL_BITS;
|
||||
if( up < LMAX )
|
||||
{
|
||||
unsigned int c2 = LOWER[up][c&((1<<UL_BITS)-1)];
|
||||
if( c2 )
|
||||
return c2;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
2192
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/ArrayBuiltin.cpp
Normal file
2192
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/ArrayBuiltin.cpp
Normal file
File diff suppressed because it is too large
Load Diff
972
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/ArrayVirtual.cpp
Normal file
972
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/ArrayVirtual.cpp
Normal file
@ -0,0 +1,972 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
#if (HXCPP_API_LEVEL>=330)
|
||||
#define BasePtr(x) x
|
||||
typedef cpp::VirtualArray_obj ArrayAnyImpl;
|
||||
#define CALL(x) x
|
||||
#else
|
||||
#define BasePtr(x) x.mPtr
|
||||
typedef ArrayBase ArrayAnyImpl;
|
||||
#define CALL(x) __##x
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static hx::Object * SLJIT_CALL objGetItem(hx::Object *inObj, int inIndex)
|
||||
{
|
||||
return inObj->__GetItem(inIndex).mPtr;
|
||||
}
|
||||
static int SLJIT_CALL arrayContains(ArrayAnyImpl *inObj, hx::Object *inValue)
|
||||
{
|
||||
return inObj->contains(inValue);
|
||||
}
|
||||
static int SLJIT_CALL arrayRemove(ArrayAnyImpl *inObj, hx::Object *inValue)
|
||||
{
|
||||
return inObj->remove(inValue);
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arrayConcat(ArrayAnyImpl *inObj, hx::Object *inValue)
|
||||
{
|
||||
return inObj->concat(Dynamic(inValue)).mPtr;
|
||||
}
|
||||
static void SLJIT_CALL arraySetSizeExact(ArrayAnyImpl *inObj, int inSize)
|
||||
{
|
||||
inObj->__SetSizeExact(inSize);
|
||||
}
|
||||
static void SLJIT_CALL arrayResize(ArrayAnyImpl *inObj, int inSize)
|
||||
{
|
||||
inObj->resize(inSize);
|
||||
}
|
||||
|
||||
|
||||
static hx::Object * SLJIT_CALL arraySplice(ArrayAnyImpl *inObj, hx::Object *a0, hx::Object *a1)
|
||||
{
|
||||
return inObj->splice( Dynamic(a0), Dynamic(a1) ).mPtr;
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arraySlice(ArrayAnyImpl *inObj, hx::Object *a0, hx::Object *a1)
|
||||
{
|
||||
return inObj->slice( Dynamic(a0), Dynamic(a1) ).mPtr;
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arrayPop(ArrayAnyImpl *inObj)
|
||||
{
|
||||
return inObj->pop().mPtr;
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arrayShift(ArrayAnyImpl *inObj)
|
||||
{
|
||||
return inObj->shift().mPtr;
|
||||
}
|
||||
|
||||
static void SLJIT_CALL runSort( ArrayAnyImpl *inArray, hx::Object *inFunc)
|
||||
{
|
||||
TRY_NATIVE
|
||||
inArray->sort( Dynamic(inFunc) );
|
||||
CATCH_NATIVE
|
||||
}
|
||||
static void SLJIT_CALL runReverse( ArrayAnyImpl *inArray)
|
||||
{
|
||||
inArray->reverse();
|
||||
}
|
||||
|
||||
static hx::Object * SLJIT_CALL runCopy( ArrayAnyImpl *inArray)
|
||||
{
|
||||
return (inArray->copy()).mPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SLJIT_CALL runJoin( ArrayAnyImpl *inArray, String *ioValue)
|
||||
{
|
||||
TRY_NATIVE
|
||||
*ioValue = inArray->join( *ioValue );
|
||||
CATCH_NATIVE
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int SLJIT_CALL arrayPushInt( ArrayAnyImpl *inArray, int inVal)
|
||||
{
|
||||
return inArray->push(inVal);
|
||||
}
|
||||
static int SLJIT_CALL arrayPushObject( ArrayAnyImpl *inArray, hx::Object *inVal)
|
||||
{
|
||||
return inArray->push(Dynamic(inVal));
|
||||
}
|
||||
static int SLJIT_CALL arrayPushFloat( ArrayAnyImpl *inArray, double *inVal)
|
||||
{
|
||||
return inArray->push(*inVal);
|
||||
}
|
||||
static int SLJIT_CALL arrayPushString( ArrayAnyImpl *inArray, String *inVal)
|
||||
{
|
||||
return inArray->push(*inVal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int SLJIT_CALL arraySetInt( ArrayAnyImpl *inArray, int inIndex, int inVal)
|
||||
{
|
||||
inArray->set(inIndex,inVal);
|
||||
return inVal;
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arraySetObject( ArrayAnyImpl *inArray, int inIndex, hx::Object *inVal)
|
||||
{
|
||||
inArray->set(inIndex,Dynamic(inVal));
|
||||
return inVal;
|
||||
}
|
||||
static void SLJIT_CALL arraySetFloat( ArrayAnyImpl *inArray, int inIndex, double *inVal)
|
||||
{
|
||||
inArray->set(inIndex,*inVal);
|
||||
}
|
||||
static void SLJIT_CALL arraySetString( ArrayAnyImpl *inArray, int inIndex, String *inVal)
|
||||
{
|
||||
inArray->set(inIndex,*inVal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SLJIT_CALL arrayUnshiftInt( ArrayAnyImpl *inArray, int inVal)
|
||||
{
|
||||
inArray->unshift(inVal);
|
||||
}
|
||||
static void SLJIT_CALL arrayUnshiftObject( ArrayAnyImpl *inArray, hx::Object *inVal)
|
||||
{
|
||||
inArray->unshift(Dynamic(inVal));
|
||||
}
|
||||
static void SLJIT_CALL arrayUnshiftFloat( ArrayAnyImpl *inArray, double *inVal)
|
||||
{
|
||||
inArray->unshift(*inVal);
|
||||
}
|
||||
|
||||
static void SLJIT_CALL arrayUnshiftString( ArrayAnyImpl *inArray, String *inVal)
|
||||
{
|
||||
inArray->unshift(*inVal);
|
||||
}
|
||||
|
||||
|
||||
static void SLJIT_CALL runBlit( JitMultiArg *inArgs)
|
||||
{
|
||||
// this, inDestElement, inSourceArray, inSourceElement, inElementCount
|
||||
ArrayAnyImpl *dest = (ArrayAnyImpl *)inArgs[0].obj;
|
||||
ArrayAnyImpl *src = (ArrayAnyImpl *)inArgs[2].obj;
|
||||
dest->blit( inArgs[1].ival, src, inArgs[3].ival, inArgs[4].ival );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
template<int FUNC,int OP>
|
||||
struct ArrayBuiltinAny : public ArrayBuiltinBase
|
||||
{
|
||||
|
||||
|
||||
|
||||
ArrayBuiltinAny(CppiaExpr *inSrc, CppiaExpr *inThisExpr, Expressions &ioExpressions)
|
||||
: ArrayBuiltinBase(inSrc,inThisExpr,ioExpressions)
|
||||
{
|
||||
}
|
||||
const char *getName() { return gArrayFuncNames[FUNC]; }
|
||||
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
if (FUNC==afPush)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object * val = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(push)(Dynamic(val));
|
||||
}
|
||||
if (FUNC==afContains)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object * val = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(contains)(val);
|
||||
}
|
||||
if (FUNC==afRemove)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object * val = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(remove)(val);
|
||||
}
|
||||
if (FUNC==afIndexOf)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object *a1 = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(indexOf)( a0, a1 );
|
||||
}
|
||||
if (FUNC==afLastIndexOf)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object *a1 = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(lastIndexOf)( a0, a1 );
|
||||
}
|
||||
|
||||
return Dynamic( runObject(ctx) );
|
||||
}
|
||||
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
return runInt(ctx);
|
||||
}
|
||||
|
||||
|
||||
::String runString(CppiaCtx *ctx)
|
||||
{
|
||||
if (FUNC==afJoin)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(join)( a0 );
|
||||
}
|
||||
|
||||
if (FUNC==afToString)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->toString();
|
||||
}
|
||||
|
||||
hx::Object *obj = runObject(ctx);
|
||||
return obj ? obj->toString() : ::String();
|
||||
}
|
||||
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
if (FUNC==afPush || FUNC==afContains || FUNC==afRemove || FUNC==afIndexOf || FUNC==afLastIndexOf)
|
||||
return Dynamic(runInt(ctx)).mPtr;
|
||||
|
||||
if (FUNC==afRemove)
|
||||
return Dynamic((bool)runInt(ctx)).mPtr;
|
||||
|
||||
if (FUNC==afJoin || FUNC==afToString)
|
||||
return Dynamic(runString(ctx)).mPtr;
|
||||
|
||||
if (FUNC==afSort || FUNC==afInsert || FUNC==afUnshift || FUNC==af__SetSizeExact || FUNC==afBlit)
|
||||
{
|
||||
runVoid(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
CPPIA_CHECK(thisVal);
|
||||
|
||||
if (FUNC==af__get)
|
||||
{
|
||||
int idx = args[0]->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->__GetItem(idx).mPtr;
|
||||
}
|
||||
if (FUNC==af__set)
|
||||
{
|
||||
int i = args[0]->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
if (OP==aoSet)
|
||||
{
|
||||
Dynamic val = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->__SetItem(i, val).mPtr;
|
||||
}
|
||||
|
||||
Dynamic orig = thisVal->__GetItem(i);
|
||||
CPPIA_CHECK(orig.mPtr);
|
||||
|
||||
Dynamic val = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
switch(OP)
|
||||
{
|
||||
case aoSet: break;
|
||||
|
||||
case aoAdd:
|
||||
val = orig + val;
|
||||
break;
|
||||
case aoMult:
|
||||
val = orig * val;
|
||||
break;
|
||||
case aoDiv:
|
||||
val = orig / val;
|
||||
break;
|
||||
case aoSub:
|
||||
val = orig - val;
|
||||
break;
|
||||
case aoAnd:
|
||||
val = orig->__ToInt() & val->__ToInt();
|
||||
break;
|
||||
case aoOr:
|
||||
val = orig->__ToInt() | val->__ToInt();
|
||||
break;
|
||||
case aoXOr:
|
||||
val = orig->__ToInt() ^ val->__ToInt();
|
||||
break;
|
||||
case aoShl:
|
||||
val = orig->__ToInt() << val->__ToInt();
|
||||
break;
|
||||
case aoShr:
|
||||
val = orig->__ToInt() >> val->__ToInt();
|
||||
break;
|
||||
case aoUShr:
|
||||
val = hx::UShr(orig,val);
|
||||
break;
|
||||
case aoMod:
|
||||
val = orig % val;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
return thisVal->__SetItem(i,val).mPtr;
|
||||
}
|
||||
if (FUNC==af__crement)
|
||||
{
|
||||
int i = args[0]->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
if (OP==coPreInc)
|
||||
return thisVal->__SetItem(i, thisVal->__GetItem(i) + 1).mPtr;
|
||||
if (OP==coPreDec)
|
||||
return thisVal->__SetItem(i, thisVal->__GetItem(i) - 1).mPtr;
|
||||
|
||||
Dynamic result = thisVal->__GetItem(i);
|
||||
if (OP==coPostDec)
|
||||
thisVal->__SetItem(i, thisVal->__GetItem(i) - 1);
|
||||
if (OP==coPostInc)
|
||||
thisVal->__SetItem(i, thisVal->__GetItem(i) + 1);
|
||||
return result.mPtr;
|
||||
}
|
||||
|
||||
if (FUNC==afPop)
|
||||
{
|
||||
return thisVal->CALL(pop)().mPtr;
|
||||
}
|
||||
if (FUNC==afShift)
|
||||
{
|
||||
return thisVal->CALL(shift)().mPtr;
|
||||
}
|
||||
|
||||
if (FUNC==afConcat)
|
||||
{
|
||||
Dynamic val = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(concat)(val).mPtr;
|
||||
}
|
||||
if (FUNC==afCopy)
|
||||
{
|
||||
return thisVal->CALL(copy)().mPtr;
|
||||
}
|
||||
if (FUNC==afSplice)
|
||||
{
|
||||
Dynamic pos = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic end = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(splice)(pos,end).mPtr;
|
||||
}
|
||||
if (FUNC==afSlice)
|
||||
{
|
||||
Dynamic pos = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic end = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(slice)(pos,end).mPtr;
|
||||
}
|
||||
if (FUNC==afMap)
|
||||
{
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(map)(a0).mPtr;
|
||||
}
|
||||
if (FUNC==afFilter)
|
||||
{
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(filter)(a0).mPtr;
|
||||
}
|
||||
|
||||
if (FUNC==afIterator)
|
||||
{
|
||||
return thisVal->CALL(iterator)().mPtr;
|
||||
}
|
||||
if (FUNC==afKeyValueIterator)
|
||||
{
|
||||
return thisVal->CALL(keyValueIterator)().mPtr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
void runVoid(CppiaCtx *ctx)
|
||||
{
|
||||
if (FUNC==afSort)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
|
||||
thisVal->CALL(sort)(a0);
|
||||
return;
|
||||
}
|
||||
if (FUNC==afInsert)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic pos = args[0]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic val = args[1]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
thisVal->CALL(insert)(pos, val);
|
||||
return;
|
||||
}
|
||||
if (FUNC==afUnshift)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic val = args[0]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
thisVal->CALL(unshift)(val);
|
||||
return;
|
||||
}
|
||||
if (FUNC==af__SetSizeExact)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
int size = args[0]->runInt(ctx);
|
||||
BCR_VCHECK;
|
||||
thisVal->__SetSizeExact(size);
|
||||
return;
|
||||
}
|
||||
if (FUNC==afBlit)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
int destElem = args[0]->runInt(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic srcArray = args[1]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
int srcElem = args[2]->runInt(ctx);
|
||||
BCR_VCHECK;
|
||||
int elemCount = args[3]->runInt(ctx);
|
||||
BCR_VCHECK;
|
||||
thisVal->blit(destElem, srcArray, srcElem, elemCount);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch(inlineGetType())
|
||||
{
|
||||
case etString:
|
||||
runString(ctx);
|
||||
return;
|
||||
case etInt:
|
||||
runInt(ctx);
|
||||
return;
|
||||
default:
|
||||
runObject(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
CppiaExpr *makeSetter(AssignOp op,CppiaExpr *inValue)
|
||||
{
|
||||
if (FUNC==af__get)
|
||||
{
|
||||
args.push_back(inValue);
|
||||
CppiaExpr *replace = 0;
|
||||
|
||||
switch(op)
|
||||
{
|
||||
case aoSet:
|
||||
replace = new ArrayBuiltinAny<af__set,aoSet>(this,thisExpr,args);
|
||||
break;
|
||||
case aoAdd:
|
||||
replace = new ArrayBuiltinAny<af__set,aoAdd>(this,thisExpr,args);
|
||||
break;
|
||||
case aoMult:
|
||||
replace = new ArrayBuiltinAny<af__set,aoMult>(this,thisExpr,args);
|
||||
break;
|
||||
case aoDiv:
|
||||
replace = new ArrayBuiltinAny<af__set,aoDiv>(this,thisExpr,args);
|
||||
break;
|
||||
case aoSub:
|
||||
replace = new ArrayBuiltinAny<af__set,aoSub>(this,thisExpr,args);
|
||||
break;
|
||||
case aoAnd:
|
||||
replace = new ArrayBuiltinAny<af__set,aoAnd>(this,thisExpr,args);
|
||||
break;
|
||||
case aoOr:
|
||||
replace = new ArrayBuiltinAny<af__set,aoOr>(this,thisExpr,args);
|
||||
break;
|
||||
case aoXOr:
|
||||
replace = new ArrayBuiltinAny<af__set,aoXOr>(this,thisExpr,args);
|
||||
break;
|
||||
case aoShl:
|
||||
replace = new ArrayBuiltinAny<af__set,aoShl>(this,thisExpr,args);
|
||||
break;
|
||||
case aoShr:
|
||||
replace = new ArrayBuiltinAny<af__set,aoShr>(this,thisExpr,args);
|
||||
break;
|
||||
case aoUShr:
|
||||
replace = new ArrayBuiltinAny<af__set,aoUShr>(this,thisExpr,args);
|
||||
break;
|
||||
case aoMod:
|
||||
replace = new ArrayBuiltinAny<af__set,aoMod>(this,thisExpr,args);
|
||||
break;
|
||||
|
||||
default: ;
|
||||
printf("make setter %d\n", op);
|
||||
throw "setter not implemented";
|
||||
}
|
||||
|
||||
delete this;
|
||||
return replace;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
CppiaExpr *makeCrement(CrementOp inOp)
|
||||
{
|
||||
if (FUNC==af__get)
|
||||
{
|
||||
CppiaExpr *replace = 0;
|
||||
|
||||
switch(inOp)
|
||||
{
|
||||
case coPreInc :
|
||||
replace = new ArrayBuiltinAny<af__crement,coPreInc>(this,thisExpr,args);
|
||||
break;
|
||||
case coPostInc :
|
||||
replace = new ArrayBuiltinAny<af__crement,coPostInc>(this,thisExpr,args);
|
||||
break;
|
||||
case coPreDec :
|
||||
replace = new ArrayBuiltinAny<af__crement,coPreDec>(this,thisExpr,args);
|
||||
break;
|
||||
case coPostDec :
|
||||
replace = new ArrayBuiltinAny<af__crement,coPostDec>(this,thisExpr,args);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return replace;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
inline ExprType inlineGetType()
|
||||
{
|
||||
switch(FUNC)
|
||||
{
|
||||
case afJoin:
|
||||
case afToString:
|
||||
return etString;
|
||||
|
||||
case afSort:
|
||||
case afInsert:
|
||||
case afUnshift:
|
||||
case af__SetSizeExact:
|
||||
case afBlit:
|
||||
return etVoid;
|
||||
|
||||
case afPush:
|
||||
case afContains:
|
||||
case afRemove:
|
||||
case afIndexOf:
|
||||
case afLastIndexOf:
|
||||
return etInt;
|
||||
|
||||
default:
|
||||
return etObject;
|
||||
}
|
||||
|
||||
return etObject;
|
||||
}
|
||||
ExprType getType() { return inlineGetType(); }
|
||||
|
||||
bool isBoolInt() { return FUNC==afRemove || FUNC==afContains; }
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
|
||||
static hx::Object * SLJIT_CALL runProcess( ArrayAnyImpl *inArray, hx::Object *inFunction)
|
||||
{
|
||||
TRY_NATIVE
|
||||
if (FUNC==afMap)
|
||||
{
|
||||
return inArray->map(inFunction).mPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return inArray->filter(inFunction).mPtr;
|
||||
}
|
||||
CATCH_NATIVE
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SLJIT_CALL runIndexOf( ArrayAnyImpl *inArray, hx::Object *inItem)
|
||||
{
|
||||
return inArray->indexOf(inItem);
|
||||
}
|
||||
|
||||
static int SLJIT_CALL runLastIndexOf( ArrayAnyImpl *inArray, hx::Object *inItem)
|
||||
{
|
||||
return inArray->lastIndexOf(inItem);
|
||||
}
|
||||
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest, ExprType destType)
|
||||
{
|
||||
JitTemp thisVal(compiler,etObject);
|
||||
if (FUNC!=afBlit)
|
||||
thisExpr->genCode(compiler,thisVal,etObject);
|
||||
|
||||
switch(FUNC)
|
||||
{
|
||||
case af__get:
|
||||
args[0]->genCode(compiler, sJitArg1, etInt);
|
||||
compiler->callNative( (void *)objGetItem, thisVal, sJitArg1.as(jtInt));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
break;
|
||||
|
||||
case afPop:
|
||||
compiler->callNative( (void *)arrayPop, thisVal);
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
break;
|
||||
|
||||
case afShift:
|
||||
compiler->callNative( (void *)arrayShift, thisVal);
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
break;
|
||||
|
||||
case afContains:
|
||||
args[0]->genCode(compiler, sJitArg1, etObject);
|
||||
compiler->callNative( (void *)arrayContains, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->convertReturnReg(etInt, inDest, destType,true);
|
||||
break;
|
||||
|
||||
case afRemove:
|
||||
args[0]->genCode(compiler, sJitArg1, etObject);
|
||||
compiler->callNative( (void *)arrayRemove, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->convertReturnReg(etInt, inDest, destType,true);
|
||||
break;
|
||||
|
||||
case afSplice:
|
||||
{
|
||||
JitTemp a0(compiler,etObject);
|
||||
args[0]->genCode(compiler, a0, etObject);
|
||||
args[1]->genCode(compiler, sJitArg2, etObject);
|
||||
compiler->callNative( (void *)arraySplice, thisVal, a0.as(jtPointer), sJitArg2.as(jtPointer));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
case afSlice:
|
||||
{
|
||||
JitTemp a0(compiler,etObject);
|
||||
args[0]->genCode(compiler, a0, etObject);
|
||||
args[1]->genCode(compiler, sJitArg2, etObject);
|
||||
compiler->callNative( (void *)arraySlice, thisVal, a0.as(jtPointer), sJitArg2.as(jtPointer));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
case afSort:
|
||||
{
|
||||
args[0]->genCode(compiler, sJitArg1, etObject);
|
||||
compiler->callNative( (void *)runSort, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->checkException();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case afReverse:
|
||||
compiler->callNative( (void *)runReverse, thisVal);
|
||||
break;
|
||||
|
||||
case afCopy:
|
||||
compiler->callNative( (void *)runCopy, thisVal);
|
||||
compiler->convertReturnReg(etObject, inDest, destType );
|
||||
break;
|
||||
|
||||
case afMap:
|
||||
case afFilter:
|
||||
{
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtPointer), etObject);
|
||||
|
||||
compiler->callNative( (void *)runProcess, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->checkException();
|
||||
compiler->convertReturnReg(etObject, inDest, destType );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case afIndexOf:
|
||||
case afLastIndexOf:
|
||||
{
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtPointer), etObject);
|
||||
compiler->callNative( (void *)(FUNC==afIndexOf ? runIndexOf : runLastIndexOf), thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->convertReturnReg(etInt, inDest, destType );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case afJoin:
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
args[0]->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)runJoin, thisVal, value);
|
||||
compiler->checkException();
|
||||
compiler->convert(value,etString, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case afConcat:
|
||||
{
|
||||
args[0]->genCode(compiler, sJitArg1, etObject);
|
||||
compiler->callNative( (void *)arrayConcat, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
case af__SetSizeExact:
|
||||
{
|
||||
JitTemp thisVal(compiler,jtPointer);
|
||||
thisExpr->genCode(compiler, thisVal, etObject);
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arraySetSizeExact, thisVal, sJitArg1.as(jtInt));
|
||||
break;
|
||||
}
|
||||
|
||||
case afResize:
|
||||
{
|
||||
JitTemp thisVal(compiler,jtPointer);
|
||||
thisExpr->genCode(compiler, thisVal, etObject);
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arrayResize, thisVal, sJitArg1.as(jtInt));
|
||||
break;
|
||||
}
|
||||
|
||||
case afBlit:
|
||||
{
|
||||
|
||||
// this, inDestElement, inSourceArray, inSourceElement, inElementCount
|
||||
JitMultiArgs fargs(compiler, 5);
|
||||
thisExpr->genCode(compiler, fargs.arg(0,jtPointer), etObject);
|
||||
args[0]->genCode(compiler, fargs.arg(1,jtInt), etInt);
|
||||
args[1]->genCode(compiler, fargs.arg(2,jtPointer), etObject);
|
||||
args[2]->genCode(compiler, fargs.arg(3,jtInt), etInt);
|
||||
args[3]->genCode(compiler, fargs.arg(4,jtInt), etInt);
|
||||
compiler->callNative( (void *)runBlit, fargs );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case af__set:
|
||||
{
|
||||
JitTemp index(compiler,etInt);
|
||||
args[0]->genCode(compiler, index, etInt);
|
||||
|
||||
switch(args[1]->getType())
|
||||
{
|
||||
case etInt:
|
||||
args[1]->genCode(compiler, sJitArg2.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arraySetInt, thisVal, index, sJitArg2.as(jtInt));
|
||||
compiler->convertReturnReg(etInt, inDest, destType);
|
||||
break;
|
||||
case etFloat:
|
||||
{
|
||||
JitTemp value(compiler, jtFloat);
|
||||
args[1]->genCode(compiler, value, etFloat);
|
||||
compiler->callNative( (void *)arraySetFloat, thisVal, index, value);
|
||||
compiler->convert(value,etFloat, inDest, destType);
|
||||
}
|
||||
break;
|
||||
case etString:
|
||||
{
|
||||
JitTemp value(compiler, jtString);
|
||||
args[1]->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)arraySetString, thisVal, index, value);
|
||||
compiler->convert(value,etString, inDest, destType);
|
||||
}
|
||||
break;
|
||||
case etObject:
|
||||
args[1]->genCode(compiler, sJitArg2.as(jtPointer), etObject);
|
||||
compiler->callNative( (void *)arraySetObject, thisVal, index, sJitArg2.as(jtPointer));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
break;
|
||||
default: ; //?
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case afPush:
|
||||
{
|
||||
switch(args[0]->getType())
|
||||
{
|
||||
case etInt:
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arrayPushInt, thisVal, sJitArg1.as(jtInt));
|
||||
break;
|
||||
case etFloat:
|
||||
{
|
||||
JitTemp value(compiler, jtFloat);
|
||||
args[0]->genCode(compiler, value, etFloat);
|
||||
compiler->callNative( (void *)arrayPushFloat, thisVal, value);
|
||||
}
|
||||
break;
|
||||
case etString:
|
||||
{
|
||||
JitTemp value(compiler, jtString);
|
||||
args[0]->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)arrayPushString, thisVal, value);
|
||||
}
|
||||
break;
|
||||
case etObject:
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtPointer), etObject);
|
||||
compiler->callNative( (void *)arrayPushObject, thisVal, sJitArg1.as(jtPointer));
|
||||
break;
|
||||
default: ; //?
|
||||
}
|
||||
compiler->convertReturnReg(etInt, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case afUnshift:
|
||||
{
|
||||
switch(args[0]->getType())
|
||||
{
|
||||
case etInt:
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arrayUnshiftInt, thisVal, sJitArg1.as(jtInt));
|
||||
break;
|
||||
case etFloat:
|
||||
{
|
||||
JitTemp value(compiler, jtFloat);
|
||||
args[0]->genCode(compiler, value, etFloat);
|
||||
compiler->callNative( (void *)arrayUnshiftFloat, thisVal, value);
|
||||
}
|
||||
break;
|
||||
case etString:
|
||||
{
|
||||
JitTemp value(compiler, jtString);
|
||||
args[0]->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)arrayUnshiftString, thisVal, value);
|
||||
}
|
||||
break;
|
||||
case etObject:
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtPointer), etObject);
|
||||
compiler->callNative( (void *)arrayUnshiftObject, thisVal, sJitArg1.as(jtPointer));
|
||||
break;
|
||||
default: ; //?
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
compiler->traceStrings("Unknown ArrayBuiltinAny:", getName() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<int FUNC>
|
||||
CppiaExpr *TCreateArrayAnyBuiltin(CppiaExpr *inSrc, CppiaExpr *thisExpr, Expressions &args, bool inUnsafe = false)
|
||||
{
|
||||
if (gArrayArgCount[FUNC]!=args.size())
|
||||
throw "Bad arg count for array builtin";
|
||||
|
||||
return new ArrayBuiltinAny<FUNC,(int)NoCrement::OP>(inSrc, thisExpr, args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CppiaExpr *createArrayAnyBuiltin(CppiaExpr *src, CppiaExpr *inThisExpr, String field, Expressions &ioExpressions )
|
||||
{
|
||||
if (field==HX_CSTRING("concat"))
|
||||
return TCreateArrayAnyBuiltin<afConcat>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("copy"))
|
||||
return TCreateArrayAnyBuiltin<afCopy>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("insert"))
|
||||
return TCreateArrayAnyBuiltin<afInsert>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("iterator"))
|
||||
return TCreateArrayAnyBuiltin<afIterator>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("keyValueIterator"))
|
||||
return TCreateArrayAnyBuiltin<afKeyValueIterator>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("join"))
|
||||
return TCreateArrayAnyBuiltin<afJoin>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("pop"))
|
||||
return TCreateArrayAnyBuiltin<afPop>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("push"))
|
||||
return TCreateArrayAnyBuiltin<afPush>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("contains"))
|
||||
return TCreateArrayAnyBuiltin<afContains>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("remove"))
|
||||
return TCreateArrayAnyBuiltin<afRemove>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("reverse"))
|
||||
return TCreateArrayAnyBuiltin<afReverse>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("shift"))
|
||||
return TCreateArrayAnyBuiltin<afShift>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("splice"))
|
||||
return TCreateArrayAnyBuiltin<afSplice>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("slice"))
|
||||
return TCreateArrayAnyBuiltin<afSlice>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("sort"))
|
||||
return TCreateArrayAnyBuiltin<afSort>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("toString"))
|
||||
return TCreateArrayAnyBuiltin<afToString>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("unshift"))
|
||||
return TCreateArrayAnyBuiltin<afUnshift>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("map"))
|
||||
return TCreateArrayAnyBuiltin<afMap>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("filter"))
|
||||
return TCreateArrayAnyBuiltin<afFilter>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("indexOf"))
|
||||
return TCreateArrayAnyBuiltin<afIndexOf>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("lastIndexOf"))
|
||||
return TCreateArrayAnyBuiltin<afLastIndexOf>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("__get") || field==HX_CSTRING("__unsafe_get"))
|
||||
return TCreateArrayAnyBuiltin<af__get>(src, inThisExpr, ioExpressions, field==HX_CSTRING("__unsafe_get"));
|
||||
if (field==HX_CSTRING("__set") || field==HX_CSTRING("__unsafe_set"))
|
||||
return TCreateArrayAnyBuiltin<af__set>(src, inThisExpr, ioExpressions, field==HX_CSTRING("__unsafe_set"));
|
||||
if (field==HX_CSTRING("__SetSizeExact"))
|
||||
return TCreateArrayAnyBuiltin<af__SetSizeExact>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("blit"))
|
||||
return TCreateArrayAnyBuiltin<afBlit>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("resize"))
|
||||
return TCreateArrayAnyBuiltin<afResize>(src, inThisExpr, ioExpressions);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
8318
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/Cppia.cpp
Normal file
8318
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/Cppia.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1227
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/Cppia.h
Normal file
1227
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/Cppia.h
Normal file
File diff suppressed because it is too large
Load Diff
1963
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaClasses.cpp
Normal file
1963
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaClasses.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1540
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCompiler.cpp
Normal file
1540
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCompiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
497
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCompiler.h
Normal file
497
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCompiler.h
Normal file
@ -0,0 +1,497 @@
|
||||
#ifndef HX_CPPIA_COMPILER_H_INCLUDED
|
||||
#define HX_CPPIA_COMPILER_H_INCLUDED
|
||||
|
||||
#if HXCPP_ARMV5
|
||||
#define SLJIT_CONFIG_ARM_V5 1
|
||||
#elif HXCPP_ARMV7
|
||||
#define SLJIT_CONFIG_ARM_V7 1
|
||||
#elif HXCPP_ARM64
|
||||
#define SLJIT_CONFIG_ARM_64 1
|
||||
#else
|
||||
#ifdef HXCPP_M64
|
||||
#define SLJIT_CONFIG_X86_64 1
|
||||
#else
|
||||
#define SLJIT_CONFIG_X86_32 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SLJIT_UTIL_STACK 0
|
||||
|
||||
#include "sljit_src/sljitLir.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define TRY_NATIVE try {
|
||||
#define CATCH_NATIVE } catch(Dynamic e) { CppiaCtx::getCurrent()->exception = e.mPtr ? e.mPtr : Dynamic(String("",0)).mPtr; }
|
||||
|
||||
|
||||
extern "C" struct sljit_jump;
|
||||
extern "C" struct sljit_label;
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
enum JitPosition
|
||||
{
|
||||
jposDontCare,
|
||||
jposCtx,
|
||||
jposFrame,
|
||||
jposLocal,
|
||||
jposThis,
|
||||
jposArray,
|
||||
jposRegister,
|
||||
jposStar,
|
||||
jposStarReg,
|
||||
jposPointerVal,
|
||||
jposIntVal,
|
||||
//jposFloatVal,
|
||||
};
|
||||
|
||||
enum JitType
|
||||
{
|
||||
jtAny,
|
||||
jtPointer,
|
||||
jtString,
|
||||
jtFloat,
|
||||
jtFloat32,
|
||||
jtInt,
|
||||
jtByte,
|
||||
jtShort,
|
||||
jtVoid,
|
||||
jtUnknown,
|
||||
};
|
||||
|
||||
|
||||
JitType getJitType(ExprType inType);
|
||||
int getJitTypeSize(JitType inType);
|
||||
|
||||
|
||||
struct JitStringMultiArg
|
||||
{
|
||||
int length;
|
||||
const HX_CHAR *__s;
|
||||
};
|
||||
|
||||
// double-aligned
|
||||
union JitMultiArg
|
||||
{
|
||||
int ival;
|
||||
double dval;
|
||||
hx::Object *obj;
|
||||
JitStringMultiArg sval;
|
||||
};
|
||||
|
||||
struct JitVal
|
||||
{
|
||||
JitPosition position;
|
||||
JitType type;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int offset;
|
||||
unsigned short reg0;
|
||||
unsigned short reg1;
|
||||
};
|
||||
void *pVal;
|
||||
double dVal;
|
||||
int iVal;
|
||||
};
|
||||
|
||||
JitVal(JitType inType=jtVoid, size_t inOffset=0, JitPosition inPosition=jposDontCare,int inReg0=0, int inReg1=0)
|
||||
{
|
||||
position = inPosition;
|
||||
type = inType;
|
||||
offset = (int)inOffset;
|
||||
reg0 = inReg0;
|
||||
reg1 = inReg1;
|
||||
}
|
||||
JitVal(int inValue)
|
||||
{
|
||||
offset = 0;
|
||||
reg0 = 0;
|
||||
reg1 = 0;
|
||||
position = jposIntVal;
|
||||
type = jtInt;
|
||||
iVal = inValue;
|
||||
}
|
||||
/*
|
||||
JitVal(double inValue)
|
||||
{
|
||||
offset = 0;
|
||||
reg0 = 0;
|
||||
reg1 = 0;
|
||||
position = jposFloatVal;
|
||||
type = jtFloat;
|
||||
dVal = inValue;
|
||||
}
|
||||
*/
|
||||
JitVal(void *inValue)
|
||||
{
|
||||
offset = 0;
|
||||
reg0 = 0;
|
||||
reg1 = 0;
|
||||
position = jposPointerVal;
|
||||
type = jtPointer;
|
||||
pVal = inValue;
|
||||
}
|
||||
|
||||
bool uses(int reg) const
|
||||
{
|
||||
return ( (position==jposRegister || position==jposStar || position==jposStar || position==jposStarReg) && reg==reg0 ) ||
|
||||
( position==jposStarReg && reg==reg1 );
|
||||
}
|
||||
|
||||
JitVal operator +(size_t inDiff) const { return JitVal(type, offset+inDiff, position, reg0, reg1); }
|
||||
JitVal as(JitType type) const { return JitVal(type, offset, position, reg0, reg1); }
|
||||
bool valid() const { return type!=jtVoid; }
|
||||
|
||||
bool operator==(const JitVal &inOther) const
|
||||
{
|
||||
return position==inOther.position && type==inOther.type && offset==inOther.offset && reg0==inOther.reg0 && reg1==inOther.reg1;
|
||||
}
|
||||
bool operator!=(const JitVal &inOther) const { return !(*this == inOther); }
|
||||
|
||||
JitVal getReg() const { return JitVal(jtPointer, 0, jposRegister, reg0, reg1); }
|
||||
|
||||
|
||||
private:
|
||||
JitVal(const JitType &);
|
||||
JitVal(const ExprType &);
|
||||
};
|
||||
|
||||
struct JitReg : public JitVal
|
||||
{
|
||||
JitReg(int inReg, JitType inType=jtAny) : JitVal(inType, 0, jposRegister, inReg, 0) { }
|
||||
|
||||
JitVal star(JitType inType=jtPointer, int inOffset=0) { return JitVal(inType, inOffset, jposStar, reg0, reg1); }
|
||||
JitVal star(ExprType inType, int inOffset=0) { return JitVal(getJitType(inType), inOffset, jposStar, reg0, reg1); }
|
||||
JitVal atReg(JitReg inReg, int inShift=0, JitType inType=jtAny) {
|
||||
return JitVal(inType, inShift, jposStarReg, reg0, inReg.reg0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern int sFrameReg;
|
||||
struct JitFramePos : public JitVal
|
||||
{
|
||||
JitFramePos(int inOffset, JitType inType=jtPointer) : JitVal(inType, inOffset, jposFrame, sFrameReg) { }
|
||||
JitFramePos(int inOffset, ExprType inType) : JitVal(getJitType(inType), inOffset, jposFrame, sFrameReg) { }
|
||||
};
|
||||
|
||||
extern int sLocalReg;
|
||||
struct JitLocalPos : public JitVal
|
||||
{
|
||||
JitLocalPos(int inOffset, JitType inType=jtPointer) : JitVal(inType, inOffset, jposLocal, sLocalReg) { }
|
||||
};
|
||||
|
||||
extern int sThisReg;
|
||||
struct JitThisPos : public JitVal
|
||||
{
|
||||
JitThisPos(int inOffset, JitType inType=jtPointer) : JitVal(inType, inOffset, jposThis, sThisReg) { }
|
||||
};
|
||||
|
||||
|
||||
enum JitCompare
|
||||
{
|
||||
// Pointer compare / String compare
|
||||
cmpP_EQUAL = 0,
|
||||
cmpP_ZERO = 0,
|
||||
cmpP_NOT_EQUAL = 1,
|
||||
cmpP_NOT_ZERO = 1,
|
||||
|
||||
cmpP_LESS = 2,
|
||||
cmpP_GREATER_EQUAL = 3,
|
||||
cmpP_GREATER = 4,
|
||||
cmpP_LESS_EQUAL = 5,
|
||||
cmpP_SIG_LESS = 6,
|
||||
cmpP_SIG_GREATER_EQUAL = 7,
|
||||
cmpP_SIG_GREATER = 8,
|
||||
cmpP_SIG_LESS_EQUAL = 9,
|
||||
|
||||
cmpP_OVERFLOW = 10,
|
||||
cmpP_NOT_OVERFLOW = 11,
|
||||
|
||||
cmpP_MUL_OVERFLOW = 12,
|
||||
cmpP_MUL_NOT_OVERFLOW = 13,
|
||||
|
||||
|
||||
// Integer compares
|
||||
cmpI_EQUAL = 0 | 0x100,
|
||||
cmpI_ZERO = 0 | 0x100,
|
||||
cmpI_NOT_EQUAL = 1 | 0x100,
|
||||
cmpI_NOT_ZERO = 1 | 0x100,
|
||||
|
||||
cmpI_LESS = 2 | 0x100,
|
||||
cmpI_GREATER_EQUAL = 3 | 0x100,
|
||||
cmpI_GREATER = 4 | 0x100,
|
||||
cmpI_LESS_EQUAL = 5 | 0x100,
|
||||
cmpI_SIG_LESS = 6 | 0x100,
|
||||
cmpI_SIG_GREATER_EQUAL = 7 | 0x100,
|
||||
cmpI_SIG_GREATER = 8 | 0x100,
|
||||
cmpI_SIG_LESS_EQUAL = 9 | 0x100,
|
||||
|
||||
cmpI_OVERFLOW = 10 | 0x100,
|
||||
cmpI_NOT_OVERFLOW = 11 | 0x100,
|
||||
|
||||
cmpI_MUL_OVERFLOW = 12 | 0x100,
|
||||
cmpI_MUL_NOT_OVERFLOW = 13 | 0x100,
|
||||
|
||||
/* Floating point comparison types - double. */
|
||||
cmpD_EQUAL = 16,
|
||||
cmpD_NOT_EQUAL = 17,
|
||||
cmpD_LESS = 18,
|
||||
cmpD_GREATER_EQUAL = 19,
|
||||
cmpD_GREATER = 20,
|
||||
cmpD_LESS_EQUAL = 21,
|
||||
cmpD_UNORDERED = 22,
|
||||
cmpD_ORDERED = 23,
|
||||
|
||||
/* Floating point comparison types - single. */
|
||||
cmpS_EQUAL = 16 | 0x100,
|
||||
cmpS_NOT_EQUAL = 17 | 0x100,
|
||||
cmpS_LESS = 18 | 0x100,
|
||||
cmpS_GREATER_EQUAL = 19 | 0x100,
|
||||
cmpS_GREATER = 20 | 0x100,
|
||||
cmpS_LESS_EQUAL = 21 | 0x100,
|
||||
cmpS_UNORDERED = 22 | 0x100,
|
||||
cmpS_ORDERED = 23 | 0x100,
|
||||
|
||||
};
|
||||
|
||||
enum BitOp
|
||||
{
|
||||
bitOpAnd,
|
||||
bitOpOr,
|
||||
bitOpXOr,
|
||||
bitOpUSR,
|
||||
bitOpShiftL,
|
||||
bitOpShiftR,
|
||||
};
|
||||
|
||||
bool isMemoryVal(const JitVal &inVal);
|
||||
|
||||
extern JitReg sJitFrame;
|
||||
extern JitReg sJitThis;
|
||||
|
||||
extern JitReg sJitTemp0;
|
||||
extern JitReg sJitTemp1;
|
||||
extern JitReg sJitTemp2;
|
||||
|
||||
extern JitReg sJitTempF0;
|
||||
extern JitReg sJitTempF1;
|
||||
extern JitReg sJitTempF2;
|
||||
|
||||
extern JitReg sJitReturnReg;
|
||||
extern JitReg sJitArg0;
|
||||
extern JitReg sJitArg1;
|
||||
extern JitReg sJitArg2;
|
||||
extern JitReg sJitCtx;
|
||||
extern JitVal sJitCtxPointer;
|
||||
extern JitVal sJitCtxFrame;
|
||||
|
||||
typedef sljit_label *LabelId;
|
||||
typedef sljit_jump *JumpId;
|
||||
|
||||
typedef void (SLJIT_CALL *CppiaFunc)(CppiaCtx *inCtx);
|
||||
typedef void (*OnReturnFunc)(class CppiaCompiler *inCompiler, int stackSize);
|
||||
|
||||
typedef std::vector<JumpId> ThrowList;
|
||||
|
||||
|
||||
class CppiaCompiler
|
||||
{
|
||||
public:
|
||||
static CppiaCompiler *create(int inFrameSize);
|
||||
virtual ~CppiaCompiler() { }
|
||||
|
||||
static void freeCompiled(CppiaFunc inFunc);
|
||||
|
||||
virtual void setError(const char *inError) = 0;
|
||||
virtual void crash() = 0;
|
||||
|
||||
virtual int getCurrentFrameSize() = 0;
|
||||
virtual void restoreFrameSize(int inSize) = 0;
|
||||
virtual void addFrame(ExprType inType) = 0;
|
||||
virtual void freeTempSize(int inSize) = 0;
|
||||
virtual int allocTempSize(int size) = 0;
|
||||
virtual int allocTemp(JitType inType) = 0;
|
||||
virtual void freeTemp(JitType inType) = 0;
|
||||
|
||||
virtual JitVal addLocal(const char *inName, JitType inType) = 0;
|
||||
virtual JitVal functionArg(int inIndex) = 0;
|
||||
|
||||
|
||||
virtual void convert(const JitVal &inSrc, ExprType inSrcType, const JitVal &inTarget, ExprType inToType, bool asBool=false) = 0;
|
||||
virtual void convertResult(ExprType inSrcType, const JitVal &inTarget, ExprType inToType) = 0;
|
||||
virtual void convertReturnReg(ExprType inSrcType, const JitVal &inTarget, ExprType inToType, bool asBool=false) = 0;
|
||||
virtual void genVariantValueTemp0(int inOffset, const JitVal &inDest, ExprType destType) = 0;
|
||||
virtual void returnNull(const JitVal &inTarget, ExprType inToType) = 0;
|
||||
|
||||
virtual void beginGeneration(int inArgs=1) = 0;
|
||||
virtual CppiaFunc finishGeneration() = 0;
|
||||
|
||||
virtual void setFunctionDebug() = 0;
|
||||
virtual void setLineDebug() = 0;
|
||||
|
||||
virtual LabelId setContinuePos(LabelId inNewPos) = 0;
|
||||
virtual void addContinue() = 0;
|
||||
virtual void swapBreakList(QuickVec<JumpId> &ioBreakList) = 0;
|
||||
virtual void addBreak() = 0;
|
||||
virtual void setBreakTarget() = 0;
|
||||
|
||||
virtual ThrowList *pushCatching(ThrowList *inCatching) = 0;
|
||||
virtual void popCatching(ThrowList *) = 0;
|
||||
virtual void addThrow() = 0;
|
||||
virtual void checkException() = 0;
|
||||
|
||||
// Unconditional
|
||||
virtual JumpId jump(LabelId inTo=0) = 0;
|
||||
virtual void jump(const JitVal &inWhere) = 0;
|
||||
// Conditional - int/pointer
|
||||
virtual JumpId compare(JitCompare condition, const JitVal &v0, const JitVal &v1, LabelId andJump=0) = 0;
|
||||
// Conditional - Float
|
||||
virtual JumpId fcompare(JitCompare condition, const JitVal &v0, const JitVal &v1, LabelId andJump, bool inReverse) = 0;
|
||||
// Conditional - String
|
||||
virtual JumpId scompare(JitCompare condition, const JitVal &v0, const JitVal &v1, LabelId andJump=0) = 0;
|
||||
// Link
|
||||
virtual void comeFrom(JumpId inWhere) = 0;
|
||||
virtual LabelId addLabel() = 0;
|
||||
|
||||
inline JumpId notNull(const JitVal &v0) { return compare(cmpP_NOT_ZERO, v0, (void *)0); }
|
||||
|
||||
virtual void setMaxPointer() = 0;
|
||||
|
||||
virtual int getBaseSize() = 0;
|
||||
virtual void setLineOffset( int inOffset ) = 0;
|
||||
virtual int getLineOffset( ) = 0;
|
||||
virtual void setOnReturn( OnReturnFunc inFunc, int inStackSize ) = 0;
|
||||
virtual void addReturn() = 0;
|
||||
|
||||
virtual void trace(const char *inValue) = 0;
|
||||
virtual void traceObject(const char *inLabel, const JitVal &inValue) = 0;
|
||||
virtual void tracePointer(const char *inLabel, const JitVal &inValue) = 0;
|
||||
virtual void traceFloat(const char *inLabel, const JitVal &inValue) = 0;
|
||||
virtual void traceStrings(const char *inS0, const char *inS1) = 0;
|
||||
virtual void traceInt(const char *inLabel, const JitVal &inValue) = 0;
|
||||
virtual void traceString(const char *inLabel, const JitVal &inValue) = 0;
|
||||
|
||||
virtual void negate(const JitVal &inDest, const JitVal &inSrc) = 0;
|
||||
virtual void add(const JitVal &inDest, const JitVal &v0, const JitVal &v1 ) = 0;
|
||||
virtual void bitOp(BitOp inOp, const JitVal &inDest, const JitVal &v0, const JitVal &v1 ) = 0;
|
||||
virtual void bitNot(const JitVal &inDest, const JitVal &v0 ) = 0;
|
||||
virtual void mult(const JitVal &inDest, const JitVal &v0, const JitVal &v1, bool asFloat ) = 0;
|
||||
virtual void sub(const JitVal &inDest, const JitVal &v0, const JitVal &v1, bool asFloat ) = 0;
|
||||
virtual void fdiv(const JitVal &inDest, const JitVal &v0, const JitVal &v1 ) = 0;
|
||||
virtual void divmod() = 0;
|
||||
virtual void move(const JitVal &inDest, const JitVal &src) = 0;
|
||||
//virtual void compare(Condition condition,const JitVal &v0, const JitVal &v1) = 0;
|
||||
|
||||
|
||||
//virtual void call(CppiaFunc func, JitType inReturnType=jtVoid)=0;
|
||||
//virtual void call(const JitVal &inFunc, JitType inReturnType=jtVoid)=0;
|
||||
virtual void call(const JitVal &inFunc, const JitVal &inArg0)=0;
|
||||
|
||||
virtual void callNative(void *func)=0;
|
||||
virtual void callNative(void *func, const JitVal &inArg0)=0;
|
||||
virtual void callNative(void *func, const JitVal &inArg0, const JitVal &inArg1)=0;
|
||||
virtual void callNative(void *func, const JitVal &inArg0, const JitVal &inArg1, const JitVal &inArg2)=0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct JitTemp : public JitVal
|
||||
{
|
||||
CppiaCompiler *compiler;
|
||||
int size;
|
||||
|
||||
JitTemp(CppiaCompiler *inCompiler, JitType inType)
|
||||
: JitVal(inType, inCompiler->allocTemp(inType), jposLocal, sLocalReg)
|
||||
{
|
||||
compiler = inCompiler;
|
||||
size = getJitTypeSize( inType );
|
||||
}
|
||||
|
||||
|
||||
JitTemp(CppiaCompiler *inCompiler, ExprType inType)
|
||||
: JitVal(getJitType(inType), inCompiler->allocTemp( getJitType(inType)), jposLocal, sLocalReg)
|
||||
{
|
||||
compiler = inCompiler;
|
||||
size = getJitTypeSize( getJitType(inType) );
|
||||
}
|
||||
|
||||
|
||||
JitTemp(CppiaCompiler *inCompiler, ExprType inType, int inSize)
|
||||
: JitVal(getJitType(inType), inCompiler->allocTempSize(inSize), jposLocal, sLocalReg)
|
||||
{
|
||||
compiler = inCompiler;
|
||||
size = inSize;
|
||||
}
|
||||
|
||||
|
||||
~JitTemp()
|
||||
{
|
||||
compiler->freeTempSize(size);
|
||||
}
|
||||
|
||||
JitVal star(JitType inType=jtPointer, size_t inOffset=0) { return JitVal(inType, offset+(int)inOffset, jposStar, sLocalReg, 0); }
|
||||
JitVal star(ExprType inType, size_t inOffset=0) { return JitVal(getJitType(inType), offset+(int)inOffset, jposStar, sLocalReg, 0); }
|
||||
|
||||
};
|
||||
|
||||
struct JitMultiArgs : public JitTemp
|
||||
{
|
||||
// Float, so address is passed to native function
|
||||
JitMultiArgs(CppiaCompiler *inCompiler, int inN) : JitTemp(inCompiler, etFloat, inN*sizeof(JitMultiArg) )
|
||||
{
|
||||
}
|
||||
|
||||
JitVal arg(int inIndex,JitType inType=jtPointer) { return (*this + inIndex*sizeof(JitMultiArg)).as(inType); }
|
||||
JitVal arg(int inIndex,ExprType inType) { return arg(inIndex,getJitType(inType)); }
|
||||
|
||||
};
|
||||
|
||||
struct JitSave
|
||||
{
|
||||
JitTemp temp;
|
||||
JitVal value;
|
||||
|
||||
JitSave(CppiaCompiler *compiler, const JitVal &val)
|
||||
: temp(compiler, val.type), value(val)
|
||||
{
|
||||
compiler->move(temp, value);
|
||||
}
|
||||
~JitSave()
|
||||
{
|
||||
temp.compiler->move(value,temp);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct AutoFramePos
|
||||
{
|
||||
CppiaCompiler *compiler;
|
||||
int framePos;
|
||||
|
||||
AutoFramePos(CppiaCompiler *inCompiler)
|
||||
{
|
||||
compiler = inCompiler;
|
||||
framePos=compiler->getCurrentFrameSize();
|
||||
}
|
||||
|
||||
~AutoFramePos()
|
||||
{
|
||||
compiler->restoreFrameSize(framePos);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// objVal - should not be sJitTemp1
|
||||
void genWriteBarrier(CppiaCompiler *compiler, JitReg objVal, JitVal valuePtr);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
137
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCtx.cpp
Normal file
137
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCtx.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/Scriptable.h>
|
||||
#include <hx/GC.h>
|
||||
#include <hx/Thread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Cppia.h"
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
#ifdef DEBUG_RETURN_TYPE
|
||||
#define DEBUG_RETURN_TYPE_CHECK \
|
||||
if (gLastRet!=CHECK && CHECK!=etVoid) { printf("BAD RETURN TYPE, got %d, expected %d!\n",gLastRet,CHECK); CPPIA_CHECK(0); }
|
||||
#else
|
||||
#define DEBUG_RETURN_TYPE_CHECK
|
||||
#endif
|
||||
|
||||
|
||||
#define GET_RETURN_VAL(RET,CHECK) \
|
||||
((ScriptCallable *)vtable)->runFunction(this); \
|
||||
breakContReturn = 0; \
|
||||
DEBUG_RETURN_TYPE_CHECK \
|
||||
RET;
|
||||
|
||||
|
||||
void StackContext::runVoid(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return;
|
||||
GET_RETURN_VAL(return,etVoid);
|
||||
/* Reached end of routine without return */
|
||||
}
|
||||
|
||||
int StackContext::runInt(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return 0;
|
||||
GET_RETURN_VAL(return getInt(), etInt );
|
||||
//printf("No Int return?\n");
|
||||
// Should not really get here...
|
||||
return 0;
|
||||
}
|
||||
Float StackContext::runFloat(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return 0;
|
||||
GET_RETURN_VAL(return getFloat(),etFloat );
|
||||
// Should not really get here...
|
||||
//printf("No Float return?\n");
|
||||
return 0;
|
||||
}
|
||||
String StackContext::runString(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return String();
|
||||
GET_RETURN_VAL(return getString(),etString );
|
||||
// Should not really get here...
|
||||
//printf("No String return?\n");
|
||||
return null();
|
||||
}
|
||||
Dynamic StackContext::runObject(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return null();
|
||||
GET_RETURN_VAL(return getObject(),etObject );
|
||||
//printf("No Object return?\n");
|
||||
return null();
|
||||
}
|
||||
hx::Object *StackContext::runObjectPtr(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return 0;
|
||||
GET_RETURN_VAL(return getObjectPtr(),etObject );
|
||||
//printf("No Object return?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int runContextConvertInt(StackContext *ctx, ExprType inType, void *inFunc)
|
||||
{
|
||||
switch(inType)
|
||||
{
|
||||
case etInt: return ctx->runInt(inFunc);
|
||||
case etFloat: return ctx->runFloat(inFunc);
|
||||
case etObject: return ctx->runObject(inFunc);
|
||||
default:
|
||||
ctx->runVoid(inFunc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Float runContextConvertFloat(StackContext *ctx, ExprType inType, void *inFunc)
|
||||
{
|
||||
switch(inType)
|
||||
{
|
||||
case etInt: return ctx->runInt(inFunc);
|
||||
case etFloat: return ctx->runFloat(inFunc);
|
||||
case etObject: return ctx->runObject(inFunc);
|
||||
default:
|
||||
ctx->runVoid(inFunc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
String runContextConvertString(StackContext *ctx, ExprType inType, void *inFunc)
|
||||
{
|
||||
switch(inType)
|
||||
{
|
||||
case etInt: return String(ctx->runInt(inFunc));
|
||||
case etFloat: return String(ctx->runFloat(inFunc));
|
||||
case etObject: return ctx->runObject(inFunc);
|
||||
case etString: return ctx->runString(inFunc);
|
||||
default:
|
||||
ctx->runVoid(inFunc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
hx::Object *runContextConvertObject(StackContext *ctx, ExprType inType, void *inFunc)
|
||||
{
|
||||
switch(inType)
|
||||
{
|
||||
case etInt: return Dynamic(ctx->runInt(inFunc)).mPtr;
|
||||
case etFloat: return Dynamic(ctx->runFloat(inFunc)).mPtr;
|
||||
case etObject: return ctx->runObject(inFunc).mPtr;
|
||||
case etString: return Dynamic(ctx->runString(inFunc)).mPtr;
|
||||
default:
|
||||
ctx->runVoid(inFunc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
1007
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaFunction.cpp
Normal file
1007
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaFunction.cpp
Normal file
File diff suppressed because it is too large
Load Diff
660
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaModule.cpp
Normal file
660
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaModule.cpp
Normal file
@ -0,0 +1,660 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
#include "CppiaStream.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
static int sScriptId = 0;
|
||||
|
||||
|
||||
const char **sgNativeNameSlots = 0;
|
||||
int sgNativeNameSlotCount = 0;
|
||||
|
||||
Array<Dynamic> gAllCppiaModules;
|
||||
|
||||
std::vector<hx::Resource> scriptResources;
|
||||
|
||||
|
||||
|
||||
// --- CppiaModule ----
|
||||
|
||||
CppiaModule::CppiaModule()
|
||||
{
|
||||
main = 0;
|
||||
layout = 0;
|
||||
creatingClass = 0;
|
||||
creatingFunction = 0;
|
||||
scriptId = ++sScriptId;
|
||||
strings = Array_obj<String>::__new(0,0);
|
||||
if (sgNativeNameSlotCount>0)
|
||||
for(int i=2;i<sgNativeNameSlotCount;i++)
|
||||
interfaceSlots[sgNativeNameSlots[i]] = i;
|
||||
|
||||
}
|
||||
|
||||
void CppiaModule::setDebug(CppiaExpr *outExpr, int inFileId, int inLine)
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (inFileId)
|
||||
allFileIds.insert(inFileId);
|
||||
#endif
|
||||
outExpr->className = creatingClass;
|
||||
outExpr->functionName = creatingFunction;
|
||||
//outExpr->filename = cStrings[inFileId].c_str();
|
||||
outExpr->filename = strings[inFileId].utf8_str();
|
||||
outExpr->line = inLine;
|
||||
}
|
||||
|
||||
|
||||
// --- CppiaModule -------------------------
|
||||
|
||||
CppiaModule::~CppiaModule()
|
||||
{
|
||||
delete main;
|
||||
for(int i=0;i<classes.size();i++)
|
||||
delete classes[i];
|
||||
}
|
||||
|
||||
void CppiaModule::link()
|
||||
{
|
||||
DBGLOG("Resolve registered - super\n");
|
||||
HaxeNativeClass::link();
|
||||
|
||||
DBGLOG("Resolve typeIds\n");
|
||||
for(int t=0;t<types.size();t++)
|
||||
types[t]->link(*this);
|
||||
|
||||
DBGLOG("Resolve inherited atributes\n");
|
||||
for(int i=0;i<classes.size();i++)
|
||||
{
|
||||
classes[i]->linkTypes();
|
||||
}
|
||||
|
||||
for(int i=0;i<classes.size();i++)
|
||||
{
|
||||
linkingClass = classes[i];
|
||||
classes[i]->link();
|
||||
}
|
||||
linkingClass = 0;
|
||||
|
||||
if (main)
|
||||
main = (ScriptCallable *)main->link(*this);
|
||||
}
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
void CppiaModule::compile()
|
||||
{
|
||||
for(int i=0;i<classes.size();i++)
|
||||
classes[i]->compile();
|
||||
|
||||
if (main)
|
||||
main->compile();
|
||||
}
|
||||
#endif
|
||||
|
||||
void addScriptableClass(String inName);
|
||||
void addScriptableFile(String inName);
|
||||
|
||||
void CppiaModule::registerDebugger()
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
for(int i=0;i<classes.size();i++)
|
||||
{
|
||||
String scriptable(classes[i]->name.c_str());
|
||||
addScriptableClass( scriptable.makePermanent().utf8_str() );
|
||||
}
|
||||
|
||||
for(hx::UnorderedSet<int>::const_iterator i = allFileIds.begin(); i!=allFileIds.end(); ++i)
|
||||
addScriptableFile(strings[*i]);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
CppiaClassInfo *CppiaModule::findClass( ::String inName)
|
||||
{
|
||||
|
||||
std::string stdName(inName.utf8_str());
|
||||
for(int i=0;i<classes.size();i++)
|
||||
if (classes[i]->name == stdName)
|
||||
return classes[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CppiaModule::mark(hx::MarkContext *__inCtx)
|
||||
{
|
||||
DBGLOG(" --- MARK --- \n");
|
||||
HX_MARK_MEMBER(strings);
|
||||
for(int i=0;i<types.size();i++)
|
||||
{
|
||||
if (types[i]) /* May be partially constructed */
|
||||
types[i]->mark(__inCtx);
|
||||
}
|
||||
for(int i=0;i<markable.size();i++)
|
||||
{
|
||||
markable[i]->mark(__inCtx);
|
||||
}
|
||||
for(int i=0;i<classes.size();i++)
|
||||
if (classes[i])
|
||||
{
|
||||
classes[i]->mark(__inCtx);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void CppiaModule::visit(hx::VisitContext *__inCtx)
|
||||
{
|
||||
HX_VISIT_MEMBER(strings);
|
||||
for(int i=0;i<types.size();i++)
|
||||
types[i]->visit(__inCtx);
|
||||
for(int i=0;i<markable.size();i++)
|
||||
markable[i]->visit(__inCtx);
|
||||
for(int i=0;i<classes.size();i++)
|
||||
if (classes[i])
|
||||
classes[i]->visit(__inCtx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void cppiaClassInit(CppiaClassInfo *inClass, CppiaCtx *ctx, int inPhase);
|
||||
|
||||
|
||||
|
||||
void CppiaModule::boot(CppiaCtx *ctx)
|
||||
{
|
||||
// boot (statics)
|
||||
for(int i=0;i<classes.size();i++)
|
||||
cppiaClassInit(classes[i],ctx,0);
|
||||
// run __init__
|
||||
for(int i=0;i<classes.size();i++)
|
||||
cppiaClassInit(classes[i],ctx,1);
|
||||
}
|
||||
|
||||
int CppiaModule::getInterfaceSlot(const std::string &inName)
|
||||
{
|
||||
InterfaceSlots::iterator it = interfaceSlots.find(inName);
|
||||
if (it==interfaceSlots.end())
|
||||
{
|
||||
#if (HXCPP_API_LEVEL >= 330)
|
||||
int result = interfaceSlots.size()+1;
|
||||
#else
|
||||
int result = interfaceSlots.size()+2;
|
||||
#endif
|
||||
interfaceSlots[inName] = result;
|
||||
return result;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
int CppiaModule::findInterfaceSlot(const std::string &inName)
|
||||
{
|
||||
InterfaceSlots::iterator it = interfaceSlots.find(inName);
|
||||
if (it==interfaceSlots.end())
|
||||
return -1;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CppiaModule::where(CppiaExpr *e)
|
||||
{
|
||||
if (linkingClass && layout)
|
||||
CPPIALOG(" in %s::%p\n", linkingClass->name.c_str(), layout);
|
||||
CPPIALOG(" %s at %s:%d %s\n", e->getName(), e->filename, e->line, e->functionName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ScriptableRegisterNameSlots(const char *inNames[], int inLength)
|
||||
{
|
||||
sgNativeNameSlots = inNames;
|
||||
sgNativeNameSlotCount = inLength;
|
||||
}
|
||||
|
||||
|
||||
// --- CppiaConst -------------------------------------------
|
||||
|
||||
CppiaConst::CppiaConst() : type(cNull), ival(0), dval(0) { }
|
||||
|
||||
void CppiaConst::fromStream(CppiaStream &stream)
|
||||
{
|
||||
std::string tok = stream.getToken();
|
||||
if (tok[0]=='i')
|
||||
{
|
||||
type = cInt;
|
||||
|
||||
dval = ival = stream.getInt();
|
||||
}
|
||||
else if (tok=="true")
|
||||
{
|
||||
type = cInt;
|
||||
dval = ival = 1;
|
||||
}
|
||||
else if (tok=="false")
|
||||
{
|
||||
type = cInt;
|
||||
dval = ival = 0;
|
||||
}
|
||||
else if (tok[0]=='f')
|
||||
{
|
||||
type = cFloat;
|
||||
int strIndex = stream.getInt();
|
||||
String val = stream.module->strings[strIndex];
|
||||
dval = atof(val.out_str());
|
||||
ival = dval;
|
||||
}
|
||||
else if (tok[0]=='s')
|
||||
{
|
||||
type = cString;
|
||||
ival = stream.getInt();
|
||||
}
|
||||
else if (tok=="NULL")
|
||||
type = cNull;
|
||||
else if (tok=="THIS")
|
||||
type = cThis;
|
||||
else if (tok=="SUPER")
|
||||
type = cSuper;
|
||||
else
|
||||
throw "unknown const value";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// --- CppiaLoadedModule -------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Cppia Object - manage
|
||||
class CppiaObject : public hx::CppiaLoadedModule_obj
|
||||
{
|
||||
public:
|
||||
CppiaModule *cppia;
|
||||
bool booted;
|
||||
|
||||
CppiaObject(CppiaModule *inModule)
|
||||
{
|
||||
cppia = inModule;
|
||||
GCSetFinalizer( this, onRelease );
|
||||
}
|
||||
static void onRelease(hx::Object *inObj)
|
||||
{
|
||||
delete ((CppiaObject *)inObj)->cppia;
|
||||
}
|
||||
void __Mark(hx::MarkContext *ctx) { cppia->mark(ctx); }
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *ctx) { cppia->visit(ctx); }
|
||||
#endif
|
||||
|
||||
|
||||
void boot()
|
||||
{
|
||||
if (booted)
|
||||
return;
|
||||
|
||||
booted = true;
|
||||
try
|
||||
{
|
||||
DBGLOG("--- Boot --------------------------------------------\n");
|
||||
CppiaCtx *ctx = CppiaCtx::getCurrent();
|
||||
cppia->boot(ctx);
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
String error(errorString);
|
||||
hx::Throw(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
if (!booted)
|
||||
boot();
|
||||
if (cppia->main)
|
||||
{
|
||||
try
|
||||
{
|
||||
//__hxcpp_enable(false);
|
||||
DBGLOG("--- Run --------------------------------------------\n");
|
||||
CppiaCtx *ctx = CppiaCtx::getCurrent();
|
||||
ctx->runVoid(cppia->main);
|
||||
if (ctx->exception)
|
||||
{
|
||||
hx::Object *e = ctx->exception;
|
||||
ctx->exception = 0;
|
||||
hx::Throw( Dynamic(e) );
|
||||
}
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
String error(errorString);
|
||||
hx::Throw(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::hx::Class resolveClass( ::String inName)
|
||||
{
|
||||
CppiaClassInfo *info = cppia->findClass(inName);
|
||||
if (info)
|
||||
return info->getClass();
|
||||
return null();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
CppiaLoadedModule LoadCppia(const unsigned char *inData, int inDataLength)
|
||||
{
|
||||
if (!gAllCppiaModules.mPtr)
|
||||
{
|
||||
gAllCppiaModules = Array_obj<Dynamic>::__new();
|
||||
GCAddRoot( (hx::Object **)&gAllCppiaModules.mPtr );
|
||||
}
|
||||
|
||||
CppiaModule *cppiaPtr = new CppiaModule();
|
||||
CppiaLoadedModule loadedModule = new CppiaObject(cppiaPtr);
|
||||
gAllCppiaModules->push(loadedModule);
|
||||
|
||||
|
||||
CppiaModule &cppia = *cppiaPtr;
|
||||
CppiaStream stream(cppiaPtr,inData, inDataLength);
|
||||
|
||||
String error;
|
||||
try
|
||||
{
|
||||
std::string tok = stream.getAsciiToken();
|
||||
if (tok!="CPPIA" && tok!="CPPIB")
|
||||
throw "Bad magic";
|
||||
|
||||
stream.setBinary(tok=="CPPIB");
|
||||
|
||||
int stringCount = stream.getAsciiInt();
|
||||
for(int s=0;s<stringCount;s++)
|
||||
cppia.strings[s] = stream.readString();
|
||||
|
||||
int typeCount = stream.getAsciiInt();
|
||||
cppia.types.resize(typeCount);
|
||||
DBGLOG("Type count : %d\n", typeCount);
|
||||
for(int t=0;t<typeCount;t++)
|
||||
cppia.types[t] = new TypeData(stream.readString());
|
||||
|
||||
int classCount = stream.getAsciiInt();
|
||||
DBGLOG("Class count : %d\n", classCount);
|
||||
|
||||
if (stream.binary)
|
||||
{
|
||||
int newLine = stream.getByte();
|
||||
if (newLine!='\n')
|
||||
throw "Missing new-line after class count";
|
||||
}
|
||||
|
||||
cppia.classes.reserve(classCount);
|
||||
for(int c=0;c<classCount;c++)
|
||||
{
|
||||
CppiaClassInfo *info = new CppiaClassInfo(cppia);
|
||||
if (info->load(stream))
|
||||
cppia.classes.push_back(info);
|
||||
}
|
||||
|
||||
tok = stream.getToken();
|
||||
if (tok=="MAIN")
|
||||
{
|
||||
DBGLOG("Main...\n");
|
||||
cppia.main = new ScriptCallable(createCppiaExpr(stream));
|
||||
cppia.main->className = "cppia";
|
||||
cppia.main->functionName = "__cppia_main";
|
||||
}
|
||||
else if (tok!="NOMAIN")
|
||||
throw "no main specified";
|
||||
|
||||
tok = stream.getToken();
|
||||
if (tok=="RESOURCES")
|
||||
{
|
||||
int count = stream.getInt( );
|
||||
scriptResources.resize(count+1);
|
||||
for(int r=0;r<count;r++)
|
||||
{
|
||||
tok = stream.getToken();
|
||||
if (tok!="RESO")
|
||||
throw "no reso tag";
|
||||
|
||||
scriptResources[r].mName = cppia.strings[stream.getInt()];
|
||||
scriptResources[r].mDataLength = stream.getInt();
|
||||
}
|
||||
if (!stream.binary)
|
||||
stream.skipChar();
|
||||
|
||||
for(int r=0;r<count;r++)
|
||||
{
|
||||
int len = scriptResources[r].mDataLength;
|
||||
unsigned char *buffer = (unsigned char *)malloc(len+5);
|
||||
*(unsigned int *)buffer = HX_GC_CONST_ALLOC_BIT;
|
||||
buffer[len+5-1] = '\0';
|
||||
stream.readBytes(buffer+4, len);
|
||||
#ifdef HX_SMART_STRINGS_1
|
||||
unsigned char *p = (unsigned char *)buffer+4;
|
||||
unsigned char *end = p + len;
|
||||
while(!hasBig && p<end)
|
||||
if (*p++>127)
|
||||
{
|
||||
*(unsigned int *)buffer |= HX_GC_STRING_CHAR16_T;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
scriptResources[r].mData = buffer + 4;
|
||||
}
|
||||
scriptResources[count].mDataLength = 0;
|
||||
scriptResources[count].mData = 0;
|
||||
scriptResources[count].mName = String();
|
||||
|
||||
RegisterResources(&scriptResources[0]);
|
||||
}
|
||||
else
|
||||
throw "no resources tag";
|
||||
|
||||
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
error = HX_CSTRING("Error reading file ") + String(errorString) +
|
||||
HX_CSTRING(", line ") + String(stream.line) + HX_CSTRING(", char ") +
|
||||
String(stream.pos);
|
||||
}
|
||||
|
||||
if (!error.raw_ptr())
|
||||
try
|
||||
{
|
||||
DBGLOG("Link...\n");
|
||||
cppia.link();
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
error = String(errorString);
|
||||
}
|
||||
|
||||
if (gEnableJit)
|
||||
{
|
||||
#ifdef CPPIA_JIT
|
||||
if (!error.raw_ptr())
|
||||
try
|
||||
{
|
||||
DBGLOG("Compile...\n");
|
||||
cppia.compile();
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
error = String(errorString);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (error.raw_ptr())
|
||||
hx::Throw(error);
|
||||
|
||||
cppia.registerDebugger();
|
||||
|
||||
return loadedModule;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Array<String > gAllClasses;
|
||||
Array<String > gAllFiles;
|
||||
|
||||
void addScriptableClass(String inName)
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (!gAllClasses.mPtr)
|
||||
{
|
||||
gAllClasses = Array_obj<Dynamic>::__new();
|
||||
GCAddRoot( (hx::Object **)&gAllClasses.mPtr );
|
||||
}
|
||||
if (gAllClasses->indexOf(inName)<0)
|
||||
gAllClasses->push(inName);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void addScriptableFile(String inName)
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (!gAllFiles.mPtr)
|
||||
{
|
||||
gAllFiles = Array_obj<Dynamic>::__new();
|
||||
GCAddRoot( (hx::Object **)&gAllFiles.mPtr );
|
||||
}
|
||||
if (gAllFiles->indexOf(inName)<0)
|
||||
gAllFiles->push(inName);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef HXCPP_STACK_SCRIPTABLE
|
||||
|
||||
void __hxcpp_dbg_getScriptableVariables(hx::StackFrame *inFrame, ::Array<Dynamic> outNames)
|
||||
{
|
||||
hx::ScriptCallable *callable = inFrame->position->scriptCallable;
|
||||
if (callable)
|
||||
callable->getScriptableVariables((unsigned char *)inFrame, outNames);
|
||||
}
|
||||
|
||||
bool __hxcpp_dbg_getScriptableValue(hx::StackFrame *inFrame, String inName, ::Dynamic &outValue)
|
||||
{
|
||||
hx::ScriptCallable *callable = inFrame->position->scriptCallable;
|
||||
if (callable)
|
||||
return callable->getScriptableValue((unsigned char *)inFrame, inName, outValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool __hxcpp_dbg_setScriptableValue(hx::StackFrame *inFrame, String inName, ::Dynamic inValue)
|
||||
{
|
||||
hx::ScriptCallable *callable = inFrame->position->scriptCallable;
|
||||
if (callable)
|
||||
return callable->setScriptableValue((unsigned char *)inFrame, inName, inValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
void __hxcpp_dbg_getScriptableFiles( Array< ::String> ioPaths )
|
||||
{
|
||||
Array<String> merge = hx::gAllFiles;
|
||||
if (merge.mPtr)
|
||||
for(int i=0;i< merge->length; i++)
|
||||
{
|
||||
if (ioPaths->indexOf( merge[i] ) < 0)
|
||||
ioPaths->push( merge[i] );
|
||||
}
|
||||
}
|
||||
|
||||
void __hxcpp_dbg_getScriptableFilesFullPath( Array< ::String> ioPaths )
|
||||
{
|
||||
__hxcpp_dbg_getScriptableFiles( ioPaths );
|
||||
}
|
||||
|
||||
void __hxcpp_dbg_getScriptableClasses( Array< ::String> ioClasses )
|
||||
{
|
||||
Array<String> merge = hx::gAllClasses;
|
||||
if (merge.mPtr)
|
||||
for(int i=0;i< merge->length; i++)
|
||||
{
|
||||
if (ioClasses->indexOf( merge[i] ) < 0)
|
||||
ioClasses->push( merge[i] );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
::hx::CppiaLoadedModule __scriptable_cppia_from_string(String inCode)
|
||||
{
|
||||
const unsigned char *code = (const unsigned char *)inCode.raw_ptr();
|
||||
int length = inCode.length;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (inCode.isUTF16Encoded())
|
||||
{
|
||||
code = (const unsigned char *)inCode.utf8_str();
|
||||
length = strlen( (const char *)code );
|
||||
}
|
||||
#endif
|
||||
|
||||
return hx::LoadCppia(code,length);
|
||||
}
|
||||
|
||||
|
||||
::hx::CppiaLoadedModule __scriptable_cppia_from_data(Array<unsigned char> inCode)
|
||||
{
|
||||
return hx::LoadCppia( (unsigned char *)inCode->GetBase() ,inCode->length);
|
||||
}
|
||||
|
||||
|
||||
void __scriptable_load_cppia(String inCode)
|
||||
{
|
||||
const unsigned char *code = (const unsigned char *)inCode.raw_ptr();
|
||||
int length = inCode.length;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (inCode.isUTF16Encoded())
|
||||
{
|
||||
code = (const unsigned char *)inCode.utf8_str();
|
||||
length = strlen( (const char *)code );
|
||||
}
|
||||
#endif
|
||||
|
||||
::hx::CppiaLoadedModule module = hx::LoadCppia(code,length);
|
||||
|
||||
module->boot();
|
||||
module->run();
|
||||
}
|
||||
|
||||
118
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaOps.inc
Normal file
118
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaOps.inc
Normal file
@ -0,0 +1,118 @@
|
||||
|
||||
CPPIA_OP( IaFunction , "FUNCTION", 1)
|
||||
CPPIA_OP( IaVar , "VAR", 2)
|
||||
CPPIA_OP( IaToInterface , "TOINTERFACE", 3)
|
||||
CPPIA_OP( IaToDynArray , "TODYNARRAY", 4)
|
||||
CPPIA_OP( IaToDataArray , "TODATAARRAY", 5)
|
||||
CPPIA_OP( IaToInterfaceArray , "TOINTERFACEARRAY", 6)
|
||||
CPPIA_OP( IaFun , "FUN", 7)
|
||||
CPPIA_OP( IaCast , "CAST", 8)
|
||||
CPPIA_OP( IaBlock , "BLOCK", 9)
|
||||
CPPIA_OP( IaBreak , "BREAK", 10)
|
||||
CPPIA_OP( IaContinue , "CONTINUE", 11)
|
||||
CPPIA_OP( IaIsNull , "ISNULL", 12)
|
||||
CPPIA_OP( IaNotNull , "NOTNULL", 13)
|
||||
CPPIA_OP( IaSet , "SET", 14)
|
||||
CPPIA_OP( IaCall , "CALL", 15)
|
||||
CPPIA_OP( IaCallGlobal , "CALLGLOBAL", 16)
|
||||
CPPIA_OP( IaCallStatic , "CALLSTATIC", 17)
|
||||
CPPIA_OP( IaCallMember , "CALLMEMBER", 18)
|
||||
CPPIA_OP( IaCallSuper , "CALLSUPER", 19)
|
||||
CPPIA_OP( IaCallThis , "CALLTHIS", 20)
|
||||
CPPIA_OP( IaCallSuperNew , "CALLSUPERNEW", 21)
|
||||
CPPIA_OP( IaCreateEnum , "CREATEENUM", 22)
|
||||
CPPIA_OP( IaADef , "ADEF", 23)
|
||||
CPPIA_OP( IaIf , "IF", 24)
|
||||
CPPIA_OP( IaIfElse , "IFELSE", 25)
|
||||
CPPIA_OP( IaFName , "FNAME", 27)
|
||||
CPPIA_OP( IaFStatic , "FSTATIC", 28)
|
||||
CPPIA_OP( IaFThisInst , "FTHISINST", 29)
|
||||
CPPIA_OP( IaFLink , "FLINK", 30)
|
||||
CPPIA_OP( IaFThisName , "FTHISNAME", 31)
|
||||
CPPIA_OP( IaFEnum , "FENUM", 32)
|
||||
CPPIA_OP( IaThrow , "THROW", 33)
|
||||
CPPIA_OP( IaArrayI , "ARRAYI", 34)
|
||||
CPPIA_OP( IaPlusPlus , "++", 35)
|
||||
CPPIA_OP( IaPlusPlusPost , "+++", 36)
|
||||
CPPIA_OP( IaMinusMinus , "--", 37)
|
||||
CPPIA_OP( IaMinusMinusPost , "---", 38)
|
||||
CPPIA_OP( IaNeg , "NEG", 39)
|
||||
CPPIA_OP( IaBitNot , "~", 40)
|
||||
CPPIA_OP( IaLogicNot , "!", 41)
|
||||
CPPIA_OP( IaTVars , "TVARS", 42)
|
||||
CPPIA_OP( IaVarDecl , "VARDECL", 43)
|
||||
CPPIA_OP( IaVarDeclI , "VARDECLI", 44)
|
||||
CPPIA_OP( IaNew , "NEW", 45)
|
||||
CPPIA_OP( IaReturn , "RETURN", 46)
|
||||
CPPIA_OP( IaRetVal , "RETVAL", 47)
|
||||
CPPIA_OP( IaPosInfo , "POSINFO", 48)
|
||||
CPPIA_OP( IaObjDef , "OBJDEF", 49)
|
||||
CPPIA_OP( IaClassOf , "CLASSOF", 50)
|
||||
CPPIA_OP( IaWhile , "WHILE", 51)
|
||||
CPPIA_OP( IaFor , "FOR", 52)
|
||||
CPPIA_OP( IaEnumI , "ENUMI", 53)
|
||||
CPPIA_OP( IaSwitch , "SWITCH", 54)
|
||||
CPPIA_OP( IaTry , "TRY", 55)
|
||||
CPPIA_OP( IaImplDynamic , "IMPLDYNAMIC", 56)
|
||||
CPPIA_OP( IaConstInt , "i", 57)
|
||||
CPPIA_OP( IaConstFloat , "f", 58)
|
||||
CPPIA_OP( IaConstString , "s", 59)
|
||||
CPPIA_OP( IaConstFalse , "false", 60)
|
||||
CPPIA_OP( IaConstTrue , "true", 61)
|
||||
CPPIA_OP( IaConstNull , "NULL", 62)
|
||||
CPPIA_OP( IaConsThis , "THIS", 63)
|
||||
CPPIA_OP( IaConstSuper , "SUPER", 64)
|
||||
CPPIA_OP( IaCastInt , "CASTINT", 65)
|
||||
CPPIA_OP( IaCastBool , "CASTBOOL", 66)
|
||||
CPPIA_OP( IaInterface , "INTERFACE", 67)
|
||||
CPPIA_OP( IaClass , "CLASS", 68)
|
||||
CPPIA_OP( IaAccessNormal , "N", 69)
|
||||
CPPIA_OP( IaAccessNot , "n", 70)
|
||||
CPPIA_OP( IaAccessResolve , "R", 71)
|
||||
CPPIA_OP( IaAccessCall , "C", 72)
|
||||
CPPIA_OP( IaEnum , "ENUM", 73)
|
||||
CPPIA_OP( IaInline , "INLINE", 74)
|
||||
CPPIA_OP( IaMain , "MAIN", 75)
|
||||
CPPIA_OP( IaNoMain , "NOMAIN", 76)
|
||||
CPPIA_OP( IaResources , "RESOURCES", 77)
|
||||
CPPIA_OP( IaReso , "RESO", 78)
|
||||
CPPIA_OP( IaNoCast , "NOCAST", 79)
|
||||
CPPIA_OP( IaAccessCallNative , "V", 80)
|
||||
CPPIA_OP( IaBinOpAdd , "+", 101)
|
||||
CPPIA_OP( IaBinOpMult , "*", 102)
|
||||
CPPIA_OP( IaBinOpDiv , "/", 103)
|
||||
CPPIA_OP( IaBinOpSub , "-", 104)
|
||||
CPPIA_OP( IaBinOpAssign , "=", 105)
|
||||
CPPIA_OP( IaBinOpEq , "==", 106)
|
||||
CPPIA_OP( IaBinOpNotEq , "!=", 107)
|
||||
CPPIA_OP( IaBinOpGte , ">=", 108)
|
||||
CPPIA_OP( IaBinOpLte , "<=", 109)
|
||||
CPPIA_OP( IaBinOpGt , ">", 110)
|
||||
CPPIA_OP( IaBinOpLt , "<", 111)
|
||||
CPPIA_OP( IaBinOpAnd , "&", 112)
|
||||
CPPIA_OP( IaBinOpOr , "|", 113)
|
||||
CPPIA_OP( IaBinOpXor , "^", 114)
|
||||
CPPIA_OP( IaBinOpBoolAnd , "&&", 115)
|
||||
CPPIA_OP( IaBinOpBoolOr , "||", 116)
|
||||
CPPIA_OP( IaBinOpShr , ">>", 117)
|
||||
CPPIA_OP( IaBinOpUShr , ">>>", 118)
|
||||
CPPIA_OP( IaBinOpShl , "<<", 119)
|
||||
CPPIA_OP( IaBinOpMod , "%", 120)
|
||||
CPPIA_OP( IaBinOpInterval , "...", 121)
|
||||
CPPIA_OP( IaBinOpArrow , "=>", 122)
|
||||
CPPIA_OP( IaBinOpAssignAdd , "+=", 201)
|
||||
CPPIA_OP( IaBinOpAssignMult , "*=", 202)
|
||||
CPPIA_OP( IaBinOpAssignDiv , "/=", 203)
|
||||
CPPIA_OP( IaBinOpAssignSub , "-=", 204)
|
||||
CPPIA_OP( IaBinOpAssignAnd , "&=", 212)
|
||||
CPPIA_OP( IaBinOpAssignOr , "|=", 213)
|
||||
CPPIA_OP( IaBinOpAssignXor , "^=", 214)
|
||||
CPPIA_OP( IaBinOpAssignBoolAnd , "&&=", 215)
|
||||
CPPIA_OP( IaBinOpAssignBoolOr , "||=", 216)
|
||||
CPPIA_OP( IaBinOpAssignShr , ">>=", 217)
|
||||
CPPIA_OP( IaBinOpAssignUShr , ">>>=", 218)
|
||||
CPPIA_OP( IaBinOpAssignShl , "<<=", 219)
|
||||
CPPIA_OP( IaBinOpAssignMod , "%=", 220)
|
||||
CPPIA_OP( IaTCast , "TCAST", 221)
|
||||
|
||||
|
||||
214
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaStream.h
Normal file
214
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaStream.h
Normal file
@ -0,0 +1,214 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
struct CppiaStream
|
||||
{
|
||||
std::map<int,std::string> tokenMap;
|
||||
std::map<std::string,int> opMap;
|
||||
bool binary;
|
||||
class CppiaModule *module;
|
||||
const char *data;
|
||||
const char *max;
|
||||
int line;
|
||||
int pos;
|
||||
|
||||
CppiaStream(class CppiaModule *inModule,const unsigned char *inData, int inLen)
|
||||
{
|
||||
binary = false;
|
||||
module = inModule;
|
||||
data = (const char *)inData;
|
||||
max = data + inLen;
|
||||
line = 1;
|
||||
pos = 1;
|
||||
}
|
||||
|
||||
struct OpName { int id; const char *name; };
|
||||
void setBinary(bool inBinary)
|
||||
{
|
||||
binary = inBinary;
|
||||
OpName names[] = {
|
||||
#define CPPIA_OP(ident,name,id) { id, name },
|
||||
#include "CppiaOps.inc"
|
||||
#undef CPPIA_OP
|
||||
};
|
||||
if (binary)
|
||||
{
|
||||
for(int i=0;i<sizeof(names)/sizeof(names[0]);i++)
|
||||
{
|
||||
OpName &name = names[i];
|
||||
if (!tokenMap[name.id].empty())
|
||||
throw "Double identifier";
|
||||
tokenMap[ name.id ] = name.name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i=0;i<sizeof(names)/sizeof(names[0]);i++)
|
||||
{
|
||||
OpName &name = names[i];
|
||||
opMap[ name.name ] = name.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
void skipWhitespace()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
while(data<max && *data<=32)
|
||||
skipChar();
|
||||
if (data<max && *data=='#')
|
||||
{
|
||||
while(data<max && *data!='\n')
|
||||
skipChar();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
int getLineId()
|
||||
{
|
||||
return binary ? 0 : getInt();
|
||||
}
|
||||
int getFileId()
|
||||
{
|
||||
return binary ? 0 : getInt();
|
||||
}
|
||||
void skipChar()
|
||||
{
|
||||
if (data>=max)
|
||||
throw "EOF";
|
||||
if (*data=='\n')
|
||||
{
|
||||
line++;
|
||||
pos = 1;
|
||||
}
|
||||
else
|
||||
pos++;
|
||||
data++;
|
||||
}
|
||||
std::string getAsciiToken()
|
||||
{
|
||||
skipWhitespace();
|
||||
const char *data0 = data;
|
||||
while(data<max && *data>32)
|
||||
{
|
||||
data++;
|
||||
pos++;
|
||||
}
|
||||
return std::string(data0,data);
|
||||
}
|
||||
|
||||
|
||||
CppiaOp getOp()
|
||||
{
|
||||
if (binary)
|
||||
return (CppiaOp) getInt();
|
||||
std::string tok = getAsciiToken();
|
||||
CppiaOp result = (CppiaOp)opMap[tok];
|
||||
if (result==0)
|
||||
throw "Unknown token";
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::string getToken()
|
||||
{
|
||||
if (!binary)
|
||||
return getAsciiToken();
|
||||
int id = getInt();
|
||||
//printf("Token %s\n", tokenMap[id].c_str());
|
||||
return tokenMap[id];
|
||||
}
|
||||
|
||||
int getAsciiInt()
|
||||
{
|
||||
int result = 0;
|
||||
int sign = 1;
|
||||
skipWhitespace();
|
||||
while(data<max && *data>32)
|
||||
{
|
||||
if (*data=='-')
|
||||
sign = -1;
|
||||
else
|
||||
{
|
||||
int digit = *data - '0';
|
||||
if (digit<0 || digit>9)
|
||||
throw "expected digit";
|
||||
result = result * 10 + digit;
|
||||
}
|
||||
pos++;
|
||||
data++;
|
||||
}
|
||||
return result*sign;
|
||||
}
|
||||
|
||||
int getByte()
|
||||
{
|
||||
int result = *(unsigned char *)data;
|
||||
data++;
|
||||
pos++;
|
||||
return result;
|
||||
}
|
||||
int getInt()
|
||||
{
|
||||
if (!binary)
|
||||
return getAsciiInt();
|
||||
|
||||
int code = getByte();
|
||||
if (code<254)
|
||||
return code;
|
||||
if (code==254)
|
||||
{
|
||||
int result = getByte();
|
||||
result |= (getByte()<<8);
|
||||
return result;
|
||||
}
|
||||
|
||||
int result = getByte();
|
||||
result |= (getByte()<<8);
|
||||
result |= (getByte()<<16);
|
||||
result |= (getByte()<<24);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool getBool()
|
||||
{
|
||||
int ival = getInt();
|
||||
if (ival>1)
|
||||
throw "invalid bool";
|
||||
return ival;
|
||||
}
|
||||
bool getStatic()
|
||||
{
|
||||
return getBool();
|
||||
}
|
||||
|
||||
String readString(std::string *outStdStdString=0)
|
||||
{
|
||||
int len = getAsciiInt();
|
||||
skipChar();
|
||||
const char *data0 = data;
|
||||
int hasBig = false;
|
||||
for(int i=0;i<len;i++)
|
||||
skipChar();
|
||||
if (outStdStdString)
|
||||
*outStdStdString = std::string(data0, data);
|
||||
return String::createPermanent(data0,data-data0);
|
||||
}
|
||||
|
||||
void readBytes(unsigned char *outBytes, int inLen)
|
||||
{
|
||||
if (data+inLen>max)
|
||||
throw "EOF";
|
||||
memcpy(outBytes, data, inLen);
|
||||
data+=inLen;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
|
||||
680
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaVars.cpp
Normal file
680
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaVars.cpp
Normal file
@ -0,0 +1,680 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
#include "CppiaStream.h"
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
static int sTypeSize[] = { 0, 0, sizeof(hx::Object *), sizeof(String), sizeof(Float), sizeof(int) };
|
||||
|
||||
inline void AlignOffset(ExprType type, int &ioOffset)
|
||||
{
|
||||
#ifdef HXCPP_ALIGN_FLOAT
|
||||
if (type==etFloat && (ioOffset & 0x7) )
|
||||
ioOffset = (ioOffset + 7) & ~7;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
FieldStorage fieldStorageFromType(TypeData *inType)
|
||||
{
|
||||
if (!inType)
|
||||
return fsObject;
|
||||
|
||||
switch(inType->expressionType)
|
||||
{
|
||||
case etInt:
|
||||
if (inType->name==HX_CSTRING("Bool"))
|
||||
return fsBool;
|
||||
return fsInt;
|
||||
case etFloat: return fsFloat;
|
||||
case etString: return fsString;
|
||||
case etObject: return fsObject;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return fsUnknown;
|
||||
}
|
||||
|
||||
|
||||
// --- CppiaVar ----
|
||||
|
||||
CppiaVar::CppiaVar(bool inIsStatic) : isStatic(inIsStatic)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
CppiaVar::CppiaVar(CppiaFunction *inDynamicFunction)
|
||||
{
|
||||
clear();
|
||||
isStatic = inDynamicFunction->isStatic;
|
||||
dynamicFunction = inDynamicFunction;
|
||||
nameId = dynamicFunction->nameId;
|
||||
exprType = etObject;
|
||||
storeType = fsObject;
|
||||
}
|
||||
|
||||
void CppiaVar::clear()
|
||||
{
|
||||
type = 0;
|
||||
nameId = 0;
|
||||
typeId = 0;
|
||||
offset = 0;
|
||||
type = 0;
|
||||
objVal.mPtr = 0;
|
||||
intVal = 0;
|
||||
stringVal = String();
|
||||
valPointer = 0;
|
||||
storeType = fsUnknown;
|
||||
dynamicFunction = 0;
|
||||
isVirtual = false;
|
||||
init = 0;
|
||||
}
|
||||
|
||||
void CppiaVar::load(CppiaStream &stream)
|
||||
{
|
||||
readAccess = getAccess(stream);
|
||||
writeAccess = getAccess(stream);
|
||||
isVirtual = stream.getBool();
|
||||
nameId = stream.getInt();
|
||||
typeId = stream.getInt();
|
||||
if (stream.getInt())
|
||||
init = createCppiaExpr(stream);
|
||||
}
|
||||
|
||||
|
||||
// Static...
|
||||
void CppiaVar::linkVarTypes(CppiaModule &cppia)
|
||||
{
|
||||
if (dynamicFunction)
|
||||
{
|
||||
nameId = dynamicFunction->nameId;
|
||||
}
|
||||
type = cppia.types[typeId];
|
||||
name = cppia.strings[nameId];
|
||||
exprType = typeId==0 ? etObject : type->expressionType;
|
||||
|
||||
if (!isVirtual)
|
||||
{
|
||||
storeType = typeId==0 ? fsObject : fieldStorageFromType(type);
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsBool: valPointer = &boolVal; break;
|
||||
case fsByte: valPointer = &byteVal; break;
|
||||
case fsInt: valPointer = &intVal; break;
|
||||
case fsFloat: valPointer = &floatVal; break;
|
||||
case fsString: valPointer = &stringVal; break;
|
||||
case fsObject: valPointer = &objVal; break;
|
||||
default:
|
||||
valPointer = 0;
|
||||
throw "Unkown store type";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CppiaVar::hasPointer()
|
||||
{
|
||||
return storeType==fsString || storeType==fsObject;
|
||||
}
|
||||
|
||||
|
||||
Dynamic CppiaVar::getStaticValue()
|
||||
{
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: return *(unsigned char *)(valPointer);
|
||||
case fsBool: return *(bool *)(valPointer);
|
||||
case fsInt: return *(int *)(valPointer);
|
||||
case fsFloat: return *(Float *)(valPointer);
|
||||
case fsString: return *(String *)(valPointer);
|
||||
case fsObject: return *(hx::Object **)(valPointer);
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
Dynamic CppiaVar::setStaticValue(Dynamic inValue)
|
||||
{
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: *(unsigned char *)(valPointer) = inValue; return inValue;
|
||||
case fsBool: *(bool *)(valPointer) = inValue; return inValue;
|
||||
case fsInt: *(int *)(valPointer) = inValue; return inValue;
|
||||
case fsFloat: *(Float *)(valPointer) = inValue; return inValue;
|
||||
case fsString: *(String *)(valPointer) = inValue; return inValue;
|
||||
case fsObject: *(hx::Object **)(valPointer) = inValue.mPtr; return inValue;
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
CppiaExpr *CppiaVar::createAccess(CppiaExpr *inSrc)
|
||||
{
|
||||
if (valPointer)
|
||||
return createStaticAccess(inSrc, storeType, valPointer);
|
||||
if (isVirtual)
|
||||
throw "Direct access to extern field";
|
||||
//throw "Unlinked static variable";
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CppiaVar::linkVarTypes(CppiaModule &cppia, int &ioOffset)
|
||||
{
|
||||
DBGLOG("linkVarTypes %p\n",dynamicFunction);
|
||||
if (dynamicFunction)
|
||||
{
|
||||
//dynamicFunction->linkTypes(cppia);
|
||||
nameId = dynamicFunction->nameId;
|
||||
}
|
||||
type = cppia.types[typeId];
|
||||
if (!isVirtual)
|
||||
{
|
||||
exprType = typeId==0 ? etObject : type->expressionType;
|
||||
AlignOffset(exprType, ioOffset);
|
||||
offset = ioOffset;
|
||||
|
||||
switch(exprType)
|
||||
{
|
||||
case etInt: ioOffset += sizeof(int); storeType=fsInt; break;
|
||||
case etFloat: ioOffset += sizeof(Float);storeType=fsFloat; break;
|
||||
case etString: ioOffset += sizeof(String);storeType=fsString; break;
|
||||
case etObject: ioOffset += sizeof(hx::Object *);storeType=fsObject; break;
|
||||
case etVoid:
|
||||
case etNull:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaVar::createDynamic(hx::Object *inBase)
|
||||
{
|
||||
*(hx::Object **)((char *)inBase+offset) = createMemberClosure(inBase,(ScriptCallable*)dynamicFunction->funExpr);
|
||||
}
|
||||
|
||||
|
||||
Dynamic CppiaVar::getValue(hx::Object *inThis)
|
||||
{
|
||||
char *base = ((char *)inThis) + offset;
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: return *(unsigned char *)(base);
|
||||
case fsInt: return *(int *)(base);
|
||||
case fsBool: return *(bool *)(base);
|
||||
case fsFloat: return *(Float *)(base);
|
||||
case fsString: return *(String *)(base);
|
||||
case fsObject: return *(hx::Object **)(base);
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
Dynamic CppiaVar::setValue(hx::Object *inThis, Dynamic inValue)
|
||||
{
|
||||
char *base = ((char *)inThis) + offset;
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: *(unsigned char *)(base) = inValue; return inValue;
|
||||
case fsInt: *(int *)(base) = inValue; return inValue;
|
||||
case fsBool: *(bool *)(base) = inValue; return inValue;
|
||||
case fsFloat: *(Float *)(base) = inValue; return inValue;
|
||||
case fsString: *(String *)(base) = inValue; return inValue;
|
||||
case fsObject:
|
||||
switch(type->arrayType)
|
||||
{
|
||||
case arrNotArray:
|
||||
*(hx::Object **)(base) = inValue.mPtr;
|
||||
break;
|
||||
case arrBool:
|
||||
*(Array<bool> *)(base) = inValue;
|
||||
break;
|
||||
case arrInt:
|
||||
*(Array<int> *)(base) = inValue;
|
||||
break;
|
||||
case arrFloat:
|
||||
*(Array<Float> *)(base) = inValue;
|
||||
break;
|
||||
case arrFloat32:
|
||||
*(Array<float> *)(base) = inValue;
|
||||
break;
|
||||
case arrUnsignedChar:
|
||||
*(Array<unsigned char> *)(base) = inValue;
|
||||
break;
|
||||
case arrString:
|
||||
*(Array<String> *)(base) = inValue;
|
||||
break;
|
||||
case arrAny:
|
||||
#if (HXCPP_API_LEVEL>=330)
|
||||
(*(cpp::VirtualArray *)base).setDynamic(inValue);
|
||||
break;
|
||||
#else
|
||||
// Fallthrough
|
||||
#endif
|
||||
case arrObject:
|
||||
*(Array<Dynamic> *)(base) = inValue;
|
||||
break;
|
||||
}
|
||||
return inValue;
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
void CppiaVar::link(CppiaModule &inModule)
|
||||
{
|
||||
if (dynamicFunction)
|
||||
dynamicFunction->link();
|
||||
type = inModule.types[typeId];
|
||||
exprType = typeId==0 ? etObject : type->expressionType;
|
||||
name = inModule.strings[nameId];
|
||||
|
||||
if (init)
|
||||
init = init->link(inModule);
|
||||
}
|
||||
|
||||
CppiaVar::Access CppiaVar::getAccess(CppiaStream &stream)
|
||||
{
|
||||
std::string tok = stream.getToken();
|
||||
if (tok.size()!=1)
|
||||
throw "bad var access length";
|
||||
switch(tok[0])
|
||||
{
|
||||
case 'N': return accNormal;
|
||||
case 'n': return accNo;
|
||||
case 'R': return accResolve;
|
||||
case 'C': return accCall;
|
||||
case 'V': return accCallNative;
|
||||
}
|
||||
throw "bad access code";
|
||||
return accNormal;
|
||||
}
|
||||
|
||||
void CppiaVar::runInit(CppiaCtx *ctx)
|
||||
{
|
||||
if (isStatic)
|
||||
{
|
||||
if (dynamicFunction)
|
||||
objVal = createMemberClosure(0,(ScriptCallable*)dynamicFunction->funExpr);
|
||||
else if (init)
|
||||
switch(storeType)
|
||||
{
|
||||
case fsBool: boolVal = init->runInt(ctx); break;
|
||||
case fsByte: byteVal = init->runInt(ctx); break;
|
||||
case fsInt: intVal = init->runInt(ctx); break;
|
||||
case fsFloat: floatVal = init->runFloat(ctx); break;
|
||||
case fsString: stringVal = init->runString(ctx); break;
|
||||
case fsObject: objVal = init->runObject(ctx); break;
|
||||
case fsUnknown: ; // ?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaVar::mark(hx::MarkContext *__inCtx)
|
||||
{
|
||||
HX_MARK_MEMBER(stringVal);
|
||||
HX_MARK_MEMBER(objVal);
|
||||
HX_MARK_MEMBER(name);
|
||||
}
|
||||
void CppiaVar::visit(hx::VisitContext *__inCtx)
|
||||
{
|
||||
HX_VISIT_MEMBER(stringVal);
|
||||
HX_VISIT_MEMBER(objVal);
|
||||
HX_VISIT_MEMBER(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --- CppiaStackVar ----
|
||||
|
||||
|
||||
std::map<int,int> sVarIdNameMap;
|
||||
|
||||
|
||||
int getStackVarNameId(int inVarId)
|
||||
{
|
||||
return sVarIdNameMap[inVarId];
|
||||
}
|
||||
|
||||
|
||||
|
||||
CppiaStackVar::CppiaStackVar()
|
||||
{
|
||||
nameId = 0;
|
||||
id = 0;
|
||||
capture = false;
|
||||
typeId = 0;
|
||||
defaultStackPos = -1;
|
||||
stackPos = 0;
|
||||
fromStackPos = 0;
|
||||
capturePos = 0;
|
||||
expressionType = etNull;
|
||||
argType = expressionType;
|
||||
storeType = fsUnknown;
|
||||
type = 0;
|
||||
module = 0;
|
||||
}
|
||||
|
||||
CppiaStackVar::CppiaStackVar(CppiaStackVar *inVar,int &ioSize, int &ioCaptureSize)
|
||||
{
|
||||
nameId = inVar->nameId;
|
||||
id = inVar->id;
|
||||
sVarIdNameMap[id] = nameId;
|
||||
capture = inVar->capture;
|
||||
typeId = inVar->typeId;
|
||||
type = inVar->type;
|
||||
expressionType = inVar->expressionType;
|
||||
argType = expressionType;
|
||||
defaultStackPos = -1;
|
||||
|
||||
fromStackPos = inVar->stackPos;
|
||||
storeType = inVar->storeType;
|
||||
stackPos = ioSize;
|
||||
capturePos = ioCaptureSize;
|
||||
ioSize += sTypeSize[expressionType];
|
||||
ioCaptureSize += sTypeSize[expressionType];
|
||||
module = inVar->module;
|
||||
}
|
||||
|
||||
|
||||
void CppiaStackVar::fromStream(CppiaStream &stream)
|
||||
{
|
||||
nameId = stream.getInt();
|
||||
id = stream.getInt();
|
||||
capture = stream.getBool();
|
||||
typeId = stream.getInt();
|
||||
}
|
||||
|
||||
void CppiaStackVar::setInFrame(unsigned char *inFrame,Dynamic inValue)
|
||||
{
|
||||
unsigned char *ptr = inFrame + stackPos;
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte:
|
||||
*(int *)(ptr) = (unsigned char)inValue;
|
||||
break;
|
||||
case fsBool:
|
||||
*(int *)(ptr) = (bool)inValue;
|
||||
break;
|
||||
case fsInt:
|
||||
*(int *)(ptr) = inValue;
|
||||
break;
|
||||
case fsFloat:
|
||||
SetFloatAligned(ptr,inValue);
|
||||
break;
|
||||
case fsString:
|
||||
*(String *)(ptr) = inValue;
|
||||
break;
|
||||
case fsObject:
|
||||
*(hx::Object **)(ptr) = inValue.mPtr;
|
||||
break;
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaStackVar::set(CppiaCtx *inCtx,Dynamic inValue)
|
||||
{
|
||||
setInFrame( inCtx->frame, inValue );
|
||||
}
|
||||
|
||||
|
||||
Dynamic CppiaStackVar::getInFrame(const unsigned char *inFrame)
|
||||
{
|
||||
const unsigned char *ptr = inFrame + stackPos;
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: return (unsigned char) *(int *)ptr;
|
||||
case fsBool: return (bool) *(int *)ptr;
|
||||
case fsInt: return *(int *)ptr;
|
||||
case fsFloat: return *(Float *)ptr;
|
||||
case fsString: return *(String *)ptr;
|
||||
case fsObject: return *(hx::Object **)ptr;
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
void CppiaStackVar::markClosure(char *inBase, hx::MarkContext *__inCtx)
|
||||
{
|
||||
switch(storeType)
|
||||
{
|
||||
case fsString:
|
||||
HX_MARK_MEMBER(*(String *)(inBase + capturePos));
|
||||
break;
|
||||
case fsObject:
|
||||
HX_MARK_MEMBER(*(hx::Object **)(inBase + capturePos));
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaStackVar::visitClosure(char *inBase, hx::VisitContext *__inCtx)
|
||||
{
|
||||
switch(storeType)
|
||||
{
|
||||
case fsString:
|
||||
HX_VISIT_MEMBER(*(String *)(inBase + capturePos));
|
||||
break;
|
||||
case fsObject:
|
||||
HX_VISIT_MEMBER(*(hx::Object **)(inBase + capturePos));
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaStackVar::link(CppiaModule &inModule, bool hasDefault)
|
||||
{
|
||||
expressionType = inModule.types[typeId]->expressionType;
|
||||
argType = hasDefault ? ( expressionType==etString ? etString : etObject) : expressionType;
|
||||
storeType = typeId==0 ? fsObject : fieldStorageFromType(inModule.types[typeId]);
|
||||
if (inModule.layout)
|
||||
{
|
||||
inModule.layout->varMap[id] = this;
|
||||
stackPos = inModule.layout->size;
|
||||
inModule.layout->size += sTypeSize[argType];
|
||||
}
|
||||
else
|
||||
{
|
||||
stackPos = -1;
|
||||
storeType = fsUnknown;
|
||||
}
|
||||
type = inModule.types[typeId];
|
||||
defaultStackPos =stackPos;
|
||||
module = &inModule;
|
||||
}
|
||||
|
||||
|
||||
void CppiaStackVar::linkDefault()
|
||||
{
|
||||
if (expressionType==etFloat && sizeof(double)>sizeof(hx::Object *) )
|
||||
{
|
||||
stackPos = module->layout->size;
|
||||
module->layout->size += sTypeSize[expressionType];
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaStackVar::setDefault(CppiaCtx *inCxt, const CppiaConst &inDefault)
|
||||
{
|
||||
if (argType==etString)
|
||||
{
|
||||
if (inDefault.type == CppiaConst::cString)
|
||||
{
|
||||
String *s = (String *)(inCxt->frame + defaultStackPos);
|
||||
if (!s->raw_ptr())
|
||||
*s = module->strings[ inDefault.ival ];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hx::Object *src = *(hx::Object **)(inCxt->frame + defaultStackPos);
|
||||
|
||||
if (src)
|
||||
{
|
||||
setInFrame(inCxt->frame, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *ptr = inCxt->frame + stackPos;
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: *(int *)ptr = (unsigned char)inDefault.ival; break;
|
||||
case fsBool: *(int *)ptr = (bool)inDefault.ival; break;
|
||||
case fsInt: *(int *)ptr =
|
||||
inDefault.type==CppiaConst::cInt ? inDefault.ival :
|
||||
inDefault.dval;
|
||||
break;
|
||||
case fsFloat: *(Float *)ptr =
|
||||
inDefault.type==CppiaConst::cInt ? inDefault.ival :
|
||||
inDefault.dval;
|
||||
break;
|
||||
case fsObject:
|
||||
{
|
||||
Dynamic &d = *(Dynamic *)ptr;
|
||||
if (inDefault.type==CppiaConst::cInt)
|
||||
d = inDefault.ival;
|
||||
else if (inDefault.type==CppiaConst::cFloat)
|
||||
d = inDefault.dval;
|
||||
else if (inDefault.type==CppiaConst::cString)
|
||||
d = module->strings[ inDefault.ival ];
|
||||
}
|
||||
break;
|
||||
case fsString:
|
||||
case fsUnknown:
|
||||
break; // handled above, or not needed
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
|
||||
static int SLJIT_CALL objToInt(hx::Object *inVal)
|
||||
{
|
||||
return inVal->__ToInt();
|
||||
}
|
||||
static void SLJIT_CALL objToFloat(hx::Object *inVal,double *outFloat)
|
||||
{
|
||||
*outFloat = inVal->__ToDouble();
|
||||
}
|
||||
static hx::Object *SLJIT_CALL intToObject(int inVal)
|
||||
{
|
||||
return Dynamic(inVal).mPtr;
|
||||
}
|
||||
static hx::Object *SLJIT_CALL floatToObject(double * inVal)
|
||||
{
|
||||
return Dynamic(*inVal).mPtr;
|
||||
}
|
||||
static hx::Object *SLJIT_CALL stringToObject(String * inVal)
|
||||
{
|
||||
return Dynamic(*inVal).mPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CppiaStackVar::genDefault(CppiaCompiler *compiler, const CppiaConst &inDefault)
|
||||
{
|
||||
if (argType==etString)
|
||||
{
|
||||
if (inDefault.type == CppiaConst::cString)
|
||||
{
|
||||
JumpId notNull = compiler->compare(cmpP_NOT_ZERO, JitFramePos(defaultStackPos+StringOffset::Ptr).as(jtPointer),(void *)0);
|
||||
String val = module->strings[ inDefault.ival ];
|
||||
compiler->move(JitFramePos(defaultStackPos).as(jtInt), (int)val.length);
|
||||
compiler->move(JitFramePos(defaultStackPos+StringOffset::Ptr).as(jtPointer), (void *)val.raw_ptr());
|
||||
compiler->comeFrom(notNull);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JitFramePos srcPos(defaultStackPos);
|
||||
JitFramePos destPos(stackPos);
|
||||
compiler->move( sJitTemp0, srcPos.as(jtPointer) );
|
||||
JumpId notNull = compiler->compare(cmpP_NOT_ZERO, sJitTemp0, (void *)0);
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte:
|
||||
compiler->move( destPos.as(jtByte), JitVal((int)(unsigned char)inDefault.ival));
|
||||
break;
|
||||
|
||||
case fsBool:
|
||||
compiler->move( destPos.as(jtByte), JitVal((int)(bool)inDefault.ival));
|
||||
break;
|
||||
|
||||
case fsInt:
|
||||
compiler->move( destPos.as(jtInt), inDefault.ival);
|
||||
break;
|
||||
case fsFloat:
|
||||
compiler->move( sJitTemp0, (void *)&inDefault.dval);
|
||||
compiler->move( destPos.as(jtFloat), sJitTemp0.star(jtFloat));
|
||||
break;
|
||||
case fsObject:
|
||||
if (inDefault.type==CppiaConst::cInt)
|
||||
compiler->callNative( (void *)intToObject, inDefault.ival );
|
||||
else if (inDefault.type==CppiaConst::cFloat)
|
||||
compiler->callNative( (void *)floatToObject, (void *)&inDefault.dval );
|
||||
else if (inDefault.type==CppiaConst::cString)
|
||||
compiler->callNative( (void *)stringToObject, (void *)&module->strings[ inDefault.ival ] );
|
||||
else
|
||||
break;
|
||||
compiler->move(destPos.as(jtPointer), sJitReturnReg.as(jtPointer));
|
||||
break;
|
||||
case fsString: // handled
|
||||
case fsUnknown: // ?
|
||||
break;
|
||||
}
|
||||
|
||||
JumpId defaultDone = compiler->jump();
|
||||
compiler->comeFrom(notNull);
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte:
|
||||
case fsBool:
|
||||
//Fallthough...
|
||||
//compiler->callNative( (void *)objToInt, sJitTemp0.as(jtPointer) );
|
||||
//compiler->move( destPos.as(jtByte), sJitReturnReg.as(jtByte));
|
||||
//compiler->move( destPos.as(jtInt), sJitReturnReg.as(jtInt));
|
||||
//break;
|
||||
|
||||
case fsInt:
|
||||
compiler->callNative( (void *)objToInt, sJitTemp0.as(jtPointer) );
|
||||
compiler->move( destPos.as(jtInt), sJitReturnReg.as(jtInt));
|
||||
break;
|
||||
case fsFloat:
|
||||
compiler->callNative( (void *)objToFloat, sJitTemp0.as(jtPointer), destPos.as(jtFloat)) ;
|
||||
break;
|
||||
case fsObject:
|
||||
// Should be same pos
|
||||
//compiler->move(destPos.as(jtPointer), sJitTemp0.as(jtPointer));
|
||||
break;
|
||||
case fsString: // handled
|
||||
case fsUnknown: // ?
|
||||
break;
|
||||
}
|
||||
|
||||
compiler->comeFrom(defaultDone);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
400
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/GlobalBuiltin.cpp
Normal file
400
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/GlobalBuiltin.cpp
Normal file
@ -0,0 +1,400 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
template<> inline Array<unsigned char> &runValue(Array<unsigned char> &outValue, CppiaCtx *ctx, CppiaExpr *expr)
|
||||
{
|
||||
outValue.mPtr = (Array_obj<unsigned char>*) expr->runObject(ctx);
|
||||
return outValue;
|
||||
}
|
||||
|
||||
|
||||
template<typename ARG0, int (*FUNC)(ARG0 arg0)>
|
||||
class IntBuiltin1 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
IntBuiltin1(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "IntBuiltin1"; }
|
||||
ExprType getType() { return etInt; }
|
||||
|
||||
void runVoid(CppiaCtx *ctx) { runInt(ctx); }
|
||||
Float runFloat(CppiaCtx *ctx) { return runInt(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runInt(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runInt(ctx)); }
|
||||
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, int (*FUNC)(ARG0 arg0, ARG1 arg1)>
|
||||
class IntBuiltin2 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
IntBuiltin2(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "IntBuiltin2"; }
|
||||
ExprType getType() { return etInt; }
|
||||
|
||||
void runVoid(CppiaCtx *ctx) { runInt(ctx); }
|
||||
Float runFloat(CppiaCtx *ctx) { return runInt(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runInt(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runInt(ctx)); }
|
||||
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0,val1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename ARG0, void (*FUNC)(ARG0)>
|
||||
class VoidBuiltin1 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
VoidBuiltin1(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "VoidBuiltin1"; }
|
||||
ExprType getType() { return etVoid; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
Float runFloat(CppiaCtx *ctx) { runVoid(ctx); return 0;}
|
||||
hx::Object *runObject(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
String runString(CppiaCtx *ctx) { runVoid(ctx); return String(); }
|
||||
void runVoid(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_VCHECK;
|
||||
FUNC(val0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, void (*FUNC)(ARG0,ARG1)>
|
||||
class VoidBuiltin2 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
VoidBuiltin2(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "VoidBuiltin2"; }
|
||||
ExprType getType() { return etVoid; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
Float runFloat(CppiaCtx *ctx) { runVoid(ctx); return 0;}
|
||||
hx::Object *runObject(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
String runString(CppiaCtx *ctx) { runVoid(ctx); return String(); }
|
||||
void runVoid(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_VCHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_VCHECK;
|
||||
FUNC(val0,val1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, typename ARG2, void (*FUNC)(ARG0,ARG1,ARG2)>
|
||||
class VoidBuiltin3 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
VoidBuiltin3(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "VoidBuiltin3"; }
|
||||
ExprType getType() { return etVoid; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
Float runFloat(CppiaCtx *ctx) { runVoid(ctx); return 0;}
|
||||
hx::Object *runObject(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
String runString(CppiaCtx *ctx) { runVoid(ctx); return String(); }
|
||||
void runVoid(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_VCHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_VCHECK;
|
||||
ARG2 val2;
|
||||
runValue(val2, ctx, args[2]);
|
||||
BCR_VCHECK;
|
||||
FUNC(val0,val1,val2);
|
||||
}
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static void SLJIT_CALL setFloat(Array_obj<unsigned char> *inBuffer, int inAddr, double *inValue)
|
||||
{
|
||||
if (sizeof(ARG2)==sizeof(float))
|
||||
__hxcpp_memory_set_float(inBuffer,inAddr,*inValue);
|
||||
else
|
||||
__hxcpp_memory_set_double(inBuffer,inAddr,*inValue);
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp obj(compiler,jtPointer);
|
||||
args[0]->genCode(compiler, obj, etObject);
|
||||
|
||||
JitTemp addr(compiler,jtInt);
|
||||
args[1]->genCode(compiler, addr, etInt);
|
||||
|
||||
JitTemp val(compiler,jtFloat);
|
||||
args[2]->genCode(compiler, val, etFloat);
|
||||
|
||||
compiler->callNative( (void *)setFloat, obj, addr, val );
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename RET, RET (*FUNC)()>
|
||||
class FloatBuiltin0 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
FloatBuiltin0(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "FloatBuiltin0"; }
|
||||
ExprType getType() { return etFloat; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { return runFloat(ctx); }
|
||||
void runVoid(CppiaCtx *ctx) { runFloat(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runFloat(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runFloat(ctx)); }
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
return FUNC();
|
||||
}
|
||||
#ifdef CPPIA_JIT
|
||||
static void SLJIT_CALL run(double *outResult)
|
||||
{
|
||||
*outResult = FUNC();
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
if (destType==etFloat && isMemoryVal(inDest) )
|
||||
{
|
||||
compiler->callNative( (void *)run, inDest.as(jtFloat));
|
||||
}
|
||||
else
|
||||
{
|
||||
JitTemp temp(compiler,jtFloat);
|
||||
compiler->callNative( (void *)run, temp);
|
||||
compiler->convert(temp, etFloat, inDest, destType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename ARG0, typename RET, RET (*FUNC)(ARG0)>
|
||||
class FloatBuiltin1 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
FloatBuiltin1(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "FloatBuiltin1"; }
|
||||
ExprType getType() { return etFloat; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { return runFloat(ctx); }
|
||||
void runVoid(CppiaCtx *ctx) { runFloat(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runFloat(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runFloat(ctx)); }
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, typename RET, RET (*FUNC)(ARG0,ARG1)>
|
||||
class FloatBuiltin2 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
FloatBuiltin2(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "FloatBuiltin2"; }
|
||||
ExprType getType() { return etFloat; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { return runFloat(ctx); }
|
||||
void runVoid(CppiaCtx *ctx) { runFloat(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runFloat(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runFloat(ctx)); }
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0,val1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, typename ARG2, typename RET, RET (*FUNC)(ARG0,ARG1,ARG2)>
|
||||
class FloatBuiltin3 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
FloatBuiltin3(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "FloatBuiltin3"; }
|
||||
ExprType getType() { return etFloat; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { return runFloat(ctx); }
|
||||
void runVoid(CppiaCtx *ctx) { runFloat(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runFloat(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runFloat(ctx)); }
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_CHECK;
|
||||
ARG2 val2;
|
||||
runValue(val2, ctx, args[2]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0,val1,val2);
|
||||
}
|
||||
};
|
||||
|
||||
#define MEMORY_INT(GETTER,SETTER) \
|
||||
if (function==HX_CSTRING( #GETTER ) ) \
|
||||
{ \
|
||||
if (ioExpressions.size()==1) \
|
||||
return new IntBuiltin1<int, GETTER>(src,ioExpressions); \
|
||||
return new IntBuiltin2<Array<unsigned char>, int, GETTER>(src,ioExpressions); \
|
||||
} \
|
||||
if (function==HX_CSTRING( #SETTER ) ) \
|
||||
{ \
|
||||
if (ioExpressions.size()==2) \
|
||||
return new VoidBuiltin2<int,int, SETTER>(src,ioExpressions); \
|
||||
return new VoidBuiltin3<Array<unsigned char>,int,int,SETTER>(src,ioExpressions); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename ARG0, typename RET, RET (*FUNC)(ARG0)>
|
||||
class ObjectBuiltin1 : public CppiaDynamicExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
ObjectBuiltin1(CppiaExpr *inSrc, Expressions &inArgs) : CppiaDynamicExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "ObjectBuiltin1"; }
|
||||
ExprType getType() { return etObject; }
|
||||
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0).mPtr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
CppiaExpr *createGlobalBuiltin(CppiaExpr *src, String function, Expressions &ioExpressions )
|
||||
{
|
||||
MEMORY_INT(__hxcpp_memory_get_byte, __hxcpp_memory_set_byte);
|
||||
MEMORY_INT(__hxcpp_memory_get_i32, __hxcpp_memory_set_i32);
|
||||
MEMORY_INT(__hxcpp_memory_get_ui32, __hxcpp_memory_set_ui32);
|
||||
MEMORY_INT(__hxcpp_memory_get_i16, __hxcpp_memory_set_i16);
|
||||
MEMORY_INT(__hxcpp_memory_get_ui16, __hxcpp_memory_set_ui16);
|
||||
|
||||
if (function==HX_CSTRING("__hxcpp_memory_get_float") )
|
||||
{
|
||||
if (ioExpressions.size()==1)
|
||||
return new FloatBuiltin1<int,float,__hxcpp_memory_get_float>(src,ioExpressions);
|
||||
return new FloatBuiltin2<Array<unsigned char>,int,float,__hxcpp_memory_get_float>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__hxcpp_memory_set_float") )
|
||||
{
|
||||
if (ioExpressions.size()==2)
|
||||
return new VoidBuiltin2<int,float,__hxcpp_memory_set_float>(src,ioExpressions);
|
||||
return new VoidBuiltin3<Array<unsigned char>,int,float,__hxcpp_memory_set_float>(src,ioExpressions);
|
||||
}
|
||||
|
||||
if (function==HX_CSTRING("__hxcpp_memory_get_double") )
|
||||
{
|
||||
if (ioExpressions.size()==1)
|
||||
return new FloatBuiltin1<int,double,__hxcpp_memory_get_double>(src,ioExpressions);
|
||||
return new FloatBuiltin2<Array<unsigned char>,int,double,__hxcpp_memory_get_double>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__hxcpp_memory_set_double") )
|
||||
{
|
||||
if (ioExpressions.size()==2)
|
||||
return new VoidBuiltin2<int,double,__hxcpp_memory_set_double>(src,ioExpressions);
|
||||
return new VoidBuiltin3<Array<unsigned char>,int,double,__hxcpp_memory_set_double>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__time_stamp") )
|
||||
{
|
||||
if (ioExpressions.size()==0)
|
||||
return new FloatBuiltin0<double,__time_stamp>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__hxcpp_thread_create") )
|
||||
{
|
||||
if (ioExpressions.size()==1)
|
||||
return new ObjectBuiltin1<Dynamic,Dynamic,__hxcpp_thread_create>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__hxcpp_thread_send") )
|
||||
{
|
||||
if (ioExpressions.size()==2)
|
||||
return new VoidBuiltin2<Dynamic,Dynamic,__hxcpp_thread_send>(src,ioExpressions);
|
||||
}
|
||||
|
||||
|
||||
printf("Unknown function : %s(%d)\n", function.out_str(), (int)ioExpressions.size() );
|
||||
throw (HX_CSTRING("Unknown global:") + function).utf8_str();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
223
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/HaxeNative.cpp
Normal file
223
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/HaxeNative.cpp
Normal file
@ -0,0 +1,223 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/Scriptable.h>
|
||||
#include "Cppia.h"
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
typedef std::map<std::string, HaxeNativeClass *> ScriptRegisteredMap;
|
||||
static ScriptRegisteredMap *sScriptRegistered = 0;
|
||||
|
||||
typedef std::map<std::string, HaxeNativeInterface *> HaxeNativeIntefaceMap;
|
||||
static HaxeNativeIntefaceMap *sScriptRegisteredInterface = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// -- HaxeNativeClass ---
|
||||
|
||||
HaxeNativeClass::HaxeNativeClass(const std::string &inName, int inDataOffset, ScriptNamedFunction *inFunctions, hx::ScriptableClassFactory inFactory, ScriptNamedFunction inConstruct)
|
||||
{
|
||||
name = inName;
|
||||
mDataOffset = inDataOffset;
|
||||
functions = inFunctions;
|
||||
factory = inFactory;
|
||||
construct = inConstruct;
|
||||
haxeSuper = 0;
|
||||
}
|
||||
|
||||
void HaxeNativeClass::addVtableEntries( std::vector<std::string> &outVtable)
|
||||
{
|
||||
if (haxeSuper)
|
||||
haxeSuper->addVtableEntries(outVtable);
|
||||
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *func = functions; func->name; func++)
|
||||
if (!func->isStatic)
|
||||
outVtable.push_back( func->name );
|
||||
}
|
||||
|
||||
void HaxeNativeClass::dump()
|
||||
{
|
||||
printf("HaxeNativeClass %s\n", name.c_str());
|
||||
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *f=functions;f->name;f++)
|
||||
printf(" %s func %s\n", f->isStatic ? "static" : "virtual", f->name );
|
||||
if (haxeSuper)
|
||||
{
|
||||
printf("super:\n");
|
||||
haxeSuper->dump();
|
||||
}
|
||||
}
|
||||
|
||||
ScriptNamedFunction HaxeNativeClass::findFunction(const std::string &inName)
|
||||
{
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *f=functions;f->name;f++)
|
||||
if (inName == f->name && !f->isStatic)
|
||||
return *f;
|
||||
if (haxeSuper)
|
||||
return haxeSuper->findFunction(inName);
|
||||
|
||||
return ScriptNamedFunction(0,0,0,0,0);
|
||||
}
|
||||
|
||||
|
||||
ScriptNamedFunction HaxeNativeClass::findStaticFunction(String inName)
|
||||
{
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *f=functions;f->name;f++)
|
||||
if ( !strcmp(inName.utf8_str(),f->name) && f->isStatic)
|
||||
return *f;
|
||||
|
||||
return ScriptNamedFunction(0,0,0,0,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
HaxeNativeClass *HaxeNativeClass::findClass(const std::string &inName)
|
||||
{
|
||||
return sScriptRegistered ? (*sScriptRegistered)[inName] : 0;
|
||||
}
|
||||
|
||||
HaxeNativeClass *HaxeNativeClass::hxObject()
|
||||
{
|
||||
return sScriptRegistered ? (*sScriptRegistered)["hx.Object"] : 0;
|
||||
}
|
||||
|
||||
void HaxeNativeClass::link()
|
||||
{
|
||||
HaxeNativeClass *hxObj = hxObject();
|
||||
for(ScriptRegisteredMap::iterator i = sScriptRegistered->begin(); i!=sScriptRegistered->end();++i)
|
||||
{
|
||||
if (!i->second)
|
||||
continue;
|
||||
|
||||
DBGLOG("== %s ==\n", i->first.c_str());
|
||||
if (i->second == hxObj)
|
||||
{
|
||||
DBGLOG(" super =0\n");
|
||||
continue;
|
||||
}
|
||||
hx::Class cls = hx::Class_obj::Resolve( String(i->first.c_str() ) );
|
||||
if (cls.mPtr)
|
||||
{
|
||||
hx::Class superClass = cls->GetSuper();
|
||||
if (superClass.mPtr)
|
||||
{
|
||||
HaxeNativeClass *superRef = (*sScriptRegistered)[superClass.mPtr->mName.utf8_str()];
|
||||
if (superRef)
|
||||
{
|
||||
DBGLOG("registered %s\n",superClass.mPtr->mName.utf8_str());
|
||||
i->second->haxeSuper = superRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBGLOG("haxe super = %p\n", i->second->haxeSuper);
|
||||
if (!i->second->haxeSuper)
|
||||
{
|
||||
DBGLOG("using hx.Object\n");
|
||||
i->second->haxeSuper = hxObj;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -- HaxeNativeInterface ---
|
||||
|
||||
|
||||
ScriptFunction HaxeNativeInterface::findFunction(const std::string &inName)
|
||||
{
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *f=functions;f->name;f++)
|
||||
if (inName == f->name)
|
||||
return *f;
|
||||
//if (haxeSuper)
|
||||
// return haxeSuper->findFunction(inName);
|
||||
|
||||
return ScriptFunction(0,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ScriptableRegisterClass( String inName, int inDataOffset, ScriptNamedFunction *inFunctions, hx::ScriptableClassFactory inFactory, hx::ScriptFunction inConstruct)
|
||||
{
|
||||
DBGLOG("ScriptableRegisterClass %s\n", inName.out_str());
|
||||
if (!sScriptRegistered)
|
||||
sScriptRegistered = new ScriptRegisteredMap();
|
||||
HaxeNativeClass *registered = new HaxeNativeClass(inName.utf8_str(),inDataOffset, inFunctions,inFactory, inConstruct);
|
||||
(*sScriptRegistered)[inName.utf8_str()] = registered;
|
||||
//printf("Registering %s -> %p\n",inName.out_str(),(*sScriptRegistered)[inName.utf8_str()]);
|
||||
}
|
||||
|
||||
|
||||
#if (HXCPP_API_LEVEL >= 330)
|
||||
|
||||
HaxeNativeInterface::HaxeNativeInterface(const std::string &inName,
|
||||
ScriptNamedFunction *inFunctions,
|
||||
void *inScriptTable )
|
||||
{
|
||||
name = inName;
|
||||
functions = inFunctions;
|
||||
scriptTable = inScriptTable;
|
||||
}
|
||||
|
||||
void ScriptableRegisterInterface( String inName,
|
||||
ScriptNamedFunction *inFunctions,
|
||||
void *inScriptTable)
|
||||
{
|
||||
DBGLOG("ScriptableInterfaceFactory %s\n",inName.out_str());
|
||||
if (!sScriptRegisteredInterface)
|
||||
sScriptRegisteredInterface = new HaxeNativeIntefaceMap();
|
||||
|
||||
HaxeNativeInterface *registered = new HaxeNativeInterface(inName.utf8_str(), inFunctions, inScriptTable);
|
||||
(*sScriptRegisteredInterface)[inName.utf8_str()] = registered;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
HaxeNativeInterface::HaxeNativeInterface(const std::string &inName,
|
||||
ScriptNamedFunction *inFunctions,
|
||||
hx::ScriptableInterfaceFactory inFactory,
|
||||
const hx::type_info *inType)
|
||||
{
|
||||
functions = inFunctions;
|
||||
factory = inFactory;
|
||||
name = inName;
|
||||
mType = inType;
|
||||
}
|
||||
|
||||
void ScriptableRegisterInterface( String inName,
|
||||
ScriptNamedFunction *inFunctions,
|
||||
const hx::type_info *inType,
|
||||
hx::ScriptableInterfaceFactory inFactory )
|
||||
{
|
||||
DBGLOG("ScriptableInterfaceFactory %s\n",inName.out_str());
|
||||
if (!sScriptRegisteredInterface)
|
||||
sScriptRegisteredInterface = new HaxeNativeIntefaceMap();
|
||||
|
||||
HaxeNativeInterface *registered = new HaxeNativeInterface(inName.utf8_str(), inFunctions, inFactory,inType);
|
||||
(*sScriptRegisteredInterface)[inName.utf8_str()] = registered;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
HaxeNativeInterface *HaxeNativeInterface::findInterface(const std::string &inName)
|
||||
{
|
||||
return sScriptRegisteredInterface ? (*sScriptRegisteredInterface)[inName] : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
472
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/StringBuiltin.cpp
Normal file
472
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/StringBuiltin.cpp
Normal file
@ -0,0 +1,472 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
struct StringExpr : public CppiaExpr
|
||||
{
|
||||
CppiaExpr *strVal;
|
||||
StringExpr(CppiaExpr *inSrc, CppiaExpr *inThis )
|
||||
: CppiaExpr(inSrc)
|
||||
{
|
||||
strVal = inThis;
|
||||
}
|
||||
ExprType getType() { return etString; }
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
strVal = strVal->link(inData);
|
||||
return this;
|
||||
}
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
return Dynamic(runString(ctx)).mPtr;
|
||||
}
|
||||
};
|
||||
|
||||
template<bool SUBSTR>
|
||||
struct SubStrExpr : public StringExpr
|
||||
{
|
||||
CppiaExpr *a0;
|
||||
CppiaExpr *a1;
|
||||
SubStrExpr(CppiaExpr *inSrc, CppiaExpr *inThis, CppiaExpr *inA0, CppiaExpr *inA1)
|
||||
: StringExpr(inSrc,inThis)
|
||||
{
|
||||
a0 = inA0;
|
||||
a1 = inA1;
|
||||
}
|
||||
const char *getName() { return "SubStrExpr"; }
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
a0 = a0->link(inData);
|
||||
a1 = a1->link(inData);
|
||||
return StringExpr::link(inData);
|
||||
}
|
||||
String runString(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
int start = a0->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic end = a1->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
if (SUBSTR)
|
||||
return val.substr(start,end);
|
||||
else
|
||||
return val.substring(start,end);
|
||||
}
|
||||
#ifdef CPPIA_JIT
|
||||
static void SLJIT_CALL runSubstr(String *ioValue, int start, hx::Object *end)
|
||||
{
|
||||
*ioValue = ioValue->substr(start, Dynamic(end));
|
||||
}
|
||||
static void SLJIT_CALL runSubstring(String *ioValue, int start, hx::Object *end)
|
||||
{
|
||||
*ioValue = ioValue->substring(start, Dynamic(end));
|
||||
}
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp ioValue(compiler,jtString);
|
||||
JitTemp startVal(compiler,jtInt);
|
||||
|
||||
strVal->genCode(compiler, ioValue, etString);
|
||||
a0->genCode(compiler, startVal, etInt);
|
||||
a1->genCode(compiler, sJitArg2, etObject);
|
||||
compiler->callNative( SUBSTR ? (void *)runSubstr : (void *)runSubstring, ioValue, startVal, sJitArg2.as(jtPointer) );
|
||||
compiler->convert(ioValue, etString, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<bool KEYS>
|
||||
struct StringIteratorExpr : public StringExpr
|
||||
{
|
||||
StringIteratorExpr(CppiaExpr *inSrc, CppiaExpr *inThis) : StringExpr(inSrc,inThis)
|
||||
{
|
||||
}
|
||||
const char *getName() { return "StringIteratorExpr"; }
|
||||
|
||||
ExprType getType() { return etObject; }
|
||||
|
||||
String runString(CppiaCtx *ctx) { return Dynamic(runObject(ctx)); }
|
||||
int runInt(CppiaCtx *ctx) { return 0; }
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
return ( KEYS ? val.keyValueIterator() : val.iterator() ).mPtr;
|
||||
}
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static hx::Object *SLJIT_CALL run(String *inValue)
|
||||
{
|
||||
return ( KEYS ? inValue->keyValueIterator() : inValue->iterator() ).mPtr;
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
strVal->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)run, value);
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<bool UPPER>
|
||||
struct ToCaseExpr : public StringExpr
|
||||
{
|
||||
const char *getName() { return "ToCaseExpr"; }
|
||||
ToCaseExpr(CppiaExpr *inSrc, CppiaExpr *inThis ) : StringExpr(inSrc,inThis) { }
|
||||
String runString(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
if (UPPER)
|
||||
return val.toUpperCase();
|
||||
else
|
||||
return val.toLowerCase();
|
||||
}
|
||||
#ifdef CPPIA_JIT
|
||||
static void SLJIT_CALL strToCase(String *ioVal)
|
||||
{
|
||||
if (UPPER)
|
||||
*ioVal = ioVal->toUpperCase();
|
||||
else
|
||||
*ioVal = ioVal->toLowerCase();
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
if (destType==etString)
|
||||
{
|
||||
strVal->genCode(compiler, inDest, destType);
|
||||
compiler->callNative( (void *)strToCase, inDest.as(jtString) );
|
||||
}
|
||||
else
|
||||
{
|
||||
JitTemp tmpVal(compiler,jtString);
|
||||
strVal->genCode(compiler, tmpVal, etString);
|
||||
compiler->callNative( (void *)strToCase, tmpVal);
|
||||
compiler->convert( tmpVal, etString, inDest, destType );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<bool CODE,bool AS_INT>
|
||||
struct CharAtExpr : public StringExpr
|
||||
{
|
||||
CppiaExpr *a0;
|
||||
|
||||
CharAtExpr(CppiaExpr *inSrc, CppiaExpr *inThis, CppiaExpr *inIndex ) : StringExpr(inSrc,inThis)
|
||||
{
|
||||
a0 = inIndex;
|
||||
}
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
a0 = a0->link(inData);
|
||||
return StringExpr::link(inData);
|
||||
}
|
||||
const char *getName() { return "CharAtExpr"; }
|
||||
ExprType getType() { return CODE ? (AS_INT ? etInt : etObject) : etString; }
|
||||
|
||||
String runString(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
int idx = a0->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
return val.charAt(idx);
|
||||
}
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
//printf("Char code at %d INT\n", CODE);
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
int idx = a0->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
|
||||
if (AS_INT)
|
||||
return (int)val.cca(idx);
|
||||
else
|
||||
return val.charCodeAt(idx);
|
||||
}
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
int idx = a0->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
|
||||
if (CODE)
|
||||
{
|
||||
if (AS_INT)
|
||||
return Dynamic( val.cca(idx) ).mPtr;
|
||||
else
|
||||
return val.charCodeAt(idx).mPtr;
|
||||
}
|
||||
else
|
||||
return Dynamic(val.charAt(idx)).mPtr;
|
||||
}
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static hx::Object *SLJIT_CALL runCharCodeAt(String *inValue, int inIndex)
|
||||
{
|
||||
return (inValue->charCodeAt(inIndex)).mPtr;
|
||||
}
|
||||
static int SLJIT_CALL runCca(String *inValue, int inIndex)
|
||||
{
|
||||
return (inValue->cca(inIndex));
|
||||
}
|
||||
static void SLJIT_CALL runCharAt(String *ioValue, int inIndex)
|
||||
{
|
||||
*ioValue = ioValue->charAt(inIndex);
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
strVal->genCode(compiler, value, etString);
|
||||
a0->genCode(compiler, sJitTemp1, etInt);
|
||||
|
||||
if (CODE)
|
||||
{
|
||||
if (AS_INT)
|
||||
{
|
||||
#ifdef HX_SMART_STRINGS
|
||||
compiler->callNative( (void *)runCca, value, sJitTemp1.as(jtInt));
|
||||
compiler->convertReturnReg( etInt, inDest, destType);
|
||||
#else
|
||||
// sJitTemp1 = __s
|
||||
compiler->move( sJitTemp0.as(jtPointer), value.star(jtPointer,offsetof(String,__s)) );
|
||||
if (destType==etInt)
|
||||
{
|
||||
compiler->move(inDest.as(jtInt), sJitTemp0.atReg(sJitTemp1,0,jtByte) );
|
||||
}
|
||||
else
|
||||
{
|
||||
compiler->move(sJitTemp0.as(jtInt), sJitTemp0.atReg(sJitTemp1,0,jtByte) );
|
||||
compiler->convertReturnReg(etInt, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
compiler->callNative( (void *)runCharCodeAt, value, sJitTemp1.as(jtInt));
|
||||
compiler->convertReturnReg( etObject, inDest, destType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
compiler->callNative( (void *)runCharAt, value, sJitTemp1.as(jtInt));
|
||||
compiler->convert(value, etString, inDest, destType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct SplitExpr : public CppiaExpr
|
||||
{
|
||||
CppiaExpr *strVal;
|
||||
CppiaExpr *a0;
|
||||
|
||||
SplitExpr(CppiaExpr *inSrc, CppiaExpr *inThis, CppiaExpr *inDelim ) :
|
||||
CppiaExpr(inSrc)
|
||||
{
|
||||
strVal = inThis;
|
||||
a0 = inDelim;
|
||||
}
|
||||
const char *getName() { return "SplitExpr"; }
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
strVal = strVal->link(inData);
|
||||
a0 = a0->link(inData);
|
||||
return this;
|
||||
}
|
||||
ExprType getType() { return etObject; }
|
||||
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
String separator = a0->runString(ctx);
|
||||
BCR_CHECK;
|
||||
return val.split(separator).mPtr;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static hx::Object *SLJIT_CALL runSplit(String *inValue, String *sep)
|
||||
{
|
||||
return (inValue->split(*sep)).mPtr;
|
||||
}
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
JitTemp sep(compiler,jtString);
|
||||
|
||||
strVal->genCode(compiler, value, etString);
|
||||
a0->genCode(compiler, sep, etString);
|
||||
compiler->callNative( (void *)runSplit, value, sep );
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<bool LAST>
|
||||
struct IndexOfExpr : public CppiaExpr
|
||||
{
|
||||
CppiaExpr *strVal;
|
||||
CppiaExpr *sought;
|
||||
CppiaExpr *start;
|
||||
|
||||
IndexOfExpr(CppiaExpr *inSrc, CppiaExpr *inThis, CppiaExpr *inSought, CppiaExpr *inStart ) :
|
||||
CppiaExpr(inSrc)
|
||||
{
|
||||
strVal = inThis;
|
||||
sought = inSought;
|
||||
start = inStart;
|
||||
}
|
||||
const char *getName() { return "IndexOfExpr"; }
|
||||
ExprType getType() { return etInt; }
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
strVal = strVal->link(inData);
|
||||
sought = sought->link(inData);
|
||||
start = start->link(inData);
|
||||
return this;
|
||||
}
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
return runInt(ctx);
|
||||
}
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
String s = sought->runString(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object *first = start->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
if (LAST)
|
||||
return val.lastIndexOf(s,first);
|
||||
else
|
||||
return val.indexOf(s,first);
|
||||
}
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runInt(ctx)).mPtr; }
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static int SLJIT_CALL runIndexOf(String *ioValue, String *sought, hx::Object *first)
|
||||
{
|
||||
return ioValue->indexOf(*sought, Dynamic(first));
|
||||
}
|
||||
static int SLJIT_CALL runLastIndexOf(String *ioValue, String *sought, hx::Object *first)
|
||||
{
|
||||
return ioValue->lastIndexOf(*sought, Dynamic(first));
|
||||
}
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
JitTemp soughtTemp(compiler,jtString);
|
||||
|
||||
strVal->genCode(compiler, value, etString);
|
||||
sought->genCode(compiler, soughtTemp, etString);
|
||||
start->genCode(compiler, sJitArg2, etObject);
|
||||
compiler->callNative( LAST ? (void *)runLastIndexOf : (void *)runIndexOf, value, soughtTemp, sJitArg2.as(jtPointer) );
|
||||
compiler->convertReturnReg(etInt, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// TODO
|
||||
// static function fromCharCode( code : Int ) : String;
|
||||
|
||||
|
||||
CppiaExpr *createStringBuiltin(CppiaExpr *inSrc, CppiaExpr *inThisExpr, String field, Expressions &ioExpressions )
|
||||
{
|
||||
if (field==HX_CSTRING("toString"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return inThisExpr;
|
||||
}
|
||||
else if (field==HX_CSTRING("toUpperCase"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return new ToCaseExpr<true>(inSrc,inThisExpr);
|
||||
}
|
||||
else if (field==HX_CSTRING("toLowerCase"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return new ToCaseExpr<false>(inSrc,inThisExpr);
|
||||
}
|
||||
else if (field==HX_CSTRING("charAt"))
|
||||
{
|
||||
if (ioExpressions.size()!=1) throw "Bad arg count";
|
||||
return new CharAtExpr<false,false>(inSrc,inThisExpr,ioExpressions[0]);
|
||||
}
|
||||
else if (field==HX_CSTRING("cca"))
|
||||
{
|
||||
if (ioExpressions.size()!=1) throw "Bad arg count";
|
||||
return new CharAtExpr<true,true>(inSrc,inThisExpr,ioExpressions[0]);
|
||||
}
|
||||
else if (field==HX_CSTRING("iterator"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return new StringIteratorExpr<false>(inSrc,inThisExpr);
|
||||
}
|
||||
else if (field==HX_CSTRING("keyValueIterator"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return new StringIteratorExpr<true>(inSrc,inThisExpr);
|
||||
}
|
||||
else if (field==HX_CSTRING("charCodeAt"))
|
||||
{
|
||||
if (ioExpressions.size()!=1) throw "Bad arg count";
|
||||
return new CharAtExpr<true,false>(inSrc,inThisExpr,ioExpressions[0]);
|
||||
}
|
||||
else if (field==HX_CSTRING("split"))
|
||||
{
|
||||
if (ioExpressions.size()!=1) throw "Bad arg count";
|
||||
return new SplitExpr(inSrc,inThisExpr,ioExpressions[0]);
|
||||
}
|
||||
else if (field==HX_CSTRING("indexOf"))
|
||||
{
|
||||
if (ioExpressions.size()!=2) throw "Bad arg count";
|
||||
return new IndexOfExpr<false>(inSrc,inThisExpr,ioExpressions[0], ioExpressions[1]);
|
||||
}
|
||||
else if (field==HX_CSTRING("lastIndexOf"))
|
||||
{
|
||||
if (ioExpressions.size()!=2) throw "Bad arg count";
|
||||
return new IndexOfExpr<true>(inSrc,inThisExpr,ioExpressions[0], ioExpressions[1]);
|
||||
}
|
||||
|
||||
else if (field==HX_CSTRING("substr"))
|
||||
{
|
||||
if (ioExpressions.size()!=2) throw "Bad arg count";
|
||||
return new SubStrExpr<true>(inSrc,inThisExpr, ioExpressions[0], ioExpressions[1]);
|
||||
}
|
||||
else if (field==HX_CSTRING("substring"))
|
||||
{
|
||||
if (ioExpressions.size()!=2) throw "Bad arg count";
|
||||
return new SubStrExpr<false>(inSrc,inThisExpr, ioExpressions[0], ioExpressions[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end namespace hx
|
||||
29
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/README
Normal file
29
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/README
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
SLJIT - Stack Less JIT Compiler
|
||||
|
||||
Purpose:
|
||||
A simple, machine independent JIT compiler, which suitable for
|
||||
translating interpreted byte code to machine code. The sljitLir.h
|
||||
describes the LIR (low-level intermediate representation) of SLJIT.
|
||||
|
||||
Compatible:
|
||||
Any C (C++) compiler. At least I hope so.
|
||||
|
||||
Using sljit:
|
||||
Copy the content of sljit_src directory into your project source directory.
|
||||
Add sljitLir.c source file to your build environment. All other files are
|
||||
included by sljitLir.c (if required). Define the machine by SLJIT_CONFIG_*
|
||||
selector. See sljitConfig.h for all possible values. For C++ compilers,
|
||||
rename sljitLir.c to sljitLir.cpp.
|
||||
|
||||
More info:
|
||||
http://sljit.sourceforge.net/
|
||||
|
||||
Contact:
|
||||
hzmester@freemail.hu
|
||||
|
||||
Special thanks:
|
||||
Alexander Nasonov
|
||||
Daniel Richard G.
|
||||
Giuseppe D'Angelo
|
||||
Jiong Wang (TileGX support)
|
||||
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SLJIT_CONFIG_H_
|
||||
#define _SLJIT_CONFIG_H_
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Custom defines */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Put your custom defines here. This empty section will never change
|
||||
which helps maintaining patches (with diff / patch utilities). */
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Architecture */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Architecture selection. */
|
||||
/* #define SLJIT_CONFIG_X86_32 1 */
|
||||
/* #define SLJIT_CONFIG_X86_64 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_V5 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_V7 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_THUMB2 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_64 1 */
|
||||
/* #define SLJIT_CONFIG_PPC_32 1 */
|
||||
/* #define SLJIT_CONFIG_PPC_64 1 */
|
||||
/* #define SLJIT_CONFIG_MIPS_32 1 */
|
||||
/* #define SLJIT_CONFIG_MIPS_64 1 */
|
||||
/* #define SLJIT_CONFIG_SPARC_32 1 */
|
||||
/* #define SLJIT_CONFIG_TILEGX 1 */
|
||||
|
||||
/* #define SLJIT_CONFIG_AUTO 1 */
|
||||
/* #define SLJIT_CONFIG_UNSUPPORTED 1 */
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Utilities */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Useful for thread-safe compiling of global functions. */
|
||||
#ifndef SLJIT_UTIL_GLOBAL_LOCK
|
||||
/* Enabled by default */
|
||||
#define SLJIT_UTIL_GLOBAL_LOCK 1
|
||||
#endif
|
||||
|
||||
/* Implements a stack like data structure (by using mmap / VirtualAlloc). */
|
||||
#ifndef SLJIT_UTIL_STACK
|
||||
/* Enabled by default */
|
||||
#define SLJIT_UTIL_STACK 1
|
||||
#endif
|
||||
|
||||
/* Single threaded application. Does not require any locks. */
|
||||
#ifndef SLJIT_SINGLE_THREADED
|
||||
/* Disabled by default. */
|
||||
#define SLJIT_SINGLE_THREADED 0
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Configuration */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* If SLJIT_STD_MACROS_DEFINED is not defined, the application should
|
||||
define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMCPY, and NULL. */
|
||||
#ifndef SLJIT_STD_MACROS_DEFINED
|
||||
/* Disabled by default. */
|
||||
#define SLJIT_STD_MACROS_DEFINED 0
|
||||
#endif
|
||||
|
||||
/* Executable code allocation:
|
||||
If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should
|
||||
define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_EXEC_OFFSET. */
|
||||
#ifndef SLJIT_EXECUTABLE_ALLOCATOR
|
||||
/* Enabled by default. */
|
||||
#define SLJIT_EXECUTABLE_ALLOCATOR 1
|
||||
|
||||
/* When SLJIT_PROT_EXECUTABLE_ALLOCATOR is enabled SLJIT uses
|
||||
an allocator which does not set writable and executable
|
||||
permission flags at the same time. The trade-of is increased
|
||||
memory consumption and disabled dynamic code modifications. */
|
||||
#ifndef SLJIT_PROT_EXECUTABLE_ALLOCATOR
|
||||
/* Disabled by default. */
|
||||
#define SLJIT_PROT_EXECUTABLE_ALLOCATOR 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Force cdecl calling convention even if a better calling
|
||||
convention (e.g. fastcall) is supported by the C compiler.
|
||||
If this option is enabled, C functions without
|
||||
SLJIT_CALL can also be called from JIT code. */
|
||||
#ifndef SLJIT_USE_CDECL_CALLING_CONVENTION
|
||||
/* Disabled by default */
|
||||
#define SLJIT_USE_CDECL_CALLING_CONVENTION 0
|
||||
#endif
|
||||
|
||||
/* Return with error when an invalid argument is passed. */
|
||||
#ifndef SLJIT_ARGUMENT_CHECKS
|
||||
/* Disabled by default */
|
||||
#define SLJIT_ARGUMENT_CHECKS 0
|
||||
#endif
|
||||
|
||||
/* Debug checks (assertions, etc.). */
|
||||
#ifndef SLJIT_DEBUG
|
||||
/* Enabled by default */
|
||||
#define SLJIT_DEBUG 1
|
||||
#endif
|
||||
|
||||
/* Verbose operations. */
|
||||
#ifndef SLJIT_VERBOSE
|
||||
/* Enabled by default */
|
||||
#define SLJIT_VERBOSE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
SLJIT_IS_FPU_AVAILABLE
|
||||
The availability of the FPU can be controlled by SLJIT_IS_FPU_AVAILABLE.
|
||||
zero value - FPU is NOT present.
|
||||
nonzero value - FPU is present.
|
||||
*/
|
||||
|
||||
/* For further configurations, see the beginning of sljitConfigInternal.h */
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,728 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SLJIT_CONFIG_INTERNAL_H_
|
||||
#define _SLJIT_CONFIG_INTERNAL_H_
|
||||
|
||||
/*
|
||||
SLJIT defines the following architecture dependent types and macros:
|
||||
|
||||
Types:
|
||||
sljit_s8, sljit_u8 : signed and unsigned 8 bit integer type
|
||||
sljit_s16, sljit_u16 : signed and unsigned 16 bit integer type
|
||||
sljit_s32, sljit_u32 : signed and unsigned 32 bit integer type
|
||||
sljit_sw, sljit_uw : signed and unsigned machine word, enough to store a pointer
|
||||
sljit_p : unsgined pointer value (usually the same as sljit_uw, but
|
||||
some 64 bit ABIs may use 32 bit pointers)
|
||||
sljit_f32 : 32 bit single precision floating point value
|
||||
sljit_f64 : 64 bit double precision floating point value
|
||||
|
||||
Macros for feature detection (boolean):
|
||||
SLJIT_32BIT_ARCHITECTURE : 32 bit architecture
|
||||
SLJIT_64BIT_ARCHITECTURE : 64 bit architecture
|
||||
SLJIT_LITTLE_ENDIAN : little endian architecture
|
||||
SLJIT_BIG_ENDIAN : big endian architecture
|
||||
SLJIT_UNALIGNED : allows unaligned memory accesses for non-fpu operations (only!)
|
||||
SLJIT_INDIRECT_CALL : see SLJIT_FUNC_OFFSET() for more information
|
||||
|
||||
Constants:
|
||||
SLJIT_NUMBER_OF_REGISTERS : number of available registers
|
||||
SLJIT_NUMBER_OF_SCRATCH_REGISTERS : number of available scratch registers
|
||||
SLJIT_NUMBER_OF_SAVED_REGISTERS : number of available saved registers
|
||||
SLJIT_NUMBER_OF_FLOAT_REGISTERS : number of available floating point registers
|
||||
SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS : number of available floating point scratch registers
|
||||
SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS : number of available floating point saved registers
|
||||
SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index
|
||||
SLJIT_F32_SHIFT : the shift required to apply when accessing
|
||||
a single precision floating point array by index
|
||||
SLJIT_F64_SHIFT : the shift required to apply when accessing
|
||||
a double precision floating point array by index
|
||||
SLJIT_LOCALS_OFFSET : local space starting offset (SLJIT_SP + SLJIT_LOCALS_OFFSET)
|
||||
SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address
|
||||
|
||||
Other macros:
|
||||
SLJIT_CALL : C calling convention define for both calling JIT form C and C callbacks for JIT
|
||||
SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (compiler independent helper)
|
||||
*/
|
||||
|
||||
/*****************/
|
||||
/* Sanity check. */
|
||||
/*****************/
|
||||
|
||||
#if !((defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|
||||
|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
|| (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
|
||||
|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|
||||
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|
||||
|| (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|
||||
|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|
||||
|| (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
|
||||
|| (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
|
||||
|| (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
|
||||
|| (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED))
|
||||
#error "An architecture must be selected"
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|
||||
+ (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
+ (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
|
||||
+ (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
+ (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|
||||
+ (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
+ (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
+ (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|
||||
+ (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
|
||||
+ (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|
||||
+ (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|
||||
+ (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
|
||||
+ (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
|
||||
+ (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2
|
||||
#error "Multiple architectures are selected"
|
||||
#endif
|
||||
|
||||
/********************************************************/
|
||||
/* Automatic CPU detection (requires compiler support). */
|
||||
/********************************************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#if defined(__i386__) || defined(__i386)
|
||||
#define SLJIT_CONFIG_X86_32 1
|
||||
#elif defined(__x86_64__)
|
||||
#define SLJIT_CONFIG_X86_64 1
|
||||
#elif defined(__arm__) || defined(__ARM__)
|
||||
#ifdef __thumb2__
|
||||
#define SLJIT_CONFIG_ARM_THUMB2 1
|
||||
#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)
|
||||
#define SLJIT_CONFIG_ARM_V7 1
|
||||
#else
|
||||
#define SLJIT_CONFIG_ARM_V5 1
|
||||
#endif
|
||||
#elif defined (__aarch64__)
|
||||
#define SLJIT_CONFIG_ARM_64 1
|
||||
#elif defined(__ppc64__) || defined(__powerpc64__) || defined(_ARCH_PPC64) || (defined(_POWER) && defined(__64BIT__))
|
||||
#define SLJIT_CONFIG_PPC_64 1
|
||||
#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER)
|
||||
#define SLJIT_CONFIG_PPC_32 1
|
||||
#elif defined(__mips__) && !defined(_LP64)
|
||||
#define SLJIT_CONFIG_MIPS_32 1
|
||||
#elif defined(__mips64)
|
||||
#define SLJIT_CONFIG_MIPS_64 1
|
||||
#elif defined(__sparc__) || defined(__sparc)
|
||||
#define SLJIT_CONFIG_SPARC_32 1
|
||||
#elif defined(__tilegx__)
|
||||
#define SLJIT_CONFIG_TILEGX 1
|
||||
#else
|
||||
/* Unsupported architecture */
|
||||
#define SLJIT_CONFIG_UNSUPPORTED 1
|
||||
#endif
|
||||
|
||||
#else /* !_WIN32 */
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define SLJIT_CONFIG_X86_64 1
|
||||
#elif defined(_ARM_)
|
||||
#define SLJIT_CONFIG_ARM_V5 1
|
||||
#else
|
||||
#define SLJIT_CONFIG_X86_32 1
|
||||
#endif
|
||||
|
||||
#endif /* !WIN32 */
|
||||
#endif /* SLJIT_CONFIG_AUTO */
|
||||
|
||||
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
#undef SLJIT_EXECUTABLE_ALLOCATOR
|
||||
#endif
|
||||
|
||||
/******************************/
|
||||
/* CPU family type detection. */
|
||||
/******************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
#define SLJIT_CONFIG_ARM_32 1
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
#define SLJIT_CONFIG_X86 1
|
||||
#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
|
||||
#define SLJIT_CONFIG_ARM 1
|
||||
#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
#define SLJIT_CONFIG_PPC 1
|
||||
#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
#define SLJIT_CONFIG_MIPS 1
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) || (defined SLJIT_CONFIG_SPARC_64 && SLJIT_CONFIG_SPARC_64)
|
||||
#define SLJIT_CONFIG_SPARC 1
|
||||
#endif
|
||||
|
||||
/**********************************/
|
||||
/* External function definitions. */
|
||||
/**********************************/
|
||||
|
||||
/* General macros:
|
||||
Note: SLJIT is designed to be independent from them as possible.
|
||||
|
||||
In release mode (SLJIT_DEBUG is not defined) only the following
|
||||
external functions are needed:
|
||||
*/
|
||||
|
||||
#ifndef SLJIT_MALLOC
|
||||
#define SLJIT_MALLOC(size, allocator_data) malloc(size)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_FREE
|
||||
#define SLJIT_FREE(ptr, allocator_data) free(ptr)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_MEMCPY
|
||||
#define SLJIT_MEMCPY(dest, src, len) memcpy(dest, src, len)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_ZEROMEM
|
||||
#define SLJIT_ZEROMEM(dest, len) memset(dest, 0, len)
|
||||
#endif
|
||||
|
||||
/***************************/
|
||||
/* Compiler helper macros. */
|
||||
/***************************/
|
||||
|
||||
#if !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY)
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
#define SLJIT_LIKELY(x) __builtin_expect((x), 1)
|
||||
#define SLJIT_UNLIKELY(x) __builtin_expect((x), 0)
|
||||
#else
|
||||
#define SLJIT_LIKELY(x) (x)
|
||||
#define SLJIT_UNLIKELY(x) (x)
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY) */
|
||||
|
||||
#ifndef SLJIT_INLINE
|
||||
/* Inline functions. Some old compilers do not support them. */
|
||||
#if defined(__SUNPRO_C) && __SUNPRO_C <= 0x510
|
||||
#define SLJIT_INLINE
|
||||
#else
|
||||
#define SLJIT_INLINE __inline
|
||||
#endif
|
||||
#endif /* !SLJIT_INLINE */
|
||||
|
||||
#ifndef SLJIT_NOINLINE
|
||||
/* Not inline functions. */
|
||||
#if defined(__GNUC__)
|
||||
#define SLJIT_NOINLINE __attribute__ ((noinline))
|
||||
#else
|
||||
#define SLJIT_NOINLINE
|
||||
#endif
|
||||
#endif /* !SLJIT_INLINE */
|
||||
|
||||
#ifndef SLJIT_UNUSED_ARG
|
||||
/* Unused arguments. */
|
||||
#define SLJIT_UNUSED_ARG(arg) (void)arg
|
||||
#endif
|
||||
|
||||
/*********************************/
|
||||
/* Type of public API functions. */
|
||||
/*********************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC)
|
||||
/* Static ABI functions. For all-in-one programs. */
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/* Disable unused warnings in gcc. */
|
||||
#define SLJIT_API_FUNC_ATTRIBUTE static __attribute__((unused))
|
||||
#else
|
||||
#define SLJIT_API_FUNC_ATTRIBUTE static
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define SLJIT_API_FUNC_ATTRIBUTE
|
||||
#endif /* (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC) */
|
||||
|
||||
/****************************/
|
||||
/* Instruction cache flush. */
|
||||
/****************************/
|
||||
|
||||
#if (!defined SLJIT_CACHE_FLUSH && defined __has_builtin)
|
||||
#if __has_builtin(__builtin___clear_cache)
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
__builtin___clear_cache((char*)from, (char*)to)
|
||||
|
||||
#endif /* __has_builtin(__builtin___clear_cache) */
|
||||
#endif /* (!defined SLJIT_CACHE_FLUSH && defined __has_builtin) */
|
||||
|
||||
#ifndef SLJIT_CACHE_FLUSH
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
|
||||
|
||||
/* Not required to implement on archs with unified caches. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to)
|
||||
|
||||
#elif defined __APPLE__
|
||||
|
||||
/* Supported by all macs since Mac OS 10.5.
|
||||
However, it does not work on non-jailbroken iOS devices,
|
||||
although the compilation is successful. */
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
sys_icache_invalidate((char*)(from), (char*)(to) - (char*)(from))
|
||||
|
||||
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
|
||||
/* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
ppc_cache_flush((from), (to))
|
||||
#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
|
||||
|
||||
#elif (defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
__builtin___clear_cache((char*)from, (char*)to)
|
||||
|
||||
#elif defined __ANDROID__
|
||||
|
||||
/* Android lacks __clear_cache; instead, cacheflush should be used. */
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
cacheflush((long)(from), (long)(to), 0)
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
|
||||
/* The __clear_cache() implementation of GCC is a dummy function on Sparc. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
sparc_cache_flush((from), (to))
|
||||
#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_64 && defined _MSC_VER )
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
FlushInstructionCache(GetCurrentProcess(),(char*)from, ((char*)to) - ((char *)from) );
|
||||
|
||||
#else
|
||||
|
||||
/* Calls __ARM_NR_cacheflush on ARM-Linux. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
__clear_cache((char*)(from), (char*)(to))
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_CACHE_FLUSH */
|
||||
|
||||
/******************************************************/
|
||||
/* Integer and floating point type definitions. */
|
||||
/******************************************************/
|
||||
|
||||
/* 8 bit byte type. */
|
||||
typedef unsigned char sljit_u8;
|
||||
typedef signed char sljit_s8;
|
||||
|
||||
/* 16 bit half-word type. */
|
||||
typedef unsigned short int sljit_u16;
|
||||
typedef signed short int sljit_s16;
|
||||
|
||||
/* 32 bit integer type. */
|
||||
typedef unsigned int sljit_u32;
|
||||
typedef signed int sljit_s32;
|
||||
|
||||
/* Machine word type. Enough for storing a pointer.
|
||||
32 bit for 32 bit machines.
|
||||
64 bit for 64 bit machines. */
|
||||
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
/* Just to have something. */
|
||||
#define SLJIT_WORD_SHIFT 0
|
||||
typedef unsigned long int sljit_uw;
|
||||
typedef long int sljit_sw;
|
||||
#elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
&& !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|
||||
&& !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|
||||
&& !(defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
|
||||
#define SLJIT_32BIT_ARCHITECTURE 1
|
||||
#define SLJIT_WORD_SHIFT 2
|
||||
typedef unsigned int sljit_uw;
|
||||
typedef int sljit_sw;
|
||||
#else
|
||||
#define SLJIT_64BIT_ARCHITECTURE 1
|
||||
#define SLJIT_WORD_SHIFT 3
|
||||
#ifdef _WIN32
|
||||
typedef unsigned __int64 sljit_uw;
|
||||
typedef __int64 sljit_sw;
|
||||
#else
|
||||
typedef unsigned long int sljit_uw;
|
||||
typedef long int sljit_sw;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef sljit_uw sljit_p;
|
||||
|
||||
/* Floating point types. */
|
||||
typedef float sljit_f32;
|
||||
typedef double sljit_f64;
|
||||
|
||||
/* Shift for pointer sized data. */
|
||||
#define SLJIT_POINTER_SHIFT SLJIT_WORD_SHIFT
|
||||
|
||||
/* Shift for double precision sized data. */
|
||||
#define SLJIT_F32_SHIFT 2
|
||||
#define SLJIT_F64_SHIFT 3
|
||||
|
||||
#ifndef SLJIT_W
|
||||
|
||||
/* Defining long constants. */
|
||||
#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
|
||||
#define SLJIT_W(w) (w##ll)
|
||||
#else
|
||||
#define SLJIT_W(w) (w)
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_W */
|
||||
|
||||
/*************************/
|
||||
/* Endianness detection. */
|
||||
/*************************/
|
||||
|
||||
#if !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN)
|
||||
|
||||
/* These macros are mostly useful for the applications. */
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#define SLJIT_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#define SLJIT_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|
||||
|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
|
||||
#ifdef __MIPSEL__
|
||||
#define SLJIT_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#define SLJIT_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
|
||||
#define SLJIT_BIG_ENDIAN 1
|
||||
|
||||
#else
|
||||
#define SLJIT_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN) */
|
||||
|
||||
/* Sanity check. */
|
||||
#if (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
|
||||
#error "Exactly one endianness must be selected"
|
||||
#endif
|
||||
|
||||
#if !(defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && !(defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
|
||||
#error "Exactly one endianness must be selected"
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_UNALIGNED
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|
||||
|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|
||||
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
#define SLJIT_UNALIGNED 1
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_UNALIGNED */
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
/* Auto detect SSE2 support using CPUID.
|
||||
On 64 bit x86 cpus, sse2 must be present. */
|
||||
#define SLJIT_DETECT_SSE2 1
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************/
|
||||
/* Calling convention of functions generated by SLJIT or called from the generated code. */
|
||||
/*****************************************************************************************/
|
||||
|
||||
#ifndef SLJIT_CALL
|
||||
|
||||
#if (defined SLJIT_USE_CDECL_CALLING_CONVENTION && SLJIT_USE_CDECL_CALLING_CONVENTION)
|
||||
|
||||
/* Force cdecl. */
|
||||
#define SLJIT_CALL
|
||||
|
||||
#elif (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
|
||||
#if defined(__GNUC__) && !defined(__APPLE__)
|
||||
|
||||
#define SLJIT_CALL __attribute__ ((fastcall))
|
||||
#define SLJIT_X86_32_FASTCALL 1
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#define SLJIT_CALL __fastcall
|
||||
#define SLJIT_X86_32_FASTCALL 1
|
||||
|
||||
#elif defined(__BORLANDC__)
|
||||
|
||||
#define SLJIT_CALL __msfastcall
|
||||
#define SLJIT_X86_32_FASTCALL 1
|
||||
|
||||
#else /* Unknown compiler. */
|
||||
|
||||
/* The cdecl attribute is the default. */
|
||||
#define SLJIT_CALL
|
||||
|
||||
#endif
|
||||
|
||||
#else /* Non x86-32 architectures. */
|
||||
|
||||
#define SLJIT_CALL
|
||||
|
||||
#endif /* SLJIT_CONFIG_X86_32 */
|
||||
|
||||
#endif /* !SLJIT_CALL */
|
||||
|
||||
#ifndef SLJIT_INDIRECT_CALL
|
||||
#if ((defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) && (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN)) \
|
||||
|| ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && defined _AIX)
|
||||
/* It seems certain ppc compilers use an indirect addressing for functions
|
||||
which makes things complicated. */
|
||||
#define SLJIT_INDIRECT_CALL 1
|
||||
#endif
|
||||
#endif /* SLJIT_INDIRECT_CALL */
|
||||
|
||||
/* The offset which needs to be substracted from the return address to
|
||||
determine the next executed instruction after return. */
|
||||
#ifndef SLJIT_RETURN_ADDRESS_OFFSET
|
||||
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
#define SLJIT_RETURN_ADDRESS_OFFSET 8
|
||||
#else
|
||||
#define SLJIT_RETURN_ADDRESS_OFFSET 0
|
||||
#endif
|
||||
#endif /* SLJIT_RETURN_ADDRESS_OFFSET */
|
||||
|
||||
/***************************************************/
|
||||
/* Functions of the built-in executable allocator. */
|
||||
/***************************************************/
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size);
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr);
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
|
||||
#define SLJIT_MALLOC_EXEC(size) sljit_malloc_exec(size)
|
||||
#define SLJIT_FREE_EXEC(ptr) sljit_free_exec(ptr)
|
||||
|
||||
#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
|
||||
#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
|
||||
#else
|
||||
#define SLJIT_EXEC_OFFSET(ptr) 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************/
|
||||
/* Registers and locals offset determination. */
|
||||
/**********************************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 9
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#else
|
||||
/* Maximum 3 arguments are passed on the stack, +1 for double alignment. */
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#endif /* SLJIT_X86_32_FASTCALL */
|
||||
|
||||
#elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
|
||||
#ifndef _WIN64
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 6
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
#else
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#endif /* _WIN64 */
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 25
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 10
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (2 * sizeof(sljit_sw))
|
||||
|
||||
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 22
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 17
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined _AIX)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((6 + 8) * sizeof(sljit_sw))
|
||||
#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
/* Add +1 for double alignment. */
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((3 + 1) * sizeof(sljit_sw))
|
||||
#else
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (3 * sizeof(sljit_sw))
|
||||
#endif /* SLJIT_CONFIG_PPC_64 || _AIX */
|
||||
|
||||
#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 21
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (4 * sizeof(sljit_sw))
|
||||
#else
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC && SLJIT_CONFIG_SPARC)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 18
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 14
|
||||
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
/* Add +1 for double alignment. */
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((23 + 1) * sizeof(sljit_sw))
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 10
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 5
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 0
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#endif
|
||||
|
||||
#define SLJIT_LOCALS_OFFSET (SLJIT_LOCALS_OFFSET_BASE)
|
||||
|
||||
#define SLJIT_NUMBER_OF_SCRATCH_REGISTERS \
|
||||
(SLJIT_NUMBER_OF_REGISTERS - SLJIT_NUMBER_OF_SAVED_REGISTERS)
|
||||
|
||||
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 6
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && (defined _WIN64)
|
||||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 1
|
||||
#else
|
||||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
|
||||
#endif
|
||||
|
||||
#define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \
|
||||
(SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS)
|
||||
|
||||
/*************************************/
|
||||
/* Debug and verbose related macros. */
|
||||
/*************************************/
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
|
||||
|
||||
#if !defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE)
|
||||
|
||||
/* SLJIT_HALT_PROCESS must halt the process. */
|
||||
#ifndef SLJIT_HALT_PROCESS
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SLJIT_HALT_PROCESS() \
|
||||
abort();
|
||||
#endif /* !SLJIT_HALT_PROCESS */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#endif /* !SLJIT_ASSERT || !SLJIT_UNREACHABLE */
|
||||
|
||||
/* Feel free to redefine these two macros. */
|
||||
#ifndef SLJIT_ASSERT
|
||||
|
||||
#define SLJIT_ASSERT(x) \
|
||||
do { \
|
||||
if (SLJIT_UNLIKELY(!(x))) { \
|
||||
printf("Assertion failed at " __FILE__ ":%d\n", __LINE__); \
|
||||
SLJIT_HALT_PROCESS(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* !SLJIT_ASSERT */
|
||||
|
||||
#ifndef SLJIT_UNREACHABLE
|
||||
|
||||
#define SLJIT_UNREACHABLE() \
|
||||
do { \
|
||||
printf("Should never been reached " __FILE__ ":%d\n", __LINE__); \
|
||||
SLJIT_HALT_PROCESS(); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !SLJIT_UNREACHABLE */
|
||||
|
||||
#else /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
|
||||
|
||||
/* Forcing empty, but valid statements. */
|
||||
#undef SLJIT_ASSERT
|
||||
#undef SLJIT_UNREACHABLE
|
||||
|
||||
#define SLJIT_ASSERT(x) \
|
||||
do { } while (0)
|
||||
#define SLJIT_UNREACHABLE() \
|
||||
do { } while (0)
|
||||
|
||||
#endif /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
|
||||
|
||||
#ifndef SLJIT_COMPILE_ASSERT
|
||||
|
||||
#define SLJIT_COMPILE_ASSERT(x, description) \
|
||||
switch(0) { case 0: case ((x) ? 1 : 0): break; }
|
||||
|
||||
#endif /* !SLJIT_COMPILE_ASSERT */
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file contains a simple executable memory allocator
|
||||
|
||||
It is assumed, that executable code blocks are usually medium (or sometimes
|
||||
large) memory blocks, and the allocator is not too frequently called (less
|
||||
optimized than other allocators). Thus, using it as a generic allocator is
|
||||
not suggested.
|
||||
|
||||
How does it work:
|
||||
Memory is allocated in continuous memory areas called chunks by alloc_chunk()
|
||||
Chunk format:
|
||||
[ block ][ block ] ... [ block ][ block terminator ]
|
||||
|
||||
All blocks and the block terminator is started with block_header. The block
|
||||
header contains the size of the previous and the next block. These sizes
|
||||
can also contain special values.
|
||||
Block size:
|
||||
0 - The block is a free_block, with a different size member.
|
||||
1 - The block is a block terminator.
|
||||
n - The block is used at the moment, and the value contains its size.
|
||||
Previous block size:
|
||||
0 - This is the first block of the memory chunk.
|
||||
n - The size of the previous block.
|
||||
|
||||
Using these size values we can go forward or backward on the block chain.
|
||||
The unused blocks are stored in a chain list pointed by free_blocks. This
|
||||
list is useful if we need to find a suitable memory area when the allocator
|
||||
is called.
|
||||
|
||||
When a block is freed, the new free block is connected to its adjacent free
|
||||
blocks if possible.
|
||||
|
||||
[ free block ][ used block ][ free block ]
|
||||
and "used block" is freed, the three blocks are connected together:
|
||||
[ one big free block ]
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* System (OS) functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* 64 KByte. */
|
||||
#define CHUNK_SIZE 0x10000
|
||||
|
||||
/*
|
||||
alloc_chunk / free_chunk :
|
||||
* allocate executable system memory chunks
|
||||
* the size is always divisible by CHUNK_SIZE
|
||||
allocator_grab_lock / allocator_release_lock :
|
||||
* make the allocator thread safe
|
||||
* can be empty if the OS (or the application) does not support threading
|
||||
* only the allocator requires this lock, sljit is fully thread safe
|
||||
as it only uses local variables
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
|
||||
{
|
||||
return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(size);
|
||||
VirtualFree(chunk, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
|
||||
{
|
||||
void *retval;
|
||||
|
||||
#ifdef MAP_ANON
|
||||
retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#else
|
||||
if (dev_zero < 0) {
|
||||
if (open_dev_zero())
|
||||
return NULL;
|
||||
}
|
||||
retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, dev_zero, 0);
|
||||
#endif
|
||||
|
||||
return (retval != MAP_FAILED) ? retval : NULL;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
|
||||
{
|
||||
munmap(chunk, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Common functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define CHUNK_MASK (~(CHUNK_SIZE - 1))
|
||||
|
||||
struct block_header {
|
||||
sljit_uw size;
|
||||
sljit_uw prev_size;
|
||||
};
|
||||
|
||||
struct free_block {
|
||||
struct block_header header;
|
||||
struct free_block *next;
|
||||
struct free_block *prev;
|
||||
sljit_uw size;
|
||||
};
|
||||
|
||||
#define AS_BLOCK_HEADER(base, offset) \
|
||||
((struct block_header*)(((sljit_u8*)base) + offset))
|
||||
#define AS_FREE_BLOCK(base, offset) \
|
||||
((struct free_block*)(((sljit_u8*)base) + offset))
|
||||
#define MEM_START(base) ((void*)(((sljit_u8*)base) + sizeof(struct block_header)))
|
||||
#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7) & ~7)
|
||||
|
||||
static struct free_block* free_blocks;
|
||||
static sljit_uw allocated_size;
|
||||
static sljit_uw total_size;
|
||||
|
||||
static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
|
||||
{
|
||||
free_block->header.size = 0;
|
||||
free_block->size = size;
|
||||
|
||||
free_block->next = free_blocks;
|
||||
free_block->prev = NULL;
|
||||
if (free_blocks)
|
||||
free_blocks->prev = free_block;
|
||||
free_blocks = free_block;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
|
||||
{
|
||||
if (free_block->next)
|
||||
free_block->next->prev = free_block->prev;
|
||||
|
||||
if (free_block->prev)
|
||||
free_block->prev->next = free_block->next;
|
||||
else {
|
||||
SLJIT_ASSERT(free_blocks == free_block);
|
||||
free_blocks = free_block->next;
|
||||
}
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
||||
{
|
||||
struct block_header *header;
|
||||
struct block_header *next_header;
|
||||
struct free_block *free_block;
|
||||
sljit_uw chunk_size;
|
||||
|
||||
allocator_grab_lock();
|
||||
if (size < (64 - sizeof(struct block_header)))
|
||||
size = (64 - sizeof(struct block_header));
|
||||
size = ALIGN_SIZE(size);
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
if (free_block->size >= size) {
|
||||
chunk_size = free_block->size;
|
||||
if (chunk_size > size + 64) {
|
||||
/* We just cut a block from the end of the free block. */
|
||||
chunk_size -= size;
|
||||
free_block->size = chunk_size;
|
||||
header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
header->prev_size = chunk_size;
|
||||
AS_BLOCK_HEADER(header, size)->prev_size = size;
|
||||
}
|
||||
else {
|
||||
sljit_remove_free_block(free_block);
|
||||
header = (struct block_header*)free_block;
|
||||
size = chunk_size;
|
||||
}
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
free_block = free_block->next;
|
||||
}
|
||||
|
||||
chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK;
|
||||
header = (struct block_header*)alloc_chunk(chunk_size);
|
||||
if (!header) {
|
||||
allocator_release_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chunk_size -= sizeof(struct block_header);
|
||||
total_size += chunk_size;
|
||||
|
||||
header->prev_size = 0;
|
||||
if (chunk_size > size + 64) {
|
||||
/* Cut the allocated space into a free and a used block. */
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
chunk_size -= size;
|
||||
|
||||
free_block = AS_FREE_BLOCK(header, size);
|
||||
free_block->header.prev_size = size;
|
||||
sljit_insert_free_block(free_block, chunk_size);
|
||||
next_header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
}
|
||||
else {
|
||||
/* All space belongs to this allocation. */
|
||||
allocated_size += chunk_size;
|
||||
header->size = chunk_size;
|
||||
next_header = AS_BLOCK_HEADER(header, chunk_size);
|
||||
}
|
||||
next_header->size = 1;
|
||||
next_header->prev_size = chunk_size;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
|
||||
{
|
||||
struct block_header *header;
|
||||
struct free_block* free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
|
||||
allocated_size -= header->size;
|
||||
|
||||
/* Connecting free blocks together if possible. */
|
||||
|
||||
/* If header->prev_size == 0, free_block will equal to header.
|
||||
In this case, free_block->header.size will be > 0. */
|
||||
free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
|
||||
if (SLJIT_UNLIKELY(!free_block->header.size)) {
|
||||
free_block->size += header->size;
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
else {
|
||||
free_block = (struct free_block*)header;
|
||||
sljit_insert_free_block(free_block, header->size);
|
||||
}
|
||||
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
if (SLJIT_UNLIKELY(!header->size)) {
|
||||
free_block->size += ((struct free_block*)header)->size;
|
||||
sljit_remove_free_block((struct free_block*)header);
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
|
||||
/* The whole chunk is free. */
|
||||
if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
|
||||
/* If this block is freed, we still have (allocated_size / 2) free space. */
|
||||
if (total_size - free_block->size > (allocated_size * 3 / 2)) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
}
|
||||
|
||||
allocator_release_lock();
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
|
||||
{
|
||||
struct free_block* free_block;
|
||||
struct free_block* next_free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
next_free_block = free_block->next;
|
||||
if (!free_block->header.prev_size &&
|
||||
AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
free_block = next_free_block;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
|
||||
allocator_release_lock();
|
||||
}
|
||||
2147
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/sljitLir.c
Normal file
2147
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/sljitLir.c
Normal file
File diff suppressed because it is too large
Load Diff
1385
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/sljitLir.h
Normal file
1385
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/sljitLir.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* mips 32-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
|
||||
{
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
if (imm < 0 && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define EMIT_LOGICAL(op_imm, op_norm) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
#define EMIT_SHIFT(op_imm, op_v) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
sljit_s32 is_overflow, is_carry, is_handled;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
|
||||
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(24), DR(dst));
|
||||
#endif
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst));
|
||||
#endif
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, CLZ | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, CLZ | S(src2) | T(dst) | D(dst), DR(dst)));
|
||||
#else
|
||||
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
|
||||
FAIL_IF(push_inst(compiler, SRL | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
|
||||
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
|
||||
}
|
||||
/* Nearly all instructions are unmovable in the following sequence. */
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
/* Check zero. */
|
||||
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(32), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(dst) | IMM(-1), DR(dst)));
|
||||
/* Loop for searching the highest bit. */
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(dst) | T(dst) | IMM(1), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
|
||||
if (op & SLJIT_SET_Z)
|
||||
return push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ADD:
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
/* a + b >= a | b (otherwise, the carry should be set to 1). */
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_ADDC:
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
} else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
if (!is_carry)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* Set carry flag. */
|
||||
return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUB:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_handled = 0;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
|
||||
is_handled = 1;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_handled) {
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MUL:
|
||||
SLJIT_ASSERT(!(flags & SRC2_IMM));
|
||||
|
||||
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW && GET_FLAG_TYPE(op) != SLJIT_MUL_NOT_OVERFLOW) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
return push_inst(compiler, MFLO | D(dst), DR(dst));
|
||||
#endif
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, SRA | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
|
||||
return push_inst(compiler, SUBU | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_AND:
|
||||
EMIT_LOGICAL(ANDI, AND);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_OR:
|
||||
EMIT_LOGICAL(ORI, OR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_XOR:
|
||||
EMIT_LOGICAL(XORI, XOR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_SHL:
|
||||
EMIT_SHIFT(SLL, SLLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_LSHR:
|
||||
EMIT_SHIFT(SRL, SRLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ASHR:
|
||||
EMIT_SHIFT(SRA, SRAV);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
|
||||
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
@ -0,0 +1,541 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* mips 64-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
|
||||
{
|
||||
sljit_s32 shift = 32;
|
||||
sljit_s32 shift2;
|
||||
sljit_s32 inv = 0;
|
||||
sljit_ins ins;
|
||||
sljit_uw uimm;
|
||||
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
if (imm < 0 && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
|
||||
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Zero extended number. */
|
||||
uimm = imm;
|
||||
if (imm < 0) {
|
||||
uimm = ~imm;
|
||||
inv = 1;
|
||||
}
|
||||
|
||||
while (!(uimm & 0xff00000000000000l)) {
|
||||
shift -= 8;
|
||||
uimm <<= 8;
|
||||
}
|
||||
|
||||
if (!(uimm & 0xf000000000000000l)) {
|
||||
shift -= 4;
|
||||
uimm <<= 4;
|
||||
}
|
||||
|
||||
if (!(uimm & 0xc000000000000000l)) {
|
||||
shift -= 2;
|
||||
uimm <<= 2;
|
||||
}
|
||||
|
||||
if ((sljit_sw)uimm < 0) {
|
||||
uimm >>= 1;
|
||||
shift += 1;
|
||||
}
|
||||
SLJIT_ASSERT(((uimm & 0xc000000000000000l) == 0x4000000000000000l) && (shift > 0) && (shift <= 32));
|
||||
|
||||
if (inv)
|
||||
uimm = ~uimm;
|
||||
|
||||
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
|
||||
if (uimm & 0x0000ffff00000000l)
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 32), dst_ar));
|
||||
|
||||
imm &= (1l << shift) - 1;
|
||||
if (!(imm & ~0xffff)) {
|
||||
ins = (shift == 32) ? DSLL32 : DSLL;
|
||||
if (shift < 32)
|
||||
ins |= SH_IMM(shift);
|
||||
FAIL_IF(push_inst(compiler, ins | TA(dst_ar) | DA(dst_ar), dst_ar));
|
||||
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
}
|
||||
|
||||
/* Double shifts needs to be performed. */
|
||||
uimm <<= 32;
|
||||
shift2 = shift - 16;
|
||||
|
||||
while (!(uimm & 0xf000000000000000l)) {
|
||||
shift2 -= 4;
|
||||
uimm <<= 4;
|
||||
}
|
||||
|
||||
if (!(uimm & 0xc000000000000000l)) {
|
||||
shift2 -= 2;
|
||||
uimm <<= 2;
|
||||
}
|
||||
|
||||
if (!(uimm & 0x8000000000000000l)) {
|
||||
shift2--;
|
||||
uimm <<= 1;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT((uimm & 0x8000000000000000l) && (shift2 > 0) && (shift2 <= 16));
|
||||
|
||||
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift - shift2), dst_ar));
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
|
||||
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift2), dst_ar));
|
||||
|
||||
imm &= (1l << shift2) - 1;
|
||||
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
}
|
||||
|
||||
#define SELECT_OP(a, b) \
|
||||
(!(op & SLJIT_I32_OP) ? a : b)
|
||||
|
||||
#define EMIT_LOGICAL(op_imm, op_norm) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
#define EMIT_SHIFT(op_dimm, op_dimm32, op_imm, op_dv, op_v) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (src2 >= 32) { \
|
||||
SLJIT_ASSERT(!(op & SLJIT_I32_OP)); \
|
||||
ins = op_dimm32; \
|
||||
src2 -= 32; \
|
||||
} \
|
||||
else \
|
||||
ins = (op & SLJIT_I32_OP) ? op_imm : op_dimm; \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, ins | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, ins | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
ins = (op & SLJIT_I32_OP) ? op_v : op_dv; \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
sljit_ins ins;
|
||||
sljit_s32 is_overflow, is_carry, is_handled;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(dst), DR(dst));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8) {
|
||||
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
|
||||
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(24), DR(dst));
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16) {
|
||||
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(16), DR(dst));
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U32:
|
||||
SLJIT_ASSERT(!(op & SLJIT_I32_OP));
|
||||
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(0), DR(dst)));
|
||||
return push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst));
|
||||
|
||||
case SLJIT_MOV_S32:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
return push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(0), DR(dst));
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | T(dst) | D(dst), DR(dst)));
|
||||
#else
|
||||
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
|
||||
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
|
||||
}
|
||||
/* Nearly all instructions are unmovable in the following sequence. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
/* Check zero. */
|
||||
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM((op & SLJIT_I32_OP) ? 32 : 64), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(dst) | IMM(-1), DR(dst)));
|
||||
/* Loop for searching the highest bit. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(dst) | T(dst) | IMM(1), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL, SLL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
|
||||
if (op & SLJIT_SET_Z)
|
||||
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ADD:
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
/* a + b >= a | b (otherwise, the carry should be set to 1). */
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_ADDC:
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
} else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
if (!is_carry)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* Set carry flag. */
|
||||
return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUB:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_handled = 0;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
|
||||
is_handled = 1;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_handled) {
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MUL:
|
||||
SLJIT_ASSERT(!(flags & SRC2_IMM));
|
||||
|
||||
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW && GET_FLAG_TYPE(op) != SLJIT_MUL_NOT_OVERFLOW) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_I32_OP)
|
||||
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
FAIL_IF(push_inst(compiler, DMULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
return push_inst(compiler, MFLO | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
|
||||
return push_inst(compiler, MFLO | D(dst), DR(dst));
|
||||
#endif
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSRA32, SRA) | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_AND:
|
||||
EMIT_LOGICAL(ANDI, AND);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_OR:
|
||||
EMIT_LOGICAL(ORI, OR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_XOR:
|
||||
EMIT_LOGICAL(XORI, XOR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_SHL:
|
||||
EMIT_SHIFT(DSLL, DSLL32, SLL, DSLLV, SLLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_LSHR:
|
||||
EMIT_SHIFT(DSRL, DSRL32, SRL, DSRLV, SRLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ASHR:
|
||||
EMIT_SHIFT(DSRA, DSRA32, SRA, DSRAV, SRAV);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 48), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 32), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 16), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[5] = (inst[5] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 6);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[5] = (inst[5] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 6);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* ppc 32-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
|
||||
{
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
|
||||
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
|
||||
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define INS_CLEAR_LEFT(dst, src, from) \
|
||||
(RLWINM | S(src) | A(dst) | ((from) << 6) | (31 << 1))
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
|
||||
{
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
|
||||
}
|
||||
else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16)
|
||||
return push_inst(compiler, EXTSH | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_NEG:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst));
|
||||
|
||||
case SLJIT_ADD:
|
||||
if (flags & ALT_FORM1) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM4) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff)));
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(dst) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1)));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
|
||||
return push_inst(compiler, ADDC | OERC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_SUB:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM2 | ALT_FORM3)) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? CMPI : CMPLI) | CRD(0) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM4 | ALT_FORM5)) {
|
||||
return push_inst(compiler, ((flags & ALT_FORM4) ? CMP : CMPL) | CRD(0) | A(src1) | B(src2));
|
||||
}
|
||||
if (flags & ALT_FORM6) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, CMPLI | CRD(0) | A(src1) | compiler->imm));
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
|
||||
}
|
||||
if (flags & ALT_FORM7) {
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(0) | A(src1) | B(src2)));
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, SUBFC | OERC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_MUL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, MULLW | OERC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_AND:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_OR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_XOR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_SHL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
|
||||
}
|
||||
return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_LSHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
|
||||
}
|
||||
return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_ASHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
|
||||
}
|
||||
return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16)));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* ppc 64-bit arch dependent functions. */
|
||||
|
||||
#if defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)
|
||||
#define ASM_SLJIT_CLZ(src, dst) \
|
||||
__asm__ volatile ( "cntlzd %0, %1" : "=r"(dst) : "r"(src) )
|
||||
#elif defined(__xlc__)
|
||||
#error "Please enable GCC syntax for inline assembly statements"
|
||||
#else
|
||||
#error "Must implement count leading zeroes"
|
||||
#endif
|
||||
|
||||
#define RLDI(dst, src, sh, mb, type) \
|
||||
(HI(30) | S(src) | A(dst) | ((type) << 2) | (((sh) & 0x1f) << 11) | (((sh) & 0x20) >> 4) | (((mb) & 0x1f) << 6) | ((mb) & 0x20))
|
||||
|
||||
#define PUSH_RLDICR(reg, shift) \
|
||||
push_inst(compiler, RLDI(reg, reg, 63 - shift, shift, 1))
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
|
||||
{
|
||||
sljit_uw tmp;
|
||||
sljit_uw shift;
|
||||
sljit_uw tmp2;
|
||||
sljit_uw shift2;
|
||||
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
|
||||
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
|
||||
|
||||
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Count leading zeroes. */
|
||||
tmp = (imm >= 0) ? imm : ~imm;
|
||||
ASM_SLJIT_CLZ(tmp, shift);
|
||||
SLJIT_ASSERT(shift > 0);
|
||||
shift--;
|
||||
tmp = (imm << shift);
|
||||
|
||||
if ((tmp & ~0xffff000000000000ul) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
shift += 15;
|
||||
return PUSH_RLDICR(reg, shift);
|
||||
}
|
||||
|
||||
if ((tmp & ~0xffffffff00000000ul) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp >> 32)));
|
||||
shift += 31;
|
||||
return PUSH_RLDICR(reg, shift);
|
||||
}
|
||||
|
||||
/* Cut out the 16 bit from immediate. */
|
||||
shift += 15;
|
||||
tmp2 = imm & ((1ul << (63 - shift)) - 1);
|
||||
|
||||
if (tmp2 <= 0xffff) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, shift));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | tmp2);
|
||||
}
|
||||
|
||||
if (tmp2 <= 0xffffffff) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, shift));
|
||||
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | (tmp2 >> 16)));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp2)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
ASM_SLJIT_CLZ(tmp2, shift2);
|
||||
tmp2 <<= shift2;
|
||||
|
||||
if ((tmp2 & ~0xffff000000000000ul) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
shift2 += 15;
|
||||
shift += (63 - shift2);
|
||||
FAIL_IF(PUSH_RLDICR(reg, shift));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | (tmp2 >> 48)));
|
||||
return PUSH_RLDICR(reg, shift2);
|
||||
}
|
||||
|
||||
/* The general version. */
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 48)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm >> 32)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, 31));
|
||||
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(imm >> 16)));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm));
|
||||
}
|
||||
|
||||
/* Simplified mnemonics: clrldi. */
|
||||
#define INS_CLEAR_LEFT(dst, src, from) \
|
||||
(RLDICL | S(src) | A(dst) | ((from) << 6) | (1 << 5))
|
||||
|
||||
/* Sign extension for integer operations. */
|
||||
#define UN_EXTS() \
|
||||
if ((flags & (ALT_SIGN_EXT | REG2_SOURCE)) == (ALT_SIGN_EXT | REG2_SOURCE)) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
|
||||
src2 = TMP_REG2; \
|
||||
}
|
||||
|
||||
#define BIN_EXTS() \
|
||||
if (flags & ALT_SIGN_EXT) { \
|
||||
if (flags & REG1_SOURCE) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
|
||||
src1 = TMP_REG1; \
|
||||
} \
|
||||
if (flags & REG2_SOURCE) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
|
||||
src2 = TMP_REG2; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define BIN_IMM_EXTS() \
|
||||
if ((flags & (ALT_SIGN_EXT | REG1_SOURCE)) == (ALT_SIGN_EXT | REG1_SOURCE)) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
|
||||
src1 = TMP_REG1; \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
|
||||
{
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S32)
|
||||
return push_inst(compiler, EXTSW | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 0));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
|
||||
}
|
||||
else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16)
|
||||
return push_inst(compiler, EXTSH | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
UN_EXTS();
|
||||
return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_NEG:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
UN_EXTS();
|
||||
return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (flags & ALT_FORM1)
|
||||
return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst));
|
||||
return push_inst(compiler, CNTLZD | RC(flags) | S(src2) | A(dst));
|
||||
|
||||
case SLJIT_ADD:
|
||||
if (flags & ALT_FORM1) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
BIN_IMM_EXTS();
|
||||
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM4) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff)));
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(dst) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1)));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, ADDC | OERC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_SUB:
|
||||
if (flags & ALT_FORM1) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM2 | ALT_FORM3)) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? CMPI : CMPLI) | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM4 | ALT_FORM5)) {
|
||||
return push_inst(compiler, ((flags & ALT_FORM4) ? CMP : CMPL) | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2));
|
||||
}
|
||||
if (flags & ALT_FORM6) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, CMPLI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm));
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
|
||||
}
|
||||
if (flags & ALT_FORM7) {
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, SUBFC | OERC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_MUL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
BIN_EXTS();
|
||||
if (flags & ALT_FORM2)
|
||||
return push_inst(compiler, MULLW | OERC(flags) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, MULLD | OERC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_AND:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_OR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_XOR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_SHL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
|
||||
}
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, RLDI(dst, src1, compiler->imm, 63 - compiler->imm, 1) | RC(flags));
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SLW : SLD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_LSHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
|
||||
}
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, RLDI(dst, src1, 64 - compiler->imm, compiler->imm, 0) | RC(flags));
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SRW : SRD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_ASHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
|
||||
}
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4));
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 48)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value >> 32)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, 31));
|
||||
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(init_value >> 16)));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins*)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[4] = (inst[4] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins*)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[4] = (inst[4] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw imm)
|
||||
{
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, OR | D(dst) | S1(0) | IMM(imm), DR(dst));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((imm >> 10) & 0x3fffff), DR(dst)));
|
||||
return (imm & 0x3ff) ? push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (imm & 0x3ff), DR(dst)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define ARG2(flags, src2) ((flags & SRC2_IMM) ? IMM(src2) : S2(src2))
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
SLJIT_COMPILE_ASSERT(ICC_IS_SET == SET_FLAGS, icc_is_set_and_set_flags_must_be_the_same);
|
||||
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, OR | D(dst) | S1(0) | S2(src2), DR(dst));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_U8)
|
||||
return push_inst(compiler, AND | D(dst) | S1(src2) | IMM(0xff), DR(dst));
|
||||
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(24), DR(dst)));
|
||||
return push_inst(compiler, SRA | D(dst) | S1(dst) | IMM(24), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(16), DR(dst)));
|
||||
return push_inst(compiler, (op == SLJIT_MOV_S16 ? SRA : SRL) | D(dst) | S1(dst) | IMM(16), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
return push_inst(compiler, XNOR | (flags & SET_FLAGS) | D(dst) | S1(0) | S2(src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
/* sparc 32 does not support SLJIT_KEEP_FLAGS. Not sure I can fix this. */
|
||||
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(src2) | S2(0), SET_FLAGS));
|
||||
FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2(src2), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, BICC | DA(0x1) | (7 & DISP_MASK), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(0) | IMM(32), UNMOVABLE_INS | (flags & SET_FLAGS)));
|
||||
FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(-1), DR(dst)));
|
||||
|
||||
/* Loop. */
|
||||
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(0), SET_FLAGS));
|
||||
FAIL_IF(push_inst(compiler, SLL | D(TMP_REG1) | S1(TMP_REG1) | IMM(1), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, BICC | DA(0xe) | (-2 & DISP_MASK), UNMOVABLE_INS));
|
||||
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_ADD:
|
||||
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
return push_inst(compiler, ADDC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_SUB:
|
||||
return push_inst(compiler, SUB | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
return push_inst(compiler, SUBC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_MUL:
|
||||
FAIL_IF(push_inst(compiler, SMUL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
if (!(flags & SET_FLAGS))
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(dst) | IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, RDY | D(TMP_LINK), DR(TMP_LINK)));
|
||||
return push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(TMP_LINK), MOVABLE_INS | SET_FLAGS);
|
||||
|
||||
case SLJIT_AND:
|
||||
return push_inst(compiler, AND | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_OR:
|
||||
return push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_XOR:
|
||||
return push_inst(compiler, XOR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_SHL:
|
||||
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
|
||||
case SLJIT_LSHR:
|
||||
FAIL_IF(push_inst(compiler, SRL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
|
||||
case SLJIT_ASHR:
|
||||
FAIL_IF(push_inst(compiler, SRA | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((init_value >> 10) & 0x3fffff), DR(dst)));
|
||||
return push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (init_value & 0x3ff), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffc00000) | ((new_target >> 10) & 0x3fffff);
|
||||
inst[1] = (inst[1] & 0xfffffc00) | (new_target & 0x3ff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffc00000) | ((new_constant >> 10) & 0x3fffff);
|
||||
inst[1] = (inst[1] & 0xfffffc00) | (new_constant & 0x3ff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* x86 32-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 emit_do_imm(struct sljit_compiler *compiler, sljit_u8 opcode, sljit_sw imm)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_sw));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1 + sizeof(sljit_sw));
|
||||
*inst++ = opcode;
|
||||
sljit_unaligned_store_sw(inst, imm);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_s32 type, sljit_sw executable_offset)
|
||||
{
|
||||
if (type == SLJIT_JUMP) {
|
||||
*code_ptr++ = JMP_i32;
|
||||
jump->addr++;
|
||||
}
|
||||
else if (type >= SLJIT_FAST_CALL) {
|
||||
*code_ptr++ = CALL_i32;
|
||||
jump->addr++;
|
||||
}
|
||||
else {
|
||||
*code_ptr++ = GROUP_0F;
|
||||
*code_ptr++ = get_jump_code(type);
|
||||
jump->addr += 2;
|
||||
}
|
||||
|
||||
if (jump->flags & JUMP_LABEL)
|
||||
jump->flags |= PATCH_MW;
|
||||
else
|
||||
sljit_unaligned_store_sw(code_ptr, jump->u.target - (jump->addr + 4) - (sljit_uw)executable_offset);
|
||||
code_ptr += 4;
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
sljit_s32 size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
compiler->args = args;
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
/* [esp+0] for saving temporaries and third argument for calls. */
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
#else
|
||||
/* [esp+0] for saving temporaries and space for maximum three arguments. */
|
||||
if (scratches <= 1)
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->saveds_offset = ((scratches == 2) ? 2 : 3) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
if (scratches > 3)
|
||||
compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
|
||||
|
||||
compiler->locals_offset = compiler->saveds_offset;
|
||||
|
||||
if (saveds > 3)
|
||||
compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
|
||||
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
|
||||
|
||||
size = 1 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
size += (args > 0 ? (args * 2) : 0) + (args > 2 ? 2 : 0);
|
||||
#else
|
||||
size += (args > 0 ? (2 + args * 3) : 0);
|
||||
#endif
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(size);
|
||||
PUSH_REG(reg_map[TMP_REG1]);
|
||||
#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (args > 0) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[TMP_REG1] << 3) | 0x4 /* esp */;
|
||||
}
|
||||
#endif
|
||||
if (saveds > 2 || scratches > 9)
|
||||
PUSH_REG(reg_map[SLJIT_S2]);
|
||||
if (saveds > 1 || scratches > 10)
|
||||
PUSH_REG(reg_map[SLJIT_S1]);
|
||||
if (saveds > 0 || scratches > 11)
|
||||
PUSH_REG(reg_map[SLJIT_S0]);
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (args > 0) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S0] << 3) | reg_map[SLJIT_R2];
|
||||
}
|
||||
if (args > 1) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S1] << 3) | reg_map[SLJIT_R1];
|
||||
}
|
||||
if (args > 2) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | 0x4 /* esp */;
|
||||
*inst++ = 0x24;
|
||||
*inst++ = sizeof(sljit_sw) * (3 + 2); /* saveds >= 3 as well. */
|
||||
}
|
||||
#else
|
||||
if (args > 0) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S0] << 3) | reg_map[TMP_REG1];
|
||||
*inst++ = sizeof(sljit_sw) * 2;
|
||||
}
|
||||
if (args > 1) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S1] << 3) | reg_map[TMP_REG1];
|
||||
*inst++ = sizeof(sljit_sw) * 3;
|
||||
}
|
||||
if (args > 2) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | reg_map[TMP_REG1];
|
||||
*inst++ = sizeof(sljit_sw) * 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_ASSERT(SLJIT_LOCALS_OFFSET > 0);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Ignore pushed registers and SLJIT_LOCALS_OFFSET when computing the aligned local size. */
|
||||
saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
|
||||
#else
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
|
||||
else
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
|
||||
#endif
|
||||
|
||||
compiler->local_size = local_size;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (local_size > 1024) {
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_R0], local_size));
|
||||
#else
|
||||
/* Space for a single argument. This amount is excluded when the stack is allocated below. */
|
||||
local_size -= sizeof(sljit_sw);
|
||||
FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_R0], local_size));
|
||||
FAIL_IF(emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, sizeof(sljit_sw)));
|
||||
#endif
|
||||
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack)));
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_ASSERT(local_size > 0);
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
if (options & SLJIT_F64_ALIGNMENT) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_SP, 0);
|
||||
|
||||
/* Some space might allocated during sljit_grow_stack() above on WIN32. */
|
||||
FAIL_IF(emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size + sizeof(sljit_sw)));
|
||||
|
||||
#if defined _WIN32 && !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->local_size > 1024)
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
TMP_REG1, 0, TMP_REG1, 0, SLJIT_IMM, sizeof(sljit_sw)));
|
||||
#endif
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 6);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(6);
|
||||
inst[0] = GROUP_BINARY_81;
|
||||
inst[1] = MOD_REG | AND | reg_map[SLJIT_SP];
|
||||
sljit_unaligned_store_sw(inst + 2, ~(sizeof(sljit_f64) - 1));
|
||||
|
||||
/* The real local size must be used. */
|
||||
return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), compiler->local_size, TMP_REG1, 0);
|
||||
}
|
||||
#endif
|
||||
return emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
compiler->args = args;
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
/* [esp+0] for saving temporaries and third argument for calls. */
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
#else
|
||||
/* [esp+0] for saving temporaries and space for maximum three arguments. */
|
||||
if (scratches <= 1)
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->saveds_offset = ((scratches == 2) ? 2 : 3) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
if (scratches > 3)
|
||||
compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
|
||||
|
||||
compiler->locals_offset = compiler->saveds_offset;
|
||||
|
||||
if (saveds > 3)
|
||||
compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
|
||||
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
compiler->local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
|
||||
#else
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
|
||||
else
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
|
||||
SLJIT_ASSERT(compiler->args >= 0);
|
||||
|
||||
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
|
||||
|
||||
SLJIT_ASSERT(compiler->local_size > 0);
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
if (compiler->options & SLJIT_F64_ALIGNMENT)
|
||||
EMIT_MOV(compiler, SLJIT_SP, 0, SLJIT_MEM1(SLJIT_SP), compiler->local_size)
|
||||
else
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
|
||||
#else
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
|
||||
#endif
|
||||
|
||||
size = 2 + (compiler->scratches > 7 ? (compiler->scratches - 7) : 0) +
|
||||
(compiler->saveds <= 3 ? compiler->saveds : 3);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->args > 2)
|
||||
size += 2;
|
||||
#else
|
||||
if (compiler->args > 0)
|
||||
size += 2;
|
||||
#endif
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(size);
|
||||
|
||||
if (compiler->saveds > 0 || compiler->scratches > 11)
|
||||
POP_REG(reg_map[SLJIT_S0]);
|
||||
if (compiler->saveds > 1 || compiler->scratches > 10)
|
||||
POP_REG(reg_map[SLJIT_S1]);
|
||||
if (compiler->saveds > 2 || compiler->scratches > 9)
|
||||
POP_REG(reg_map[SLJIT_S2]);
|
||||
POP_REG(reg_map[TMP_REG1]);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->args > 2)
|
||||
RET_I16(sizeof(sljit_sw));
|
||||
else
|
||||
RET();
|
||||
#else
|
||||
RET();
|
||||
#endif
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Size contains the flags as well. */
|
||||
static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
|
||||
/* The register or immediate operand. */
|
||||
sljit_s32 a, sljit_sw imma,
|
||||
/* The general operand (not immediate). */
|
||||
sljit_s32 b, sljit_sw immb)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_u8 *buf_ptr;
|
||||
sljit_s32 flags = size & ~0xf;
|
||||
sljit_s32 inst_size;
|
||||
|
||||
/* Both cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
|
||||
/* Size flags not allowed for typed instructions. */
|
||||
SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
|
||||
/* Both size flags cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
|
||||
/* SSE2 and immediate is not possible. */
|
||||
SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
|
||||
SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
|
||||
&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
|
||||
&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
|
||||
|
||||
size &= 0xf;
|
||||
inst_size = size;
|
||||
|
||||
if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
|
||||
inst_size++;
|
||||
if (flags & EX86_PREF_66)
|
||||
inst_size++;
|
||||
|
||||
/* Calculate size of b. */
|
||||
inst_size += 1; /* mod r/m byte. */
|
||||
if (b & SLJIT_MEM) {
|
||||
if ((b & REG_MASK) == SLJIT_UNUSED)
|
||||
inst_size += sizeof(sljit_sw);
|
||||
else if (immb != 0 && !(b & OFFS_REG_MASK)) {
|
||||
/* Immediate operand. */
|
||||
if (immb <= 127 && immb >= -128)
|
||||
inst_size += sizeof(sljit_s8);
|
||||
else
|
||||
inst_size += sizeof(sljit_sw);
|
||||
}
|
||||
|
||||
if ((b & REG_MASK) == SLJIT_SP && !(b & OFFS_REG_MASK))
|
||||
b |= TO_OFFS_REG(SLJIT_SP);
|
||||
|
||||
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED)
|
||||
inst_size += 1; /* SIB byte. */
|
||||
}
|
||||
|
||||
/* Calculate size of a. */
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BIN_INS) {
|
||||
if (imma <= 127 && imma >= -128) {
|
||||
inst_size += 1;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
} else
|
||||
inst_size += 4;
|
||||
}
|
||||
else if (flags & EX86_SHIFT_INS) {
|
||||
imma &= 0x1f;
|
||||
if (imma != 1) {
|
||||
inst_size ++;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
}
|
||||
} else if (flags & EX86_BYTE_ARG)
|
||||
inst_size++;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
inst_size += sizeof(short);
|
||||
else
|
||||
inst_size += sizeof(sljit_sw);
|
||||
}
|
||||
else
|
||||
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
|
||||
PTR_FAIL_IF(!inst);
|
||||
|
||||
/* Encoding the byte. */
|
||||
INC_SIZE(inst_size);
|
||||
if (flags & EX86_PREF_F2)
|
||||
*inst++ = 0xf2;
|
||||
if (flags & EX86_PREF_F3)
|
||||
*inst++ = 0xf3;
|
||||
if (flags & EX86_PREF_66)
|
||||
*inst++ = 0x66;
|
||||
|
||||
buf_ptr = inst + size;
|
||||
|
||||
/* Encode mod/rm byte. */
|
||||
if (!(flags & EX86_SHIFT_INS)) {
|
||||
if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
|
||||
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
|
||||
|
||||
if ((a & SLJIT_IMM) || (a == 0))
|
||||
*buf_ptr = 0;
|
||||
else if (!(flags & EX86_SSE2_OP1))
|
||||
*buf_ptr = reg_map[a] << 3;
|
||||
else
|
||||
*buf_ptr = a << 3;
|
||||
}
|
||||
else {
|
||||
if (a & SLJIT_IMM) {
|
||||
if (imma == 1)
|
||||
*inst = GROUP_SHIFT_1;
|
||||
else
|
||||
*inst = GROUP_SHIFT_N;
|
||||
} else
|
||||
*inst = GROUP_SHIFT_CL;
|
||||
*buf_ptr = 0;
|
||||
}
|
||||
|
||||
if (!(b & SLJIT_MEM))
|
||||
*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_map[b] : b);
|
||||
else if ((b & REG_MASK) != SLJIT_UNUSED) {
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
|
||||
if (immb != 0) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr |= 0x40;
|
||||
else
|
||||
*buf_ptr |= 0x80;
|
||||
}
|
||||
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
|
||||
*buf_ptr++ |= reg_map[b & REG_MASK];
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3);
|
||||
}
|
||||
|
||||
if (immb != 0) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr++ = immb; /* 8 bit displacement. */
|
||||
else {
|
||||
sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_sw);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3) | (immb << 6);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*buf_ptr++ |= 0x05;
|
||||
sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_sw);
|
||||
}
|
||||
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BYTE_ARG)
|
||||
*buf_ptr = imma;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
sljit_unaligned_store_s16(buf_ptr, imma);
|
||||
else if (!(flags & EX86_SHIFT_INS))
|
||||
sljit_unaligned_store_sw(buf_ptr, imma);
|
||||
}
|
||||
|
||||
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Call / return instructions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static SLJIT_INLINE sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
inst = (sljit_u8*)ensure_buf(compiler, type >= SLJIT_CALL3 ? 1 + 2 + 1 : 1 + 2);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(type >= SLJIT_CALL3 ? 2 + 1 : 2);
|
||||
|
||||
if (type >= SLJIT_CALL3)
|
||||
PUSH_REG(reg_map[SLJIT_R2]);
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_R2] << 3) | reg_map[SLJIT_R0];
|
||||
#else
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 * (type - SLJIT_CALL0));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4 * (type - SLJIT_CALL0));
|
||||
|
||||
*inst++ = MOV_rm_r;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_R0] << 3) | 0x4 /* SIB */;
|
||||
*inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_SP];
|
||||
*inst++ = 0;
|
||||
if (type >= SLJIT_CALL2) {
|
||||
*inst++ = MOV_rm_r;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_R1] << 3) | 0x4 /* SIB */;
|
||||
*inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_SP];
|
||||
*inst++ = sizeof(sljit_sw);
|
||||
}
|
||||
if (type >= SLJIT_CALL3) {
|
||||
*inst++ = MOV_rm_r;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_R2] << 3) | 0x4 /* SIB */;
|
||||
*inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_SP];
|
||||
*inst++ = 2 * sizeof(sljit_sw);
|
||||
}
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
CHECK_EXTRA_REGS(dst, dstw, (void)0);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
dst = TMP_REG1;
|
||||
|
||||
if (FAST_IS_REG(dst)) {
|
||||
/* Unused dest is possible here. */
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(1);
|
||||
POP_REG(reg_map[dst]);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Memory. */
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = POP_rm;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
CHECK_EXTRA_REGS(src, srcw, (void)0);
|
||||
|
||||
if (FAST_IS_REG(src)) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(1 + 1);
|
||||
PUSH_REG(reg_map[src]);
|
||||
}
|
||||
else if (src & SLJIT_MEM) {
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = GROUP_FF;
|
||||
*inst |= PUSH_rm;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
}
|
||||
else {
|
||||
/* SLJIT_IMM. */
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(5 + 1);
|
||||
*inst++ = PUSH_i32;
|
||||
sljit_unaligned_store_sw(inst, srcw);
|
||||
inst += sizeof(sljit_sw);
|
||||
}
|
||||
|
||||
RET();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
@ -0,0 +1,739 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* x86 64-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 emit_load_imm64(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(2 + sizeof(sljit_sw));
|
||||
*inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
|
||||
*inst++ = MOV_r_i32 + (reg_map[reg] & 0x7);
|
||||
sljit_unaligned_store_sw(inst, imm);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_s32 type)
|
||||
{
|
||||
if (type < SLJIT_JUMP) {
|
||||
/* Invert type. */
|
||||
*code_ptr++ = get_jump_code(type ^ 0x1) - 0x10;
|
||||
*code_ptr++ = 10 + 3;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT(reg_map[TMP_REG3] == 9);
|
||||
*code_ptr++ = REX_W | REX_B;
|
||||
*code_ptr++ = MOV_r_i32 + 1;
|
||||
jump->addr = (sljit_uw)code_ptr;
|
||||
|
||||
if (jump->flags & JUMP_LABEL)
|
||||
jump->flags |= PATCH_MD;
|
||||
else
|
||||
sljit_unaligned_store_sw(code_ptr, jump->u.target);
|
||||
|
||||
code_ptr += sizeof(sljit_sw);
|
||||
*code_ptr++ = REX_B;
|
||||
*code_ptr++ = GROUP_FF;
|
||||
*code_ptr++ = (type >= SLJIT_FAST_CALL) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1);
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
sljit_s32 i, tmp, size, saved_register_size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Two/four register slots for parameters plus space for xmm6 register if needed. */
|
||||
if (fscratches >= 6 || fsaveds >= 1)
|
||||
compiler->locals_offset = 6 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
/* Including the return address saved by the call instruction. */
|
||||
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
|
||||
|
||||
tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
|
||||
for (i = SLJIT_S0; i >= tmp; i--) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
PUSH_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
PUSH_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
if (args > 0) {
|
||||
size = args * 3;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(size);
|
||||
|
||||
#ifndef _WIN64
|
||||
if (args > 0) {
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x7 /* rdi */;
|
||||
}
|
||||
if (args > 1) {
|
||||
*inst++ = REX_W | REX_R;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_lmap[SLJIT_S1] << 3) | 0x6 /* rsi */;
|
||||
}
|
||||
if (args > 2) {
|
||||
*inst++ = REX_W | REX_R;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_lmap[SLJIT_S2] << 3) | 0x2 /* rdx */;
|
||||
}
|
||||
#else
|
||||
if (args > 0) {
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x1 /* rcx */;
|
||||
}
|
||||
if (args > 1) {
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S1] << 3) | 0x2 /* rdx */;
|
||||
}
|
||||
if (args > 2) {
|
||||
*inst++ = REX_W | REX_B;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S2] << 3) | 0x0 /* r8 */;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
|
||||
compiler->local_size = local_size;
|
||||
|
||||
#ifdef _WIN64
|
||||
if (local_size > 1024) {
|
||||
/* Allocate stack for the callback, which grows the stack. */
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + (3 + sizeof(sljit_s32)));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4 + (3 + sizeof(sljit_s32)));
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_83;
|
||||
*inst++ = MOD_REG | SUB | reg_map[SLJIT_SP];
|
||||
/* Allocated size for registers must be divisible by 8. */
|
||||
SLJIT_ASSERT(!(saved_register_size & 0x7));
|
||||
/* Aligned to 16 byte. */
|
||||
if (saved_register_size & 0x8) {
|
||||
*inst++ = 5 * sizeof(sljit_sw);
|
||||
local_size -= 5 * sizeof(sljit_sw);
|
||||
} else {
|
||||
*inst++ = 4 * sizeof(sljit_sw);
|
||||
local_size -= 4 * sizeof(sljit_sw);
|
||||
}
|
||||
/* Second instruction */
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R0] < 8);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_rm_i32;
|
||||
*inst++ = MOD_REG | reg_lmap[SLJIT_R0];
|
||||
sljit_unaligned_store_s32(inst, local_size);
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
compiler->skip_checks = 1;
|
||||
#endif
|
||||
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack)));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (local_size > 0) {
|
||||
if (local_size <= 127) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_83;
|
||||
*inst++ = MOD_REG | SUB | reg_map[SLJIT_SP];
|
||||
*inst++ = local_size;
|
||||
}
|
||||
else {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 7);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(7);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_81;
|
||||
*inst++ = MOD_REG | SUB | reg_map[SLJIT_SP];
|
||||
sljit_unaligned_store_s32(inst, local_size);
|
||||
inst += sizeof(sljit_s32);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Save xmm6 register: movaps [rsp + 0x20], xmm6 */
|
||||
if (fscratches >= 6 || fsaveds >= 1) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(5);
|
||||
*inst++ = GROUP_0F;
|
||||
sljit_unaligned_store_s32(inst, 0x20247429);
|
||||
}
|
||||
#endif
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
sljit_s32 saved_register_size;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Two/four register slots for parameters plus space for xmm6 register if needed. */
|
||||
if (fscratches >= 6 || fsaveds >= 1)
|
||||
compiler->locals_offset = 6 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
/* Including the return address saved by the call instruction. */
|
||||
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
|
||||
compiler->local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 i, tmp, size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
|
||||
|
||||
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Restore xmm6 register: movaps xmm6, [rsp + 0x20] */
|
||||
if (compiler->fscratches >= 6 || compiler->fsaveds >= 1) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(5);
|
||||
*inst++ = GROUP_0F;
|
||||
sljit_unaligned_store_s32(inst, 0x20247428);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (compiler->local_size > 0) {
|
||||
if (compiler->local_size <= 127) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_83;
|
||||
*inst++ = MOD_REG | ADD | 4;
|
||||
*inst = compiler->local_size;
|
||||
}
|
||||
else {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 7);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(7);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_81;
|
||||
*inst++ = MOD_REG | ADD | 4;
|
||||
sljit_unaligned_store_s32(inst, compiler->local_size);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = compiler->scratches;
|
||||
for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
POP_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
|
||||
for (i = tmp; i <= SLJIT_S0; i++) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
POP_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
RET();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static sljit_s32 emit_do_imm32(struct sljit_compiler *compiler, sljit_u8 rex, sljit_u8 opcode, sljit_sw imm)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_s32 length = 1 + (rex ? 1 : 0) + sizeof(sljit_s32);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + length);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(length);
|
||||
if (rex)
|
||||
*inst++ = rex;
|
||||
*inst++ = opcode;
|
||||
sljit_unaligned_store_s32(inst, imm);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
|
||||
/* The register or immediate operand. */
|
||||
sljit_s32 a, sljit_sw imma,
|
||||
/* The general operand (not immediate). */
|
||||
sljit_s32 b, sljit_sw immb)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_u8 *buf_ptr;
|
||||
sljit_u8 rex = 0;
|
||||
sljit_s32 flags = size & ~0xf;
|
||||
sljit_s32 inst_size;
|
||||
|
||||
/* The immediate operand must be 32 bit. */
|
||||
SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma));
|
||||
/* Both cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
|
||||
/* Size flags not allowed for typed instructions. */
|
||||
SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
|
||||
/* Both size flags cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
|
||||
/* SSE2 and immediate is not possible. */
|
||||
SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
|
||||
SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
|
||||
&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
|
||||
&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
|
||||
|
||||
size &= 0xf;
|
||||
inst_size = size;
|
||||
|
||||
if (!compiler->mode32 && !(flags & EX86_NO_REXW))
|
||||
rex |= REX_W;
|
||||
else if (flags & EX86_REX)
|
||||
rex |= REX;
|
||||
|
||||
if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
|
||||
inst_size++;
|
||||
if (flags & EX86_PREF_66)
|
||||
inst_size++;
|
||||
|
||||
/* Calculate size of b. */
|
||||
inst_size += 1; /* mod r/m byte. */
|
||||
if (b & SLJIT_MEM) {
|
||||
if (!(b & OFFS_REG_MASK)) {
|
||||
if (NOT_HALFWORD(immb)) {
|
||||
PTR_FAIL_IF(emit_load_imm64(compiler, TMP_REG3, immb));
|
||||
immb = 0;
|
||||
if (b & REG_MASK)
|
||||
b |= TO_OFFS_REG(TMP_REG3);
|
||||
else
|
||||
b |= TMP_REG3;
|
||||
}
|
||||
else if (reg_lmap[b & REG_MASK] == 4)
|
||||
b |= TO_OFFS_REG(SLJIT_SP);
|
||||
}
|
||||
|
||||
if ((b & REG_MASK) == SLJIT_UNUSED)
|
||||
inst_size += 1 + sizeof(sljit_s32); /* SIB byte required to avoid RIP based addressing. */
|
||||
else {
|
||||
if (reg_map[b & REG_MASK] >= 8)
|
||||
rex |= REX_B;
|
||||
|
||||
if (immb != 0 && (!(b & OFFS_REG_MASK) || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP))) {
|
||||
/* Immediate operand. */
|
||||
if (immb <= 127 && immb >= -128)
|
||||
inst_size += sizeof(sljit_s8);
|
||||
else
|
||||
inst_size += sizeof(sljit_s32);
|
||||
}
|
||||
else if (reg_lmap[b & REG_MASK] == 5)
|
||||
inst_size += sizeof(sljit_s8);
|
||||
|
||||
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED) {
|
||||
inst_size += 1; /* SIB byte. */
|
||||
if (reg_map[OFFS_REG(b)] >= 8)
|
||||
rex |= REX_X;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(flags & EX86_SSE2_OP2) && reg_map[b] >= 8)
|
||||
rex |= REX_B;
|
||||
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BIN_INS) {
|
||||
if (imma <= 127 && imma >= -128) {
|
||||
inst_size += 1;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
} else
|
||||
inst_size += 4;
|
||||
}
|
||||
else if (flags & EX86_SHIFT_INS) {
|
||||
imma &= compiler->mode32 ? 0x1f : 0x3f;
|
||||
if (imma != 1) {
|
||||
inst_size ++;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
}
|
||||
} else if (flags & EX86_BYTE_ARG)
|
||||
inst_size++;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
inst_size += sizeof(short);
|
||||
else
|
||||
inst_size += sizeof(sljit_s32);
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
|
||||
/* reg_map[SLJIT_PREF_SHIFT_REG] is less than 8. */
|
||||
if (!(flags & EX86_SSE2_OP1) && reg_map[a] >= 8)
|
||||
rex |= REX_R;
|
||||
}
|
||||
|
||||
if (rex)
|
||||
inst_size++;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
|
||||
PTR_FAIL_IF(!inst);
|
||||
|
||||
/* Encoding the byte. */
|
||||
INC_SIZE(inst_size);
|
||||
if (flags & EX86_PREF_F2)
|
||||
*inst++ = 0xf2;
|
||||
if (flags & EX86_PREF_F3)
|
||||
*inst++ = 0xf3;
|
||||
if (flags & EX86_PREF_66)
|
||||
*inst++ = 0x66;
|
||||
if (rex)
|
||||
*inst++ = rex;
|
||||
buf_ptr = inst + size;
|
||||
|
||||
/* Encode mod/rm byte. */
|
||||
if (!(flags & EX86_SHIFT_INS)) {
|
||||
if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
|
||||
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
|
||||
|
||||
if ((a & SLJIT_IMM) || (a == 0))
|
||||
*buf_ptr = 0;
|
||||
else if (!(flags & EX86_SSE2_OP1))
|
||||
*buf_ptr = reg_lmap[a] << 3;
|
||||
else
|
||||
*buf_ptr = a << 3;
|
||||
}
|
||||
else {
|
||||
if (a & SLJIT_IMM) {
|
||||
if (imma == 1)
|
||||
*inst = GROUP_SHIFT_1;
|
||||
else
|
||||
*inst = GROUP_SHIFT_N;
|
||||
} else
|
||||
*inst = GROUP_SHIFT_CL;
|
||||
*buf_ptr = 0;
|
||||
}
|
||||
|
||||
if (!(b & SLJIT_MEM))
|
||||
*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_lmap[b] : b);
|
||||
else if ((b & REG_MASK) != SLJIT_UNUSED) {
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
|
||||
if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr |= 0x40;
|
||||
else
|
||||
*buf_ptr |= 0x80;
|
||||
}
|
||||
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
|
||||
*buf_ptr++ |= reg_lmap[b & REG_MASK];
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3);
|
||||
}
|
||||
|
||||
if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr++ = immb; /* 8 bit displacement. */
|
||||
else {
|
||||
sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_s32);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (reg_lmap[b & REG_MASK] == 5)
|
||||
*buf_ptr |= 0x40;
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6);
|
||||
if (reg_lmap[b & REG_MASK] == 5)
|
||||
*buf_ptr++ = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = 0x25;
|
||||
sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_s32);
|
||||
}
|
||||
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BYTE_ARG)
|
||||
*buf_ptr = imma;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
sljit_unaligned_store_s16(buf_ptr, imma);
|
||||
else if (!(flags & EX86_SHIFT_INS))
|
||||
sljit_unaligned_store_s32(buf_ptr, imma);
|
||||
}
|
||||
|
||||
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Call / return instructions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static SLJIT_INLINE sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
#ifndef _WIN64
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R1] == 6 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
|
||||
if (type >= SLJIT_CALL3) {
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x2 /* rdx */ << 3) | reg_lmap[SLJIT_R2];
|
||||
}
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x7 /* rdi */ << 3) | reg_lmap[SLJIT_R0];
|
||||
#else
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R1] == 2 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
|
||||
if (type >= SLJIT_CALL3) {
|
||||
*inst++ = REX_W | REX_R;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x0 /* r8 */ << 3) | reg_lmap[SLJIT_R2];
|
||||
}
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x1 /* rcx */ << 3) | reg_lmap[SLJIT_R0];
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
dst = TMP_REG1;
|
||||
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (reg_map[dst] < 8) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
POP_REG(reg_lmap[dst]);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(2);
|
||||
*inst++ = REX_B;
|
||||
POP_REG(reg_lmap[dst]);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* REX_W is not necessary (src is not immediate). */
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = POP_rm;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
if ((src & SLJIT_IMM) && NOT_HALFWORD(srcw)) {
|
||||
FAIL_IF(emit_load_imm64(compiler, TMP_REG1, srcw));
|
||||
src = TMP_REG1;
|
||||
}
|
||||
|
||||
if (FAST_IS_REG(src)) {
|
||||
if (reg_map[src] < 8) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(1 + 1);
|
||||
PUSH_REG(reg_lmap[src]);
|
||||
}
|
||||
else {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(2 + 1);
|
||||
*inst++ = REX_B;
|
||||
PUSH_REG(reg_lmap[src]);
|
||||
}
|
||||
}
|
||||
else if (src & SLJIT_MEM) {
|
||||
/* REX_W is not necessary (src is not immediate). */
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = GROUP_FF;
|
||||
*inst |= PUSH_rm;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(IS_HALFWORD(srcw));
|
||||
/* SLJIT_IMM. */
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(5 + 1);
|
||||
*inst++ = PUSH_i32;
|
||||
sljit_unaligned_store_s32(inst, srcw);
|
||||
inst += sizeof(sljit_s32);
|
||||
}
|
||||
|
||||
RET();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Extend input */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_u8* inst;
|
||||
sljit_s32 dst_r;
|
||||
|
||||
compiler->mode32 = 0;
|
||||
|
||||
if (dst == SLJIT_UNUSED && !(src & SLJIT_MEM))
|
||||
return SLJIT_SUCCESS; /* Empty instruction. */
|
||||
|
||||
if (src & SLJIT_IMM) {
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (sign || ((sljit_uw)srcw <= 0x7fffffff)) {
|
||||
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = MOV_rm_i32;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
return emit_load_imm64(compiler, dst, srcw);
|
||||
}
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = MOV_rm_i32;
|
||||
compiler->mode32 = 0;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
|
||||
if ((dst & SLJIT_MEM) && FAST_IS_REG(src))
|
||||
dst_r = src;
|
||||
else {
|
||||
if (sign) {
|
||||
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = MOVSXD_r_rm;
|
||||
} else {
|
||||
compiler->mode32 = 1;
|
||||
FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw));
|
||||
compiler->mode32 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM) {
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = MOV_rm_r;
|
||||
compiler->mode32 = 0;
|
||||
}
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,421 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file contains a simple executable memory allocator
|
||||
|
||||
It is assumed, that executable code blocks are usually medium (or sometimes
|
||||
large) memory blocks, and the allocator is not too frequently called (less
|
||||
optimized than other allocators). Thus, using it as a generic allocator is
|
||||
not suggested.
|
||||
|
||||
How does it work:
|
||||
Memory is allocated in continuous memory areas called chunks by alloc_chunk()
|
||||
Chunk format:
|
||||
[ block ][ block ] ... [ block ][ block terminator ]
|
||||
|
||||
All blocks and the block terminator is started with block_header. The block
|
||||
header contains the size of the previous and the next block. These sizes
|
||||
can also contain special values.
|
||||
Block size:
|
||||
0 - The block is a free_block, with a different size member.
|
||||
1 - The block is a block terminator.
|
||||
n - The block is used at the moment, and the value contains its size.
|
||||
Previous block size:
|
||||
0 - This is the first block of the memory chunk.
|
||||
n - The size of the previous block.
|
||||
|
||||
Using these size values we can go forward or backward on the block chain.
|
||||
The unused blocks are stored in a chain list pointed by free_blocks. This
|
||||
list is useful if we need to find a suitable memory area when the allocator
|
||||
is called.
|
||||
|
||||
When a block is freed, the new free block is connected to its adjacent free
|
||||
blocks if possible.
|
||||
|
||||
[ free block ][ used block ][ free block ]
|
||||
and "used block" is freed, the three blocks are connected together:
|
||||
[ one big free block ]
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* System (OS) functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* 64 KByte. */
|
||||
#define CHUNK_SIZE 0x10000
|
||||
|
||||
struct chunk_header {
|
||||
void *executable;
|
||||
int fd;
|
||||
};
|
||||
|
||||
/*
|
||||
alloc_chunk / free_chunk :
|
||||
* allocate executable system memory chunks
|
||||
* the size is always divisible by CHUNK_SIZE
|
||||
allocator_grab_lock / allocator_release_lock :
|
||||
* make the allocator thread safe
|
||||
* can be empty if the OS (or the application) does not support threading
|
||||
* only the allocator requires this lock, sljit is fully thread safe
|
||||
as it only uses local variables
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef O_NOATIME
|
||||
#define O_NOATIME 0
|
||||
#endif
|
||||
|
||||
#ifdef __O_TMPFILE
|
||||
#ifndef O_TMPFILE
|
||||
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int mkostemp(char *template, int flags);
|
||||
char *secure_getenv(const char *name);
|
||||
|
||||
static SLJIT_INLINE int create_tempfile(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
char tmp_name[256];
|
||||
size_t tmp_name_len;
|
||||
char *dir;
|
||||
size_t len;
|
||||
|
||||
#ifdef P_tmpdir
|
||||
len = (P_tmpdir != NULL) ? strlen(P_tmpdir) : 0;
|
||||
|
||||
if (len > 0 && len < sizeof(tmp_name)) {
|
||||
strcpy(tmp_name, P_tmpdir);
|
||||
tmp_name_len = len;
|
||||
}
|
||||
else {
|
||||
strcpy(tmp_name, "/tmp");
|
||||
tmp_name_len = 4;
|
||||
}
|
||||
#else
|
||||
strcpy(tmp_name, "/tmp");
|
||||
tmp_name_len = 4;
|
||||
#endif
|
||||
|
||||
dir = secure_getenv("TMPDIR");
|
||||
if (dir) {
|
||||
len = strlen(dir);
|
||||
if (len > 0 && len < sizeof(tmp_name)) {
|
||||
strcpy(tmp_name, dir);
|
||||
tmp_name_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
SLJIT_ASSERT(tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name));
|
||||
|
||||
while (tmp_name_len > 0 && tmp_name[tmp_name_len - 1] == '/') {
|
||||
tmp_name_len--;
|
||||
tmp_name[tmp_name_len] = '\0';
|
||||
}
|
||||
|
||||
#ifdef O_TMPFILE
|
||||
fd = open(tmp_name, O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, S_IRUSR | S_IWUSR);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
#endif
|
||||
|
||||
if (tmp_name_len + 7 >= sizeof(tmp_name))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(tmp_name + tmp_name_len, "/XXXXXX");
|
||||
fd = mkostemp(tmp_name, O_CLOEXEC | O_NOATIME);
|
||||
|
||||
if (fd == -1)
|
||||
return fd;
|
||||
|
||||
if (unlink(tmp_name)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE struct chunk_header* alloc_chunk(sljit_uw size)
|
||||
{
|
||||
struct chunk_header *retval;
|
||||
int fd;
|
||||
|
||||
fd = create_tempfile();
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
|
||||
if (ftruncate(fd, size)) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retval = (struct chunk_header *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
|
||||
if (retval == MAP_FAILED) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retval->executable = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
|
||||
|
||||
if (retval->executable == MAP_FAILED) {
|
||||
munmap(retval, size);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retval->fd = fd;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
|
||||
{
|
||||
struct chunk_header *header = ((struct chunk_header *)chunk) - 1;
|
||||
|
||||
int fd = header->fd;
|
||||
munmap(header->executable, size);
|
||||
munmap(header, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Common functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define CHUNK_MASK (~(CHUNK_SIZE - 1))
|
||||
|
||||
struct block_header {
|
||||
sljit_uw size;
|
||||
sljit_uw prev_size;
|
||||
sljit_sw executable_offset;
|
||||
};
|
||||
|
||||
struct free_block {
|
||||
struct block_header header;
|
||||
struct free_block *next;
|
||||
struct free_block *prev;
|
||||
sljit_uw size;
|
||||
};
|
||||
|
||||
#define AS_BLOCK_HEADER(base, offset) \
|
||||
((struct block_header*)(((sljit_u8*)base) + offset))
|
||||
#define AS_FREE_BLOCK(base, offset) \
|
||||
((struct free_block*)(((sljit_u8*)base) + offset))
|
||||
#define MEM_START(base) ((void*)((base) + 1))
|
||||
#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7) & ~7)
|
||||
|
||||
static struct free_block* free_blocks;
|
||||
static sljit_uw allocated_size;
|
||||
static sljit_uw total_size;
|
||||
|
||||
static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
|
||||
{
|
||||
free_block->header.size = 0;
|
||||
free_block->size = size;
|
||||
|
||||
free_block->next = free_blocks;
|
||||
free_block->prev = NULL;
|
||||
if (free_blocks)
|
||||
free_blocks->prev = free_block;
|
||||
free_blocks = free_block;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
|
||||
{
|
||||
if (free_block->next)
|
||||
free_block->next->prev = free_block->prev;
|
||||
|
||||
if (free_block->prev)
|
||||
free_block->prev->next = free_block->next;
|
||||
else {
|
||||
SLJIT_ASSERT(free_blocks == free_block);
|
||||
free_blocks = free_block->next;
|
||||
}
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
||||
{
|
||||
struct chunk_header *chunk_header;
|
||||
struct block_header *header;
|
||||
struct block_header *next_header;
|
||||
struct free_block *free_block;
|
||||
sljit_uw chunk_size;
|
||||
sljit_sw executable_offset;
|
||||
|
||||
allocator_grab_lock();
|
||||
if (size < (64 - sizeof(struct block_header)))
|
||||
size = (64 - sizeof(struct block_header));
|
||||
size = ALIGN_SIZE(size);
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
if (free_block->size >= size) {
|
||||
chunk_size = free_block->size;
|
||||
if (chunk_size > size + 64) {
|
||||
/* We just cut a block from the end of the free block. */
|
||||
chunk_size -= size;
|
||||
free_block->size = chunk_size;
|
||||
header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
header->prev_size = chunk_size;
|
||||
header->executable_offset = free_block->header.executable_offset;
|
||||
AS_BLOCK_HEADER(header, size)->prev_size = size;
|
||||
}
|
||||
else {
|
||||
sljit_remove_free_block(free_block);
|
||||
header = (struct block_header*)free_block;
|
||||
size = chunk_size;
|
||||
}
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
free_block = free_block->next;
|
||||
}
|
||||
|
||||
chunk_size = sizeof(struct chunk_header) + sizeof(struct block_header);
|
||||
chunk_size = (chunk_size + size + CHUNK_SIZE - 1) & CHUNK_MASK;
|
||||
|
||||
chunk_header = alloc_chunk(chunk_size);
|
||||
if (!chunk_header) {
|
||||
allocator_release_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
executable_offset = (sljit_sw)((sljit_u8*)chunk_header->executable - (sljit_u8*)chunk_header);
|
||||
|
||||
chunk_size -= sizeof(struct chunk_header) + sizeof(struct block_header);
|
||||
total_size += chunk_size;
|
||||
|
||||
header = (struct block_header *)(chunk_header + 1);
|
||||
|
||||
header->prev_size = 0;
|
||||
header->executable_offset = executable_offset;
|
||||
if (chunk_size > size + 64) {
|
||||
/* Cut the allocated space into a free and a used block. */
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
chunk_size -= size;
|
||||
|
||||
free_block = AS_FREE_BLOCK(header, size);
|
||||
free_block->header.prev_size = size;
|
||||
free_block->header.executable_offset = executable_offset;
|
||||
sljit_insert_free_block(free_block, chunk_size);
|
||||
next_header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
}
|
||||
else {
|
||||
/* All space belongs to this allocation. */
|
||||
allocated_size += chunk_size;
|
||||
header->size = chunk_size;
|
||||
next_header = AS_BLOCK_HEADER(header, chunk_size);
|
||||
}
|
||||
next_header->size = 1;
|
||||
next_header->prev_size = chunk_size;
|
||||
next_header->executable_offset = executable_offset;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
|
||||
{
|
||||
struct block_header *header;
|
||||
struct free_block* free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
|
||||
header = AS_BLOCK_HEADER(header, -header->executable_offset);
|
||||
allocated_size -= header->size;
|
||||
|
||||
/* Connecting free blocks together if possible. */
|
||||
|
||||
/* If header->prev_size == 0, free_block will equal to header.
|
||||
In this case, free_block->header.size will be > 0. */
|
||||
free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
|
||||
if (SLJIT_UNLIKELY(!free_block->header.size)) {
|
||||
free_block->size += header->size;
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
else {
|
||||
free_block = (struct free_block*)header;
|
||||
sljit_insert_free_block(free_block, header->size);
|
||||
}
|
||||
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
if (SLJIT_UNLIKELY(!header->size)) {
|
||||
free_block->size += ((struct free_block*)header)->size;
|
||||
sljit_remove_free_block((struct free_block*)header);
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
|
||||
/* The whole chunk is free. */
|
||||
if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
|
||||
/* If this block is freed, we still have (allocated_size / 2) free space. */
|
||||
if (total_size - free_block->size > (allocated_size * 3 / 2)) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
}
|
||||
|
||||
allocator_release_lock();
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
|
||||
{
|
||||
struct free_block* free_block;
|
||||
struct free_block* next_free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
next_free_block = free_block->next;
|
||||
if (!free_block->header.prev_size &&
|
||||
AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
free_block = next_free_block;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
|
||||
allocator_release_lock();
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr)
|
||||
{
|
||||
return ((struct block_header *)(ptr))[-1].executable_offset;
|
||||
}
|
||||
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Locks */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) || (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
static SLJIT_INLINE void allocator_grab_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void allocator_release_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
|
||||
|
||||
#elif defined(_WIN32) /* SLJIT_SINGLE_THREADED */
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
static HANDLE allocator_mutex = 0;
|
||||
|
||||
static SLJIT_INLINE void allocator_grab_lock(void)
|
||||
{
|
||||
/* No idea what to do if an error occures. Static mutexes should never fail... */
|
||||
if (!allocator_mutex)
|
||||
allocator_mutex = CreateMutex(NULL, TRUE, NULL);
|
||||
else
|
||||
WaitForSingleObject(allocator_mutex, INFINITE);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void allocator_release_lock(void)
|
||||
{
|
||||
ReleaseMutex(allocator_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
static HANDLE global_mutex = 0;
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
|
||||
{
|
||||
/* No idea what to do if an error occures. Static mutexes should never fail... */
|
||||
if (!global_mutex)
|
||||
global_mutex = CreateMutex(NULL, TRUE, NULL);
|
||||
else
|
||||
WaitForSingleObject(global_mutex, INFINITE);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void)
|
||||
{
|
||||
ReleaseMutex(global_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static SLJIT_INLINE void allocator_grab_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&allocator_mutex);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void allocator_release_lock(void)
|
||||
{
|
||||
pthread_mutex_unlock(&allocator_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&global_mutex);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void)
|
||||
{
|
||||
pthread_mutex_unlock(&global_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Stack */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) || (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
/* Provides mmap function. */
|
||||
#include <sys/mman.h>
|
||||
/* For detecting the page size. */
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef MAP_ANON
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Some old systems does not have MAP_ANON. */
|
||||
static sljit_s32 dev_zero = -1;
|
||||
|
||||
#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
|
||||
|
||||
static SLJIT_INLINE sljit_s32 open_dev_zero(void)
|
||||
{
|
||||
dev_zero = open("/dev/zero", O_RDWR);
|
||||
return dev_zero < 0;
|
||||
}
|
||||
|
||||
#else /* SLJIT_SINGLE_THREADED */
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static SLJIT_INLINE sljit_s32 open_dev_zero(void)
|
||||
{
|
||||
pthread_mutex_lock(&dev_zero_mutex);
|
||||
/* The dev_zero might be initialized by another thread during the waiting. */
|
||||
if (dev_zero < 0) {
|
||||
dev_zero = open("/dev/zero", O_RDWR);
|
||||
}
|
||||
pthread_mutex_unlock(&dev_zero_mutex);
|
||||
return dev_zero < 0;
|
||||
}
|
||||
|
||||
#endif /* SLJIT_SINGLE_THREADED */
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SLJIT_UTIL_STACK || SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK)
|
||||
|
||||
/* Planning to make it even more clever in the future. */
|
||||
static sljit_sw sljit_page_align = 0;
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit, void *allocator_data)
|
||||
{
|
||||
struct sljit_stack *stack;
|
||||
void *ptr;
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO si;
|
||||
#endif
|
||||
|
||||
SLJIT_UNUSED_ARG(allocator_data);
|
||||
if (limit > max_limit || limit < 1)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!sljit_page_align) {
|
||||
GetSystemInfo(&si);
|
||||
sljit_page_align = si.dwPageSize - 1;
|
||||
}
|
||||
#else
|
||||
if (!sljit_page_align) {
|
||||
sljit_page_align = sysconf(_SC_PAGESIZE);
|
||||
/* Should never happen. */
|
||||
if (sljit_page_align < 0)
|
||||
sljit_page_align = 4096;
|
||||
sljit_page_align--;
|
||||
}
|
||||
#endif
|
||||
|
||||
stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data);
|
||||
if (!stack)
|
||||
return NULL;
|
||||
|
||||
/* Align max_limit. */
|
||||
max_limit = (max_limit + sljit_page_align) & ~sljit_page_align;
|
||||
|
||||
#ifdef _WIN32
|
||||
ptr = VirtualAlloc(NULL, max_limit, MEM_RESERVE, PAGE_READWRITE);
|
||||
if (!ptr) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
stack->max_limit = (sljit_u8 *)ptr;
|
||||
stack->base = stack->max_limit + max_limit;
|
||||
stack->limit = stack->base;
|
||||
if (sljit_stack_resize(stack, stack->base - limit)) {
|
||||
sljit_free_stack(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#ifdef MAP_ANON
|
||||
ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#else
|
||||
if (dev_zero < 0) {
|
||||
if (open_dev_zero()) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0);
|
||||
#endif
|
||||
if (ptr == MAP_FAILED) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
stack->max_limit = (sljit_u8 *)ptr;
|
||||
stack->base = stack->max_limit + max_limit;
|
||||
stack->limit = stack->base - limit;
|
||||
#endif
|
||||
stack->top = stack->base;
|
||||
return stack;
|
||||
}
|
||||
|
||||
#undef PAGE_ALIGN
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack *stack, void *allocator_data)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(allocator_data);
|
||||
#ifdef _WIN32
|
||||
VirtualFree((void*)stack->max_limit, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap((void*)stack->max_limit, stack->base - stack->max_limit);
|
||||
#endif
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_limit)
|
||||
{
|
||||
sljit_uw aligned_old_limit;
|
||||
sljit_uw aligned_new_limit;
|
||||
|
||||
if ((new_limit < stack->max_limit) || (new_limit >= stack->base))
|
||||
return -1;
|
||||
#ifdef _WIN32
|
||||
aligned_new_limit = (sljit_uw)new_limit & ~sljit_page_align;
|
||||
aligned_old_limit = ((sljit_uw)stack->limit) & ~sljit_page_align;
|
||||
if (aligned_new_limit != aligned_old_limit) {
|
||||
if (aligned_new_limit < aligned_old_limit) {
|
||||
if (!VirtualAlloc((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MEM_COMMIT, PAGE_READWRITE))
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (!VirtualFree((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MEM_DECOMMIT))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
stack->limit = new_limit;
|
||||
return 0;
|
||||
#else
|
||||
if (new_limit <= stack->limit) {
|
||||
stack->limit = new_limit;
|
||||
return 0;
|
||||
}
|
||||
aligned_new_limit = (sljit_uw)new_limit & ~sljit_page_align;
|
||||
aligned_old_limit = ((sljit_uw)stack->limit) & ~sljit_page_align;
|
||||
/* If madvise is available, we release the unnecessary space. */
|
||||
#if defined(MADV_DONTNEED)
|
||||
if (aligned_new_limit > aligned_old_limit)
|
||||
madvise((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MADV_DONTNEED);
|
||||
#elif defined(POSIX_MADV_DONTNEED)
|
||||
if (aligned_new_limit > aligned_old_limit)
|
||||
posix_madvise((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, POSIX_MADV_DONTNEED);
|
||||
#endif
|
||||
stack->limit = new_limit;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_STACK */
|
||||
|
||||
#endif
|
||||
182
Kha/Backends/Kore-hxcpp/khacpp/src/hx/gc/GcCommon.cpp
Normal file
182
Kha/Backends/Kore-hxcpp/khacpp/src/hx/gc/GcCommon.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
#include <hxcpp.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(HXCPP_CAPTURE_x64) && !defined(__GNUC__)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define GC_WIN32_THREADS
|
||||
#include <time.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_TELEMETRY
|
||||
extern void __hxt_new_string(void* result, int size);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
#if defined(HX_MACOS) || defined(HX_WINDOWS) || defined(HX_LINUX) || defined(KINC_CONSOLE)
|
||||
int sgMinimumWorkingMemory = 20*1024*1024;
|
||||
int sgMinimumFreeSpace = 10*1024*1024;
|
||||
#else
|
||||
int sgMinimumWorkingMemory = 8*1024*1024;
|
||||
int sgMinimumFreeSpace = 4*1024*1024;
|
||||
#endif
|
||||
// Once you use more than the minimum, this kicks in...
|
||||
int sgTargetFreeSpacePercentage = 100;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Called internally before and GC operations
|
||||
void CommonInitAlloc()
|
||||
{
|
||||
#if !defined(HX_WINRT) && !defined(__SNC__) && !defined(__ORBIS__) && !defined(KINC_CONSOLE)
|
||||
const char *minimumWorking = getenv("HXCPP_MINIMUM_WORKING_MEMORY");
|
||||
if (minimumWorking)
|
||||
{
|
||||
int mem = atoi(minimumWorking);
|
||||
if (mem>0)
|
||||
sgMinimumWorkingMemory = mem;
|
||||
}
|
||||
|
||||
const char *minimumFreeSpace = getenv("HXCPP_MINIMUM_FREE_SPACE");
|
||||
if (minimumFreeSpace)
|
||||
{
|
||||
int mem = atoi(minimumFreeSpace);
|
||||
if (mem>0)
|
||||
sgMinimumFreeSpace = mem;
|
||||
}
|
||||
|
||||
|
||||
const char *targetFree = getenv("HXCPP_TARGET_FREE_SPACE");
|
||||
if (targetFree)
|
||||
{
|
||||
int percent = atoi(targetFree);
|
||||
if (percent>0)
|
||||
sgTargetFreeSpacePercentage = percent;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
|
||||
|
||||
void *String::operator new( size_t inSize )
|
||||
{
|
||||
return hx::InternalNew(inSize,false);
|
||||
}
|
||||
|
||||
|
||||
void __hxcpp_collect(bool inMajor)
|
||||
{
|
||||
hx::InternalCollect(inMajor,inMajor);
|
||||
}
|
||||
|
||||
|
||||
void __hxcpp_gc_compact()
|
||||
{
|
||||
int mem = hx::InternalCollect(true,true);
|
||||
while(true)
|
||||
{
|
||||
int compact = hx::InternalCollect(true,true);
|
||||
if (compact>=mem-16384)
|
||||
break;
|
||||
mem = compact;
|
||||
}
|
||||
}
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
void GCAddFinalizer(hx::Object *v, finalizer f)
|
||||
{
|
||||
if (v)
|
||||
{
|
||||
throw Dynamic(HX_CSTRING("Add finalizer error"));
|
||||
}
|
||||
}
|
||||
|
||||
HX_CHAR *NewString(int inLen)
|
||||
{
|
||||
char *result = (char *)hx::InternalNew( (inLen+1)*sizeof(char), false );
|
||||
result[inLen] = '\0';
|
||||
#ifdef HXCPP_TELEMETRY
|
||||
__hxt_new_string(result, inLen+1);
|
||||
#endif
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
void *NewGCBytes(void *inData,int inSize)
|
||||
{
|
||||
void *result = hx::InternalNew(inSize,false);
|
||||
if (inData)
|
||||
{
|
||||
memcpy(result,inData,inSize);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void *NewGCPrivate(void *inData,int inSize)
|
||||
{
|
||||
void *result = InternalNew(inSize,false);
|
||||
if (inData)
|
||||
{
|
||||
memcpy(result,inData,inSize);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
|
||||
|
||||
|
||||
void __hxcpp_enable(bool inEnable)
|
||||
{
|
||||
hx::InternalEnableGC(inEnable);
|
||||
}
|
||||
|
||||
void __hxcpp_set_minimum_working_memory(int inBytes)
|
||||
{
|
||||
hx::sgMinimumWorkingMemory = inBytes;
|
||||
}
|
||||
|
||||
void __hxcpp_set_minimum_free_space(int inBytes)
|
||||
{
|
||||
hx::sgMinimumFreeSpace = inBytes;
|
||||
}
|
||||
|
||||
void __hxcpp_set_target_free_space_percentage(int inPercentage)
|
||||
{
|
||||
hx::sgTargetFreeSpacePercentage = inPercentage;
|
||||
}
|
||||
|
||||
bool __hxcpp_is_const_string(const ::String &inString)
|
||||
{
|
||||
#ifdef HXCPP_ALIGN_ALLOC
|
||||
// Unaligned must be native const
|
||||
if ( ((size_t)inString.__s) & 0x3 )
|
||||
return true;
|
||||
#endif
|
||||
return ((unsigned int *)inString.raw_ptr())[-1] & HX_GC_CONST_ALLOC_BIT;
|
||||
}
|
||||
|
||||
160
Kha/Backends/Kore-hxcpp/khacpp/src/hx/gc/GcRegCapture.cpp
Normal file
160
Kha/Backends/Kore-hxcpp/khacpp/src/hx/gc/GcRegCapture.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#include "hxcpp.h"
|
||||
#include "GcRegCapture.h"
|
||||
|
||||
#ifdef HXCPP_CAPTURE_SETJMP // {
|
||||
|
||||
// Nothing
|
||||
|
||||
#elif defined(HXCPP_CAPTURE_x86) // } {
|
||||
|
||||
#pragma optimize( "", off )
|
||||
|
||||
|
||||
namespace hx {
|
||||
|
||||
void CaptureX86(RegisterCaptureBuffer &outBuffer)
|
||||
{
|
||||
void *regEsi;
|
||||
void *regEdi;
|
||||
void *regEbx;
|
||||
#ifdef __GNUC__
|
||||
asm ("mov %%esi, %0\n\t" : "=r" (regEsi) );
|
||||
asm ("mov %%edi, %0\n\t" : "=r" (regEdi) );
|
||||
asm ("mov %%ebx, %0\n\t" : "=r" (regEbx) );
|
||||
#else
|
||||
__asm {
|
||||
mov regEsi, esi
|
||||
mov regEdi, edi
|
||||
mov regEbx, ebx
|
||||
}
|
||||
#endif
|
||||
outBuffer.esi = regEsi;
|
||||
outBuffer.edi = regEdi;
|
||||
outBuffer.ebx = regEbx;
|
||||
}
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
#elif defined(HXCPP_CAPTURE_x64) // } {
|
||||
|
||||
#if !defined(__GNUC__)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace hx {
|
||||
|
||||
void CaptureX64(RegisterCaptureBuffer &outBuffer)
|
||||
{
|
||||
#if !defined(__GNUC__)
|
||||
CONTEXT context;
|
||||
|
||||
context.ContextFlags = CONTEXT_INTEGER;
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
outBuffer.rbx = (void *)context.Rbx;
|
||||
outBuffer.rbp = (void *)context.Rbp;
|
||||
outBuffer.rdi = (void *)context.Rdi;
|
||||
outBuffer.r12 = (void *)context.R12;
|
||||
outBuffer.r13 = (void *)context.R13;
|
||||
outBuffer.r14 = (void *)context.R14;
|
||||
outBuffer.r15 = (void *)context.R15;
|
||||
memcpy(outBuffer.xmm, &context.Xmm0, sizeof(outBuffer.xmm));
|
||||
#else
|
||||
void *regBx;
|
||||
void *regBp;
|
||||
void *regDi;
|
||||
void *reg12;
|
||||
void *reg13;
|
||||
void *reg14;
|
||||
void *reg15;
|
||||
asm ("movq %%rbx, %0\n\t" : "=r" (regBx) );
|
||||
asm ("movq %%rbp, %0\n\t" : "=r" (regBp) );
|
||||
asm ("movq %%rdi, %0\n\t" : "=r" (regDi) );
|
||||
asm ("movq %%r12, %0\n\t" : "=r" (reg12) );
|
||||
asm ("movq %%r13, %0\n\t" : "=r" (reg13) );
|
||||
asm ("movq %%r14, %0\n\t" : "=r" (reg14) );
|
||||
asm ("movq %%r15, %0\n\t" : "=r" (reg15) );
|
||||
outBuffer.rbx = regBx;
|
||||
outBuffer.rbp = regBp;
|
||||
outBuffer.r12 = reg12;
|
||||
outBuffer.r13 = reg13;
|
||||
outBuffer.r14 = reg14;
|
||||
outBuffer.r15 = reg15;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
|
||||
#elif defined(HXCPP_CAPTURE_ARM64) // } {
|
||||
|
||||
namespace hx {
|
||||
|
||||
void CaptureArm64(RegisterCaptureBuffer &outBuffer)
|
||||
{
|
||||
void *regX19;
|
||||
void *regX20;
|
||||
void *regX21;
|
||||
void *regX22;
|
||||
void *regX23;
|
||||
void *regX24;
|
||||
void *regX25;
|
||||
void *regX26;
|
||||
void *regX27;
|
||||
void *regX28;
|
||||
asm ("mov %0, x19\n\t" : "=r" (regX19) );
|
||||
asm ("mov %0, x20\n\t" : "=r" (regX20) );
|
||||
asm ("mov %0, x21\n\t" : "=r" (regX21) );
|
||||
asm ("mov %0, x22\n\t" : "=r" (regX22) );
|
||||
asm ("mov %0, x23\n\t" : "=r" (regX23) );
|
||||
asm ("mov %0, x24\n\t" : "=r" (regX24) );
|
||||
asm ("mov %0, x25\n\t" : "=r" (regX25) );
|
||||
asm ("mov %0, x26\n\t" : "=r" (regX26) );
|
||||
asm ("mov %0, x27\n\t" : "=r" (regX27) );
|
||||
asm ("mov %0, x28\n\t" : "=r" (regX28) );
|
||||
outBuffer.x19 = regX19;
|
||||
outBuffer.x20 = regX20;
|
||||
outBuffer.x21 = regX21;
|
||||
outBuffer.x22 = regX22;
|
||||
outBuffer.x23 = regX23;
|
||||
outBuffer.x24 = regX24;
|
||||
outBuffer.x25 = regX25;
|
||||
outBuffer.x26 = regX26;
|
||||
outBuffer.x27 = regX27;
|
||||
outBuffer.x28 = regX28;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
#else // } {
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace hx {
|
||||
|
||||
// Put this function here so we can be reasonablly sure that "this" register and
|
||||
// the 4 registers that may be used to pass args are on the stack.
|
||||
int RegisterCapture::Capture(int *inTopOfStack,int **inBuf,int &outSize,int inMaxSize, int *inBottom)
|
||||
{
|
||||
int size = ( (char *)inTopOfStack - (char *)inBottom )/sizeof(void *);
|
||||
if (size>inMaxSize)
|
||||
size = inMaxSize;
|
||||
outSize = size;
|
||||
if (size>0)
|
||||
memcpy(inBuf,inBottom,size*sizeof(void*));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
RegisterCapture *gRegisterCaptureInstance = 0;
|
||||
RegisterCapture *RegisterCapture::Instance()
|
||||
{
|
||||
if (!gRegisterCaptureInstance)
|
||||
gRegisterCaptureInstance = new RegisterCapture();
|
||||
return gRegisterCaptureInstance;
|
||||
}
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
#endif // }
|
||||
|
||||
140
Kha/Backends/Kore-hxcpp/khacpp/src/hx/gc/GcRegCapture.h
Normal file
140
Kha/Backends/Kore-hxcpp/khacpp/src/hx/gc/GcRegCapture.h
Normal file
@ -0,0 +1,140 @@
|
||||
#ifndef HX_GC_HELPERS_INCLUDED
|
||||
#define HX_GC_HELPERS_INCLUDED
|
||||
|
||||
#if defined(HX_WINDOWS) && defined(HXCPP_ARM64)
|
||||
// Eg, Microsoft Surface
|
||||
#define HXCPP_CAPTURE_SETJMP
|
||||
#endif
|
||||
|
||||
#ifdef HXCPP_CAPTURE_SETJMP
|
||||
#include <setjmp.h>
|
||||
#else
|
||||
|
||||
#if (defined(HX_WINDOWS) || (defined(HX_LINUX) && defined(__i386__))) && !defined(HXCPP_M64)
|
||||
#define HXCPP_CAPTURE_x86
|
||||
#endif
|
||||
|
||||
#if ((defined(HX_MACOS) && defined(__x86_64)) || (defined(HX_WINDOWS) && !defined(HX_WINRT)) || defined(_XBOX_ONE) || (defined(HX_LINUX) && defined(__x86_64__)) || defined(KINC_PS4) || defined(KINC_PS5) || defined(KINC_XBOX_ONE) || defined(KINC_XBOX_SERIES)) && defined(HXCPP_M64)
|
||||
#define HXCPP_CAPTURE_x64
|
||||
#endif
|
||||
|
||||
#if defined(HXCPP_ARM64)
|
||||
//#define HXCPP_CAPTURE_ARM64
|
||||
// Awlays use setjmp on arm64
|
||||
#include <setjmp.h>
|
||||
#define HXCPP_CAPTURE_SETJMP
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
// Capture Registers
|
||||
//
|
||||
#ifdef HXCPP_CAPTURE_SETJMP // {
|
||||
|
||||
typedef jmp_buf RegisterCaptureBuffer;
|
||||
|
||||
#define CAPTURE_REGS \
|
||||
setjmp(mRegisterBuf);
|
||||
|
||||
#define CAPTURE_REG_START (int *)(&mRegisterBuf)
|
||||
#define CAPTURE_REG_END (int *)(&mRegisterBuf+1)
|
||||
|
||||
#elif defined(HXCPP_CAPTURE_x86) // } {
|
||||
|
||||
struct RegisterCaptureBuffer
|
||||
{
|
||||
void *ebx;
|
||||
void *edi;
|
||||
void *esi;
|
||||
};
|
||||
|
||||
void CaptureX86(RegisterCaptureBuffer &outBuffer);
|
||||
|
||||
#define CAPTURE_REGS \
|
||||
hx::CaptureX86(mRegisterBuf);
|
||||
|
||||
#define CAPTURE_REG_START (int *)(&mRegisterBuf)
|
||||
#define CAPTURE_REG_END (int *)(&mRegisterBuf+1)
|
||||
|
||||
#elif defined(HXCPP_CAPTURE_x64) // } {
|
||||
|
||||
|
||||
struct RegisterCaptureBuffer
|
||||
{
|
||||
void *rbx;
|
||||
void *rbp;
|
||||
void *rdi;
|
||||
void *r12;
|
||||
void *r13;
|
||||
void *r14;
|
||||
void *r15;
|
||||
|
||||
void *xmm[16*2];
|
||||
};
|
||||
|
||||
void CaptureX64(RegisterCaptureBuffer &outBuffer);
|
||||
|
||||
#define CAPTURE_REGS \
|
||||
hx::CaptureX64(mRegisterBuf);
|
||||
|
||||
#define CAPTURE_REG_START (int *)(&mRegisterBuf)
|
||||
#define CAPTURE_REG_END (int *)(&mRegisterBuf+1)
|
||||
|
||||
|
||||
#elif defined(HXCPP_CAPTURE_ARM64) // } {
|
||||
|
||||
|
||||
struct RegisterCaptureBuffer
|
||||
{
|
||||
void *x19;
|
||||
void *x20;
|
||||
void *x21;
|
||||
void *x22;
|
||||
void *x23;
|
||||
void *x24;
|
||||
void *x25;
|
||||
void *x26;
|
||||
void *x27;
|
||||
void *x28;
|
||||
};
|
||||
|
||||
void CaptureArm64(RegisterCaptureBuffer &outBuffer);
|
||||
|
||||
#define CAPTURE_REGS \
|
||||
hx::CaptureArm64(mRegisterBuf);
|
||||
|
||||
#define CAPTURE_REG_START (int *)(&mRegisterBuf)
|
||||
#define CAPTURE_REG_END (int *)(&mRegisterBuf+1)
|
||||
|
||||
|
||||
#else // } default capture... {
|
||||
|
||||
|
||||
class RegisterCapture
|
||||
{
|
||||
public:
|
||||
virtual int Capture(int *inTopOfStack,int **inBuf,int &outSize,int inMaxSize,int *inDummy);
|
||||
static RegisterCapture *Instance();
|
||||
};
|
||||
|
||||
typedef int *RegisterCaptureBuffer[20];
|
||||
|
||||
#define CAPTURE_REGS \
|
||||
hx::RegisterCapture::Instance()->Capture(mTopOfStack, \
|
||||
mRegisterBuf,mRegisterBufSize,20,mBottomOfStack); \
|
||||
|
||||
#define CAPTURE_REG_START (int *)mRegisterBuf
|
||||
#define CAPTURE_REG_END (int *)(mRegisterBuf+mRegisterBufSize)
|
||||
|
||||
#endif // }
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
7042
Kha/Backends/Kore-hxcpp/khacpp/src/hx/gc/Immix.cpp
Normal file
7042
Kha/Backends/Kore-hxcpp/khacpp/src/hx/gc/Immix.cpp
Normal file
File diff suppressed because it is too large
Load Diff
24
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/Build.xml
Normal file
24
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/Build.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<xml>
|
||||
|
||||
<files id="hxcpp_mysql" dir="${this_dir}" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<depend name="${this_dir}/sha1.h" />
|
||||
<depend name="${this_dir}/socket.h" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<file name="Mysql.cpp"/>
|
||||
<file name="my_api.cpp"/>
|
||||
<file name="my_proto.cpp"/>
|
||||
<file name="socket.cpp"/>
|
||||
<file name="sha1.cpp"/>
|
||||
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_mysql"/>
|
||||
<lib name="ws2_32.lib" if="windows" unless="static_link" />
|
||||
</target>
|
||||
|
||||
|
||||
</xml>
|
||||
555
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/Mysql.cpp
Normal file
555
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/Mysql.cpp
Normal file
@ -0,0 +1,555 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <hxcpp.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "mysql.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HX_ANDROID
|
||||
#define atof(x) strtod((x),0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>MySQL</h1>
|
||||
<p>
|
||||
API to connect and use MySQL database
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
|
||||
#define HXTHROW(x) hx::Throw(HX_CSTRING(x))
|
||||
|
||||
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Connection : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdMysql };
|
||||
|
||||
|
||||
MYSQL *m;
|
||||
|
||||
|
||||
void create(MYSQL *inM)
|
||||
{
|
||||
m = inM;
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (m)
|
||||
{
|
||||
mysql_close(m);
|
||||
m = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((Connection *)(obj.mPtr))->destroy();
|
||||
}
|
||||
};
|
||||
|
||||
Connection *getConnection(Dynamic o)
|
||||
{
|
||||
Connection *connection = dynamic_cast<Connection *>(o.mPtr);
|
||||
if (!connection || !connection->m)
|
||||
hx::Throw( HX_CSTRING("Invalid Connection") );
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
static void error( MYSQL *m, const char *msg )
|
||||
{
|
||||
hx::Throw( String(msg) + HX_CSTRING(" ") + String(mysql_error(m)) );
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Result
|
||||
|
||||
/**
|
||||
<doc><h2>Result</h2></doc>
|
||||
**/
|
||||
|
||||
#undef CONV_FLOAT
|
||||
typedef enum {
|
||||
CONV_INT,
|
||||
CONV_STRING,
|
||||
CONV_FLOAT,
|
||||
CONV_BINARY,
|
||||
CONV_DATE,
|
||||
CONV_DATETIME,
|
||||
CONV_BOOL
|
||||
} CONV;
|
||||
|
||||
struct Result : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdMysqlResult };
|
||||
|
||||
MYSQL_RES *r;
|
||||
int nfields;
|
||||
CONV *fields_convs;
|
||||
String *field_names;
|
||||
MYSQL_ROW current;
|
||||
|
||||
void create(MYSQL_RES *inR)
|
||||
{
|
||||
r = inR;
|
||||
fields_convs = 0;
|
||||
field_names = 0;
|
||||
nfields = 0;
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (r)
|
||||
{
|
||||
if (fields_convs)
|
||||
free(fields_convs);
|
||||
if (field_names)
|
||||
free(field_names);
|
||||
fields_convs = 0;
|
||||
field_names = 0;
|
||||
mysql_free_result(r);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int numRows() { return mysql_num_rows(r); }
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((Result *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Result *getResult(Dynamic o)
|
||||
{
|
||||
Result *result = dynamic_cast<Result *>(o.mPtr);
|
||||
if (!result)
|
||||
HXTHROW("Invalid result");
|
||||
return result;
|
||||
}
|
||||
|
||||
cpp::Function< Dynamic(Dynamic) > gDataToBytes;
|
||||
cpp::Function< Dynamic(Float) > gDateFromSeconds;
|
||||
|
||||
}
|
||||
|
||||
void _hx_mysql_set_conversion(
|
||||
cpp::Function< Dynamic(Dynamic) > inDataToBytes,
|
||||
cpp::Function< Dynamic(Float) > inDateFromSeconds )
|
||||
{
|
||||
gDataToBytes = inDataToBytes;
|
||||
gDateFromSeconds = inDateFromSeconds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
result_get_length : 'result -> int
|
||||
<doc>Return the number of rows returned or affected</doc>
|
||||
**/
|
||||
int _hx_mysql_result_get_length(Dynamic handle)
|
||||
{
|
||||
if( handle->__GetType() == vtInt )
|
||||
return handle;
|
||||
|
||||
return getResult(handle)->numRows();
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_nfields : 'result -> int
|
||||
<doc>Return the number of fields in a result row</doc>
|
||||
**/
|
||||
int _hx_mysql_result_get_nfields(Dynamic handle)
|
||||
{
|
||||
if( handle->__GetType() == vtInt )
|
||||
return 0;
|
||||
|
||||
return getResult(handle)->nfields;
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_fields_names : 'result -> string array
|
||||
<doc>Return the fields names corresponding results columns</doc>
|
||||
**/
|
||||
Array<String> _hx_mysql_result_get_fields_names(Dynamic handle)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
|
||||
MYSQL_FIELD *fields = mysql_fetch_fields(r->r);
|
||||
int count = r->nfields;
|
||||
Array<String> output = Array_obj<String>::__new(count);
|
||||
|
||||
for(int k=0;k<count;k++)
|
||||
output[k] = String(fields[k].name);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
result_next : 'result -> object?
|
||||
<doc>
|
||||
Return the next row if available. A row is represented
|
||||
as an object, which fields have been converted to the
|
||||
corresponding Neko value (int, float or string). For
|
||||
Date and DateTime you can specify your own conversion
|
||||
function using [result_set_conv_date]. By default they're
|
||||
returned as plain strings. Additionally, the TINYINT(1) will
|
||||
be converted to either true or false if equal to 0.
|
||||
</doc>
|
||||
**/
|
||||
Dynamic _hx_mysql_result_next(Dynamic handle)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
MYSQL_ROW row = mysql_fetch_row(r->r);
|
||||
if( !row )
|
||||
return null();
|
||||
|
||||
int count = r->nfields;
|
||||
hx::Anon cur = hx::Anon_obj::Create(0);
|
||||
|
||||
r->current = row;
|
||||
unsigned long *lengths = 0;
|
||||
for(int i=0;i<r->nfields;i++)
|
||||
{
|
||||
if( row[i] )
|
||||
{
|
||||
Dynamic v;
|
||||
switch( r->fields_convs[i] )
|
||||
{
|
||||
case CONV_INT:
|
||||
v = atoi(row[i]);
|
||||
break;
|
||||
case CONV_STRING:
|
||||
v = String(row[i]);
|
||||
break;
|
||||
case CONV_BOOL:
|
||||
v = *row[i] != '0';
|
||||
break;
|
||||
case CONV_FLOAT:
|
||||
v = atof(row[i]);
|
||||
break;
|
||||
case CONV_BINARY:
|
||||
{
|
||||
if( lengths == NULL )
|
||||
{
|
||||
lengths = mysql_fetch_lengths(r->r);
|
||||
if( lengths == NULL )
|
||||
HXTHROW("mysql_fetch_lengths");
|
||||
}
|
||||
Array<unsigned char> buf = Array_obj<unsigned char>::__new(lengths[i],lengths[i]);
|
||||
memcpy(&buf[0],row[i],lengths[i]);
|
||||
v = gDataToBytes.call(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case CONV_DATE:
|
||||
{
|
||||
struct tm t;
|
||||
sscanf(row[i],"%4d-%2d-%2d",&t.tm_year,&t.tm_mon,&t.tm_mday);
|
||||
t.tm_hour = 0;
|
||||
t.tm_min = 0;
|
||||
t.tm_sec = 0;
|
||||
t.tm_isdst = -1;
|
||||
t.tm_year -= 1900;
|
||||
t.tm_mon--;
|
||||
v = gDateFromSeconds.call((int)mktime(&t));
|
||||
}
|
||||
break;
|
||||
case CONV_DATETIME:
|
||||
{
|
||||
struct tm t;
|
||||
sscanf(row[i],"%4d-%2d-%2d %2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
|
||||
t.tm_isdst = -1;
|
||||
t.tm_year -= 1900;
|
||||
t.tm_mon--;
|
||||
v = gDateFromSeconds.call(mktime(&t));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cur->__SetField(r->field_names[i],v, hx::paccDynamic );
|
||||
}
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
result_get : 'result -> n:int -> string
|
||||
<doc>Return the [n]th field of the current row</doc>
|
||||
**/
|
||||
String _hx_mysql_result_get(Dynamic handle,int n)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
if( n < 0 || n >= r->nfields )
|
||||
HXTHROW("Invalid index");
|
||||
|
||||
if( !r->current )
|
||||
{
|
||||
_hx_mysql_result_next(handle);
|
||||
if( !r->current )
|
||||
HXTHROW("No more results");
|
||||
}
|
||||
|
||||
return String(r->current[n]);
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_int : 'result -> n:int -> int
|
||||
<doc>Return the [n]th field of the current row as an integer (or 0)</doc>
|
||||
**/
|
||||
int _hx_mysql_result_get_int(Dynamic handle,int n)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
if( n < 0 || n >= r->nfields )
|
||||
HXTHROW("Invalid index");
|
||||
|
||||
if( !r->current )
|
||||
{
|
||||
_hx_mysql_result_next(handle);
|
||||
if( !r->current )
|
||||
HXTHROW("No more results");
|
||||
}
|
||||
|
||||
const char *s = r->current[n];
|
||||
return s?atoi(s):0;
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_float : 'result -> n:int -> float
|
||||
<doc>Return the [n]th field of the current row as a float (or 0)</doc>
|
||||
**/
|
||||
Float _hx_mysql_result_get_float(Dynamic handle,int n)
|
||||
{
|
||||
Result *r = getResult(handle);
|
||||
if( n < 0 || n >= r->nfields )
|
||||
HXTHROW("Invalid index");
|
||||
|
||||
if( !r->current )
|
||||
{
|
||||
_hx_mysql_result_next(handle);
|
||||
if( !r->current )
|
||||
HXTHROW("No more results");
|
||||
}
|
||||
|
||||
const char *s = r->current[n];
|
||||
return s?atof(s):0;
|
||||
}
|
||||
|
||||
static CONV convert_type( enum enum_field_types t, int flags, unsigned int length ) {
|
||||
// FIELD_TYPE_TIME
|
||||
// FIELD_TYPE_YEAR
|
||||
// FIELD_TYPE_NEWDATE
|
||||
// FIELD_TYPE_NEWDATE + 2: // 5.0 MYSQL_TYPE_BIT
|
||||
switch( t ) {
|
||||
case FIELD_TYPE_TINY:
|
||||
if( length == 1 )
|
||||
return CONV_BOOL;
|
||||
case FIELD_TYPE_SHORT:
|
||||
case FIELD_TYPE_LONG:
|
||||
case FIELD_TYPE_INT24:
|
||||
return CONV_INT;
|
||||
case FIELD_TYPE_LONGLONG:
|
||||
case FIELD_TYPE_DECIMAL:
|
||||
case FIELD_TYPE_FLOAT:
|
||||
case FIELD_TYPE_DOUBLE:
|
||||
case 246: // 5.0 MYSQL_NEW_DECIMAL
|
||||
return CONV_FLOAT;
|
||||
case FIELD_TYPE_BLOB:
|
||||
case FIELD_TYPE_TINY_BLOB:
|
||||
case FIELD_TYPE_MEDIUM_BLOB:
|
||||
case FIELD_TYPE_LONG_BLOB:
|
||||
if( (flags & BINARY_FLAG) != 0 )
|
||||
return CONV_BINARY;
|
||||
return CONV_STRING;
|
||||
case FIELD_TYPE_DATETIME:
|
||||
case FIELD_TYPE_TIMESTAMP:
|
||||
return CONV_DATETIME;
|
||||
case FIELD_TYPE_DATE:
|
||||
return CONV_DATE;
|
||||
case FIELD_TYPE_NULL:
|
||||
case FIELD_TYPE_ENUM:
|
||||
case FIELD_TYPE_SET:
|
||||
//case FIELD_TYPE_VAR_STRING:
|
||||
//case FIELD_TYPE_GEOMETRY:
|
||||
// 5.0 MYSQL_TYPE_VARCHAR
|
||||
default:
|
||||
if( (flags & BINARY_FLAG) != 0 )
|
||||
return CONV_BINARY;
|
||||
return CONV_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Result *alloc_result( Connection *c, MYSQL_RES *r )
|
||||
{
|
||||
Result *res = new Result();
|
||||
res->create(r);
|
||||
|
||||
int num_fields = mysql_num_fields(r);
|
||||
int i,j;
|
||||
MYSQL_FIELD *fields = mysql_fetch_fields(r);
|
||||
res->current = 0;
|
||||
res->nfields = num_fields;
|
||||
res->field_names = (String *)malloc(sizeof(String)*num_fields);
|
||||
res->fields_convs = (CONV*)malloc(sizeof(CONV)*num_fields);
|
||||
|
||||
for(i=0;i<num_fields;i++)
|
||||
{
|
||||
String name;
|
||||
if( strchr(fields[i].name,'(') )
|
||||
name = String::createPermanent("???",3); // looks like an inner request : prevent hashing + cashing it
|
||||
else
|
||||
name = String::createPermanent(fields[i].name, -1);
|
||||
|
||||
res->field_names[i] = name;
|
||||
res->fields_convs[i] = convert_type(fields[i].type,fields[i].flags,fields[i].length);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Connection
|
||||
|
||||
/** <doc><h2>Connection</h2></doc> **/
|
||||
|
||||
/**
|
||||
close : 'connection -> void
|
||||
<doc>Close the connection. Any subsequent operation will fail on it</doc>
|
||||
**/
|
||||
Dynamic _hx_mysql_close(Dynamic handle)
|
||||
{
|
||||
Connection *connection = getConnection(handle);
|
||||
connection->destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
select_db : 'connection -> string -> void
|
||||
<doc>Select the database</doc>
|
||||
**/
|
||||
void _hx_mysql_select_db(Dynamic handle,String db)
|
||||
{
|
||||
Connection *connection = getConnection(handle);
|
||||
|
||||
if( mysql_select_db(connection->m,db.utf8_str()) != 0 )
|
||||
error(connection->m,"Failed to select database :");
|
||||
}
|
||||
|
||||
/**
|
||||
request : 'connection -> string -> 'result
|
||||
<doc>Execute an SQL request. Exception on error</doc>
|
||||
**/
|
||||
Dynamic _hx_mysql_request(Dynamic handle,String req)
|
||||
{
|
||||
Connection *connection = getConnection(handle);
|
||||
|
||||
if( mysql_real_query(connection->m,req.utf8_str(),req.length) != 0 )
|
||||
error(connection->m,req);
|
||||
|
||||
MYSQL_RES *res = mysql_store_result(connection->m);
|
||||
if( !res )
|
||||
{
|
||||
if( mysql_field_count(connection->m) == 0 )
|
||||
return mysql_affected_rows(connection->m);
|
||||
else
|
||||
error(connection->m,req);
|
||||
}
|
||||
|
||||
return alloc_result(connection,res);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
escape : 'connection -> string -> string
|
||||
<doc>Escape the string for inserting into a SQL request</doc>
|
||||
**/
|
||||
struct AutoBuf
|
||||
{
|
||||
AutoBuf(int inLen) { buffer = new char[inLen]; }
|
||||
~AutoBuf() { delete [] buffer; }
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
|
||||
String _hx_mysql_escape(Dynamic handle,String str)
|
||||
{
|
||||
Connection *connection = getConnection(handle);
|
||||
int len = str.length * 2 + 1;
|
||||
AutoBuf sout(len);
|
||||
|
||||
int finalLen = mysql_real_escape_string(connection->m,sout.buffer,str.utf8_str(),str.length);
|
||||
if( finalLen < 0 )
|
||||
hx::Throw( HX_CSTRING("Unsupported charset : ") + String(mysql_character_set_name(connection->m)) );
|
||||
|
||||
return String::create(sout.buffer,finalLen);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Sql
|
||||
|
||||
|
||||
/**
|
||||
connect : { host => string, port => int, user => string, pass => string, socket => string? } -> 'connection
|
||||
<doc>Connect to a database using the connection informations</doc>
|
||||
**/
|
||||
Dynamic _hx_mysql_connect(Dynamic params)
|
||||
{
|
||||
String host = params->__Field(HX_CSTRING("host"), hx::paccDynamic );
|
||||
int port = params->__Field(HX_CSTRING("port"), hx::paccDynamic);
|
||||
String user = params->__Field(HX_CSTRING("user"), hx::paccDynamic);
|
||||
String pass = params->__Field(HX_CSTRING("pass"), hx::paccDynamic);
|
||||
String socket = params->__Field(HX_CSTRING("socket"), hx::paccDynamic );
|
||||
|
||||
MYSQL *cnx = mysql_init(NULL);
|
||||
if( mysql_real_connect(cnx,host.utf8_str(),user.utf8_str(),pass.utf8_str(),NULL,port,socket.utf8_str(),0) == NULL )
|
||||
{
|
||||
String error = HX_CSTRING("Failed to connect to mysql server : ") + String(mysql_error(cnx));
|
||||
mysql_close(cnx);
|
||||
hx::Throw(error);
|
||||
}
|
||||
|
||||
Connection *connection = new Connection();
|
||||
connection->create(cnx);
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
511
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/my_api.cpp
Normal file
511
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/my_api.cpp
Normal file
@ -0,0 +1,511 @@
|
||||
/* ************************************************************************ */
|
||||
/* */
|
||||
/* MYSQL 5.0 Protocol Implementation */
|
||||
/* Copyright (c)2008 Nicolas Cannasse */
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "my_proto.h"
|
||||
|
||||
static void error( MYSQL *m, const char *err, const char *param ) {
|
||||
if( param ) {
|
||||
unsigned int max = MAX_ERR_SIZE - (strlen(err) + 3);
|
||||
if( strlen(param) > max ) {
|
||||
char *p2 = (char*)malloc(max + 1);
|
||||
memcpy(p2,param,max-3);
|
||||
p2[max - 3] = '.';
|
||||
p2[max - 2] = '.';
|
||||
p2[max - 1] = '.';
|
||||
p2[max] = 0;
|
||||
sprintf(m->last_error,err,param);
|
||||
free(p2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
sprintf(m->last_error,err,param);
|
||||
m->errcode = -1;
|
||||
}
|
||||
|
||||
static void save_error( MYSQL *m, MYSQL_PACKET *p ) {
|
||||
int ecode;
|
||||
p->pos = 0;
|
||||
// seems like we sometimes get some FFFFFF sequences before
|
||||
// the actual error...
|
||||
do {
|
||||
if( myp_read_byte(p) != 0xFF ) {
|
||||
m->errcode = -1;
|
||||
error(m,"Failed to decode error",NULL);
|
||||
return;
|
||||
}
|
||||
ecode = myp_read_ui16(p);
|
||||
} while( ecode == 0xFFFF );
|
||||
if( m->is41 && p->buf[p->pos] == '#' )
|
||||
p->pos += 6; // skip sqlstate marker
|
||||
error(m,"%s",myp_read_string(p));
|
||||
m->errcode = ecode;
|
||||
}
|
||||
|
||||
static int myp_ok( MYSQL *m, int allow_others ) {
|
||||
int code;
|
||||
MYSQL_PACKET *p = &m->packet;
|
||||
if( !myp_read_packet(m,p) ) {
|
||||
error(m,"Failed to read packet",NULL);
|
||||
return 0;
|
||||
}
|
||||
code = myp_read_byte(p);
|
||||
if( code == 0x00 )
|
||||
return 1;
|
||||
if( code == 0xFF )
|
||||
save_error(m,p);
|
||||
else if( allow_others )
|
||||
return 1;
|
||||
else
|
||||
error(m,"Invalid packet error",NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void myp_close( MYSQL *m ) {
|
||||
psock_close(m->s);
|
||||
m->s = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
MYSQL *mysql_init( void *unused ) {
|
||||
MYSQL *m = (MYSQL*)malloc(sizeof(struct _MYSQL));
|
||||
psock_init();
|
||||
memset(m,0,sizeof(struct _MYSQL));
|
||||
m->s = INVALID_SOCKET;
|
||||
error(m,"NO ERROR",NULL);
|
||||
m->errcode = 0;
|
||||
m->last_field_count = -1;
|
||||
m->last_insert_id = -1;
|
||||
m->affected_rows = -1;
|
||||
return m;
|
||||
}
|
||||
|
||||
MYSQL *mysql_real_connect( MYSQL *m, const char *host, const char *user, const char *pass, void *unused, int port, const char *socket, int options ) {
|
||||
PHOST h;
|
||||
char scramble_buf[21];
|
||||
MYSQL_PACKET *p = &m->packet;
|
||||
int pcount = 1;
|
||||
if( socket && *socket ) {
|
||||
error(m,"Unix Socket connections are not supported",NULL);
|
||||
return NULL;
|
||||
}
|
||||
h = phost_resolve(host);
|
||||
if( h == UNRESOLVED_HOST ) {
|
||||
error(m,"Failed to resolve host '%s'",host);
|
||||
return NULL;
|
||||
}
|
||||
m->s = psock_create();
|
||||
if( m->s == INVALID_SOCKET ) {
|
||||
error(m,"Failed to create socket",NULL);
|
||||
return NULL;
|
||||
}
|
||||
psock_set_fastsend(m->s,1);
|
||||
psock_set_timeout(m->s,50); // 50 seconds
|
||||
if( psock_connect(m->s,h,port) != PS_OK ) {
|
||||
myp_close(m);
|
||||
error(m,"Failed to connect on host '%s'",host);
|
||||
return NULL;
|
||||
}
|
||||
if( !myp_read_packet(m,p) ) {
|
||||
myp_close(m);
|
||||
error(m,"Failed to read handshake packet",NULL);
|
||||
return NULL;
|
||||
}
|
||||
// process handshake packet
|
||||
{
|
||||
char filler[13];
|
||||
unsigned int len;
|
||||
m->infos.proto_version = myp_read_byte(p);
|
||||
// this seems like an error packet
|
||||
if( m->infos.proto_version == 0xFF ) {
|
||||
myp_close(m);
|
||||
save_error(m,p);
|
||||
return NULL;
|
||||
}
|
||||
m->infos.server_version = strdup(myp_read_string(p));
|
||||
m->infos.thread_id = myp_read_int(p);
|
||||
myp_read(p,scramble_buf,8);
|
||||
myp_read_byte(p); // should be 0
|
||||
m->infos.server_flags = myp_read_ui16(p);
|
||||
m->infos.server_charset = myp_read_byte(p);
|
||||
m->infos.server_status = myp_read_ui16(p);
|
||||
m->infos.server_flags |= myp_read_ui16(p) << 16;
|
||||
len = myp_read_byte(p);
|
||||
myp_read(p,filler,10);
|
||||
// try to disable 41
|
||||
m->is41 = (m->infos.server_flags & FL_PROTOCOL_41) != 0;
|
||||
if( !p->error && m->is41 )
|
||||
myp_read(p,scramble_buf + 8,13);
|
||||
if( p->pos != p->size )
|
||||
myp_read_string(p); // 5.5+
|
||||
if( p->error ) {
|
||||
myp_close(m);
|
||||
error(m,"Failed to decode server handshake",NULL);
|
||||
return NULL;
|
||||
}
|
||||
// fill answer packet
|
||||
{
|
||||
unsigned int flags = m->infos.server_flags;
|
||||
int max_packet_size = 0x01000000;
|
||||
SHA1_DIGEST hpass;
|
||||
char filler[23];
|
||||
flags &= (FL_PROTOCOL_41 | FL_TRANSACTIONS | FL_SECURE_CONNECTION);
|
||||
myp_begin_packet(p,128);
|
||||
if( m->is41 ) {
|
||||
myp_write_int(p,flags);
|
||||
myp_write_int(p,max_packet_size);
|
||||
myp_write_byte(p,m->infos.server_charset);
|
||||
memset(filler,0,23);
|
||||
myp_write(p,filler,23);
|
||||
myp_write_string(p,user);
|
||||
if( *pass ) {
|
||||
myp_encrypt_password(pass,scramble_buf,hpass);
|
||||
myp_write_bin(p,SHA1_SIZE);
|
||||
myp_write(p,hpass,SHA1_SIZE);
|
||||
myp_write_byte(p,0);
|
||||
} else
|
||||
myp_write_bin(p,0);
|
||||
} else {
|
||||
myp_write_ui16(p,flags);
|
||||
// max_packet_size
|
||||
myp_write_byte(p,0xFF);
|
||||
myp_write_byte(p,0xFF);
|
||||
myp_write_byte(p,0xFF);
|
||||
myp_write_string(p,user);
|
||||
if( *pass ) {
|
||||
char hpass[SEED_LENGTH_323 + 1];
|
||||
myp_encrypt_pass_323(pass,scramble_buf,hpass);
|
||||
hpass[SEED_LENGTH_323] = 0;
|
||||
myp_write(p,hpass,SEED_LENGTH_323 + 1);
|
||||
} else
|
||||
myp_write_bin(p,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
// send connection packet
|
||||
send_cnx_packet:
|
||||
if( !myp_send_packet(m,p,&pcount) ) {
|
||||
myp_close(m);
|
||||
error(m,"Failed to send connection packet",NULL);
|
||||
return NULL;
|
||||
}
|
||||
// read answer packet
|
||||
if( !myp_read_packet(m,p) ) {
|
||||
myp_close(m);
|
||||
error(m,"Failed to read packet",NULL);
|
||||
return NULL;
|
||||
}
|
||||
// increase packet counter (because we read one packet)
|
||||
pcount++;
|
||||
// process answer
|
||||
{
|
||||
int code = myp_read_byte(p);
|
||||
switch( code ) {
|
||||
case 0: // OK packet
|
||||
break;
|
||||
case 0xFF: // ERROR
|
||||
myp_close(m);
|
||||
save_error(m,p);
|
||||
return NULL;
|
||||
case 0xFE: // EOF
|
||||
// we are asked to send old password authentification
|
||||
if( p->size == 1 ) {
|
||||
char hpass[SEED_LENGTH_323 + 1];
|
||||
myp_encrypt_pass_323(pass,scramble_buf,hpass);
|
||||
hpass[SEED_LENGTH_323] = 0;
|
||||
myp_begin_packet(p,0);
|
||||
myp_write(p,hpass,SEED_LENGTH_323 + 1);
|
||||
goto send_cnx_packet;
|
||||
}
|
||||
// fallthrough
|
||||
default:
|
||||
myp_close(m);
|
||||
error(m,"Invalid packet error",NULL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// we are connected, setup a longer timeout
|
||||
psock_set_timeout(m->s,18000);
|
||||
return m;
|
||||
}
|
||||
|
||||
int mysql_select_db( MYSQL *m, const char *dbname ) {
|
||||
MYSQL_PACKET *p = &m->packet;
|
||||
int pcount = 0;
|
||||
myp_begin_packet(p,0);
|
||||
myp_write_byte(p,COM_INIT_DB);
|
||||
// send dbname without trailing 0x00
|
||||
myp_write(p,dbname,strlen(dbname));
|
||||
if( !myp_send_packet(m,p,&pcount) ) {
|
||||
error(m,"Failed to send packet",NULL);
|
||||
return -1;
|
||||
}
|
||||
return myp_ok(m,0) ? 0 : -1;
|
||||
}
|
||||
|
||||
int mysql_real_query( MYSQL *m, const char *query, int qlength ) {
|
||||
MYSQL_PACKET *p = &m->packet;
|
||||
int pcount = 0;
|
||||
myp_begin_packet(p,0);
|
||||
myp_write_byte(p,COM_QUERY);
|
||||
myp_write(p,query,qlength);
|
||||
m->last_field_count = -1;
|
||||
m->affected_rows = -1;
|
||||
m->last_insert_id = -1;
|
||||
if( !myp_send_packet(m,p,&pcount) ) {
|
||||
error(m,"Failed to send packet",NULL);
|
||||
return -1;
|
||||
}
|
||||
if( !myp_ok(m,1) )
|
||||
return -1;
|
||||
p->id = IS_QUERY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_store( MYSQL *m, MYSQL_RES *r ) {
|
||||
int i;
|
||||
MYSQL_PACKET *p = &m->packet;
|
||||
p->pos = 0;
|
||||
r->nfields = myp_read_bin(p);
|
||||
if( p->error ) return 0;
|
||||
r->fields = (MYSQL_FIELD*)malloc(sizeof(MYSQL_FIELD) * r->nfields);
|
||||
memset(r->fields,0,sizeof(MYSQL_FIELD) * r->nfields);
|
||||
for(i=0;i<r->nfields;i++) {
|
||||
if( !myp_read_packet(m,p) )
|
||||
return 0;
|
||||
{
|
||||
MYSQL_FIELD *f = r->fields + i;
|
||||
f->catalog = m->is41 ? myp_read_bin_str(p) : NULL;
|
||||
f->db = m->is41 ? myp_read_bin_str(p) : NULL;
|
||||
f->table = myp_read_bin_str(p);
|
||||
f->org_table = m->is41 ? myp_read_bin_str(p) : NULL;
|
||||
f->name = myp_read_bin_str(p);
|
||||
f->org_name = m->is41 ? myp_read_bin_str(p) : NULL;
|
||||
if( m->is41 ) myp_read_byte(p);
|
||||
f->charset = m->is41 ? myp_read_ui16(p) : 0x08;
|
||||
f->length = m->is41 ? myp_read_int(p) : myp_read_bin(p);
|
||||
f->type = (FIELD_TYPE)(m->is41 ? myp_read_byte(p) : myp_read_bin(p));
|
||||
f->flags = m->is41 ? myp_read_ui16(p) : myp_read_bin(p);
|
||||
f->decimals = myp_read_byte(p);
|
||||
if( m->is41 ) myp_read_byte(p); // should be 0
|
||||
if( m->is41 ) myp_read_byte(p); // should be 0
|
||||
if( p->error )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// first EOF packet
|
||||
if( !myp_read_packet(m,p) )
|
||||
return 0;
|
||||
if( myp_read_byte(p) != 0xFE || p->size >= 9 )
|
||||
return 0;
|
||||
// reset packet buffer (to prevent to store large buffer in row data)
|
||||
free(p->buf);
|
||||
p->buf = NULL;
|
||||
p->mem = 0;
|
||||
// datas
|
||||
while( 1 ) {
|
||||
if( !myp_read_packet(m,p) )
|
||||
return 0;
|
||||
// EOF : end of datas
|
||||
if( (unsigned char)p->buf[0] == 0xFE && p->size < 9 )
|
||||
break;
|
||||
// ERROR ?
|
||||
if( (unsigned char)p->buf[0] == 0xFF ) {
|
||||
save_error(m,p);
|
||||
return 0;
|
||||
}
|
||||
// allocate one more row
|
||||
if( r->row_count == r->memory_rows ) {
|
||||
MYSQL_ROW_DATA *rows;
|
||||
r->memory_rows = r->memory_rows ? (r->memory_rows << 1) : 1;
|
||||
rows = (MYSQL_ROW_DATA*)malloc(r->memory_rows * sizeof(MYSQL_ROW_DATA));
|
||||
memcpy(rows,r->rows,r->row_count * sizeof(MYSQL_ROW_DATA));
|
||||
free(r->rows);
|
||||
r->rows = rows;
|
||||
}
|
||||
// read row fields
|
||||
{
|
||||
MYSQL_ROW_DATA *current = r->rows + r->row_count++;
|
||||
int prev = 0;
|
||||
current->raw = p->buf;
|
||||
current->lengths = (unsigned long*)malloc(sizeof(unsigned long) * r->nfields);
|
||||
current->datas = (char**)malloc(sizeof(char*) * r->nfields);
|
||||
for(i=0;i<r->nfields;i++) {
|
||||
int l = myp_read_bin(p);
|
||||
if( !p->error )
|
||||
p->buf[prev] = 0;
|
||||
if( l == -1 ) {
|
||||
current->lengths[i] = 0;
|
||||
current->datas[i] = NULL;
|
||||
} else {
|
||||
current->lengths[i] = l;
|
||||
current->datas[i] = p->buf + p->pos;
|
||||
p->pos += l;
|
||||
}
|
||||
prev = p->pos;
|
||||
}
|
||||
if( !p->error )
|
||||
p->buf[prev] = 0;
|
||||
}
|
||||
// the packet buffer as been stored, don't reuse it
|
||||
p->buf = NULL;
|
||||
p->mem = 0;
|
||||
if( p->error )
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
MYSQL_RES *mysql_store_result( MYSQL *m ) {
|
||||
MYSQL_RES *r;
|
||||
MYSQL_PACKET *p = &m->packet;
|
||||
if( p->id != IS_QUERY )
|
||||
return NULL;
|
||||
// OK without result
|
||||
if( p->buf[0] == 0 ) {
|
||||
p->pos = 0;
|
||||
m->last_field_count = myp_read_byte(p); // 0
|
||||
m->affected_rows = myp_read_bin(p);
|
||||
m->last_insert_id = myp_read_bin(p);
|
||||
return NULL;
|
||||
}
|
||||
r = (MYSQL_RES*)malloc(sizeof(struct _MYSQL_RES));
|
||||
memset(r,0,sizeof(struct _MYSQL_RES));
|
||||
m->errcode = 0;
|
||||
if( !do_store(m,r) ) {
|
||||
mysql_free_result(r);
|
||||
if( !m->errcode )
|
||||
error(m,"Failure while storing result",NULL);
|
||||
return NULL;
|
||||
}
|
||||
m->last_field_count = r->nfields;
|
||||
return r;
|
||||
}
|
||||
|
||||
int mysql_field_count( MYSQL *m ) {
|
||||
return m->last_field_count;
|
||||
}
|
||||
|
||||
int mysql_affected_rows( MYSQL *m ) {
|
||||
return m->affected_rows;
|
||||
}
|
||||
|
||||
int mysql_escape_string( MYSQL *m, char *sout, const char *sin, int length ) {
|
||||
return myp_escape_string(m->infos.server_charset,sout,sin,length);
|
||||
}
|
||||
|
||||
const char *mysql_character_set_name( MYSQL *m ) {
|
||||
const char *name = myp_charset_name(m->infos.server_charset);
|
||||
if( name == NULL ) {
|
||||
static char tmp[512];
|
||||
sprintf(tmp,"#%d",m->infos.server_charset);
|
||||
return tmp;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
int mysql_real_escape_string( MYSQL *m, char *sout, const char *sin, int length ) {
|
||||
if( !myp_supported_charset(m->infos.server_charset) )
|
||||
return -1;
|
||||
if( m->infos.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES )
|
||||
return myp_escape_quotes(m->infos.server_charset,sout,sin,length);
|
||||
return myp_escape_string(m->infos.server_charset,sout,sin,length);
|
||||
}
|
||||
|
||||
void mysql_close( MYSQL *m ) {
|
||||
MYSQL_PACKET *p = &m->packet;
|
||||
int pcount = 0;
|
||||
myp_begin_packet(p,0);
|
||||
myp_write_byte(p,COM_QUIT);
|
||||
myp_send_packet(m,p,&pcount);
|
||||
myp_close(m);
|
||||
free(m->packet.buf);
|
||||
free(m->infos.server_version);
|
||||
free(m);
|
||||
}
|
||||
|
||||
const char *mysql_error( MYSQL *m ) {
|
||||
return m->last_error;
|
||||
}
|
||||
|
||||
// RESULTS API
|
||||
|
||||
unsigned int mysql_num_rows( MYSQL_RES *r ) {
|
||||
return r->row_count;
|
||||
}
|
||||
|
||||
int mysql_num_fields( MYSQL_RES *r ) {
|
||||
return r->nfields;
|
||||
}
|
||||
|
||||
MYSQL_FIELD *mysql_fetch_fields( MYSQL_RES *r ) {
|
||||
return r->fields;
|
||||
}
|
||||
|
||||
unsigned long *mysql_fetch_lengths( MYSQL_RES *r ) {
|
||||
return r->current ? r->current->lengths : NULL;
|
||||
}
|
||||
|
||||
MYSQL_ROW mysql_fetch_row( MYSQL_RES * r ) {
|
||||
MYSQL_ROW_DATA *cur = r->current;
|
||||
if( cur == NULL )
|
||||
cur = r->rows;
|
||||
else {
|
||||
// free the previous result, since we're done with it
|
||||
free(cur->datas);
|
||||
free(cur->lengths);
|
||||
free(cur->raw);
|
||||
cur->datas = NULL;
|
||||
cur->lengths = NULL;
|
||||
cur->raw = NULL;
|
||||
// next
|
||||
cur++;
|
||||
}
|
||||
if( cur >= r->rows + r->row_count ) {
|
||||
free(r->rows);
|
||||
r->rows = NULL;
|
||||
r->memory_rows = 0;
|
||||
cur = NULL;
|
||||
}
|
||||
r->current = cur;
|
||||
return cur ? cur->datas : NULL;
|
||||
}
|
||||
|
||||
void mysql_free_result( MYSQL_RES *r ) {
|
||||
if( r->fields ) {
|
||||
int i;
|
||||
for(i=0;i<r->nfields;i++) {
|
||||
MYSQL_FIELD *f = r->fields + i;
|
||||
free(f->catalog);
|
||||
free(f->db);
|
||||
free(f->table);
|
||||
free(f->org_table);
|
||||
free(f->name);
|
||||
free(f->org_name);
|
||||
}
|
||||
free(r->fields);
|
||||
}
|
||||
if( r->rows ) {
|
||||
int i;
|
||||
for(i=0;i<r->row_count;i++) {
|
||||
MYSQL_ROW_DATA *row = r->rows + i;
|
||||
free(row->datas);
|
||||
free(row->lengths);
|
||||
free(row->raw);
|
||||
}
|
||||
free(r->rows);
|
||||
}
|
||||
free(r);
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
||||
414
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/my_proto.cpp
Normal file
414
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/my_proto.cpp
Normal file
@ -0,0 +1,414 @@
|
||||
/* ************************************************************************ */
|
||||
/* */
|
||||
/* MYSQL 5.0 Protocol Implementation */
|
||||
/* Copyright (c)2008 Nicolas Cannasse */
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "my_proto.h"
|
||||
|
||||
#define MAX_PACKET_LENGTH 0xFFFFFF
|
||||
|
||||
int myp_recv( MYSQL *m, void *buf, int size ) {
|
||||
hx::AutoGCFreeZone blocking;
|
||||
return myp_recv_no_gc(m,buf,size);
|
||||
}
|
||||
|
||||
int myp_recv_no_gc( MYSQL *m, void *buf, int size ) {
|
||||
while( size ) {
|
||||
int len = psock_recv_no_gc(m->s,(char*)buf,size);
|
||||
if( len <= 0 ) return size == 0 ? 1 : 0;
|
||||
buf = ((char*)buf) + len;
|
||||
size -= len;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int myp_send( MYSQL *m, void *buf, int size ) {
|
||||
hx::AutoGCFreeZone blocking;
|
||||
return myp_send_no_gc(m,buf,size);
|
||||
}
|
||||
|
||||
int myp_send_no_gc( MYSQL *m, void *buf, int size ) {
|
||||
while( size ) {
|
||||
int len = psock_send_no_gc(m->s,(char*)buf,size);
|
||||
if( len <= 0 ) return size == 0 ? 1 : 0;
|
||||
buf = ((char*)buf) + len;
|
||||
size -= len;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int myp_read( MYSQL_PACKET *p, void *buf, int size ) {
|
||||
if( p->size - p->pos < size ) {
|
||||
p->error = 1;
|
||||
return 0;
|
||||
}
|
||||
memcpy(buf,p->buf + p->pos,size);
|
||||
p->pos += size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char myp_read_byte( MYSQL_PACKET *p ) {
|
||||
unsigned char c;
|
||||
if( !myp_read(p,&c,1) )
|
||||
return 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
unsigned short myp_read_ui16( MYSQL_PACKET *p ) {
|
||||
unsigned short i;
|
||||
if( !myp_read(p,&i,2) )
|
||||
return 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
int myp_read_int( MYSQL_PACKET *p ) {
|
||||
int i;
|
||||
if( !myp_read(p,&i,4) )
|
||||
return 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
int myp_read_bin( MYSQL_PACKET *p ) {
|
||||
int c = myp_read_byte(p);
|
||||
if( c <= 250 )
|
||||
return c;
|
||||
if( c == 251 )
|
||||
return -1; // NULL
|
||||
if( c == 252 )
|
||||
return myp_read_ui16(p);
|
||||
if( c == 253 ) {
|
||||
c = 0;
|
||||
myp_read(p,&c,3);
|
||||
return c;
|
||||
}
|
||||
if( c == 254 )
|
||||
return myp_read_int(p);
|
||||
p->error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *myp_read_string( MYSQL_PACKET *p ) {
|
||||
char *str;
|
||||
if( p->pos >= p->size ) {
|
||||
p->error = 1;
|
||||
return "";
|
||||
}
|
||||
str = p->buf + p->pos;
|
||||
p->pos += strlen(str) + 1;
|
||||
return str;
|
||||
}
|
||||
|
||||
char *myp_read_bin_str( MYSQL_PACKET *p ) {
|
||||
int size = myp_read_bin(p);
|
||||
char *str;
|
||||
if( size == -1 )
|
||||
return NULL;
|
||||
if( p->error || p->pos + size > p->size ) {
|
||||
p->error = 1;
|
||||
return NULL;
|
||||
}
|
||||
str = (char*)malloc(size + 1);
|
||||
memcpy(str,p->buf + p->pos, size);
|
||||
str[size] = 0;
|
||||
p->pos += size;
|
||||
return str;
|
||||
}
|
||||
|
||||
int myp_read_packet( MYSQL *m, MYSQL_PACKET *p ) {
|
||||
hx::AutoGCFreeZone blocking;
|
||||
unsigned int psize;
|
||||
p->pos = 0;
|
||||
p->error = 0;
|
||||
if( !myp_recv_no_gc(m,&psize,4) ) {
|
||||
p->error = 1;
|
||||
p->size = 0;
|
||||
return 0;
|
||||
}
|
||||
//p->id = (psize >> 24);
|
||||
psize &= 0xFFFFFF;
|
||||
p->size = psize;
|
||||
if( p->mem < (int)psize ) {
|
||||
free(p->buf);
|
||||
p->buf = (char*)malloc(psize + 1);
|
||||
p->mem = psize;
|
||||
}
|
||||
p->buf[psize] = 0;
|
||||
if( psize == 0 || !myp_recv_no_gc(m,p->buf,psize) ) {
|
||||
p->error = 1;
|
||||
p->size = 0;
|
||||
p->buf[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int myp_send_packet( MYSQL *m, MYSQL_PACKET *p, int *packet_counter ) {
|
||||
hx::AutoGCFreeZone blocking;
|
||||
unsigned int header;
|
||||
char *buf = p->buf;
|
||||
int size = p->size;
|
||||
int next = 1;
|
||||
while( next ) {
|
||||
int psize;
|
||||
if( size >= MAX_PACKET_LENGTH )
|
||||
psize = MAX_PACKET_LENGTH;
|
||||
else {
|
||||
psize = size;
|
||||
next = 0;
|
||||
}
|
||||
header = psize | (((*packet_counter)++) << 24);
|
||||
if( !myp_send_no_gc(m,&header,4) || !myp_send_no_gc(m,buf,psize) ) {
|
||||
p->error = 1;
|
||||
return 0;
|
||||
}
|
||||
buf += psize;
|
||||
size -= psize;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void myp_begin_packet( MYSQL_PACKET *p, int minsize ) {
|
||||
if( p->mem < minsize ) {
|
||||
free(p->buf);
|
||||
p->buf = (char*)malloc(minsize + 1);
|
||||
p->mem = minsize;
|
||||
}
|
||||
p->error = 0;
|
||||
p->size = 0;
|
||||
}
|
||||
|
||||
void myp_write( MYSQL_PACKET *p, const void *data, int size ) {
|
||||
if( p->size + size > p->mem ) {
|
||||
char *buf2;
|
||||
if( p->mem == 0 ) p->mem = 32;
|
||||
do {
|
||||
p->mem <<= 1;
|
||||
} while( p->size + size > p->mem );
|
||||
buf2 = (char*)malloc(p->mem + 1);
|
||||
memcpy(buf2,p->buf,p->size);
|
||||
free(p->buf);
|
||||
p->buf = buf2;
|
||||
}
|
||||
memcpy( p->buf + p->size , data, size );
|
||||
p->size += size;
|
||||
}
|
||||
|
||||
void myp_write_byte( MYSQL_PACKET *p, int i ) {
|
||||
unsigned char c = (unsigned char)i;
|
||||
myp_write(p,&c,1);
|
||||
}
|
||||
|
||||
void myp_write_ui16( MYSQL_PACKET *p, int i ) {
|
||||
unsigned short c = (unsigned char)i;
|
||||
myp_write(p,&c,2);
|
||||
}
|
||||
|
||||
void myp_write_int( MYSQL_PACKET *p, int i ) {
|
||||
myp_write(p,&i,4);
|
||||
}
|
||||
|
||||
void myp_write_string( MYSQL_PACKET *p, const char *str ) {
|
||||
myp_write(p,str,strlen(str) + 1);
|
||||
}
|
||||
|
||||
void myp_write_bin( MYSQL_PACKET *p, int size ) {
|
||||
if( size <= 250 ) {
|
||||
unsigned char l = (unsigned char)size;
|
||||
myp_write(p,&l,1);
|
||||
} else if( size < 0x10000 ) {
|
||||
unsigned char c = 252;
|
||||
unsigned short l = (unsigned short)size;
|
||||
myp_write(p,&c,1);
|
||||
myp_write(p,&l,2);
|
||||
} else if( size < 0x1000000 ) {
|
||||
unsigned char c = 253;
|
||||
unsigned int l = (unsigned short)size;
|
||||
myp_write(p,&c,1);
|
||||
myp_write(p,&l,3);
|
||||
} else {
|
||||
unsigned char c = 254;
|
||||
myp_write(p,&c,1);
|
||||
myp_write(p,&size,4);
|
||||
}
|
||||
}
|
||||
|
||||
void myp_crypt( unsigned char *out, const unsigned char *s1, const unsigned char *s2, unsigned int len ) {
|
||||
unsigned int i;
|
||||
for(i=0;i<len;i++)
|
||||
out[i] = s1[i] ^ s2[i];
|
||||
}
|
||||
|
||||
void myp_encrypt_password( const char *pass, const char *seed, SHA1_DIGEST out ) {
|
||||
SHA1_CTX ctx;
|
||||
SHA1_DIGEST hash_stage1, hash_stage2;
|
||||
// stage 1: hash password
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx,(const unsigned char *)pass,strlen(pass));;
|
||||
sha1_final(&ctx,hash_stage1);
|
||||
// stage 2: hash stage 1; note that hash_stage2 is stored in the database
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, hash_stage1, SHA1_SIZE);
|
||||
sha1_final(&ctx, hash_stage2);
|
||||
// create crypt string as sha1(message, hash_stage2)
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, (const unsigned char *)seed, SHA1_SIZE);
|
||||
sha1_update(&ctx, hash_stage2, SHA1_SIZE);
|
||||
sha1_final( &ctx, out );
|
||||
// xor the result
|
||||
myp_crypt(out,out,hash_stage1,SHA1_SIZE);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned long seed1;
|
||||
unsigned long seed2;
|
||||
unsigned long max_value;
|
||||
double max_value_dbl;
|
||||
} rand_ctx;
|
||||
|
||||
static void random_init( rand_ctx *r, unsigned long seed1, unsigned long seed2 ) {
|
||||
r->max_value = 0x3FFFFFFFL;
|
||||
r->max_value_dbl = (double)r->max_value;
|
||||
r->seed1 = seed1 % r->max_value ;
|
||||
r->seed2 = seed2 % r->max_value;
|
||||
}
|
||||
|
||||
static double myp_rnd( rand_ctx *r ) {
|
||||
r->seed1 = (r->seed1 * 3 + r->seed2) % r->max_value;
|
||||
r->seed2 = (r->seed1 + r->seed2 + 33) % r->max_value;
|
||||
return (((double) r->seed1)/r->max_value_dbl);
|
||||
}
|
||||
|
||||
static void hash_password( unsigned long *result, const char *password, int password_len ) {
|
||||
unsigned long nr = 1345345333L, add = 7, nr2 = 0x12345671L;
|
||||
unsigned long tmp;
|
||||
const char *password_end = password + password_len;
|
||||
for(; password < password_end; password++) {
|
||||
if( *password == ' ' || *password == '\t' )
|
||||
continue;
|
||||
tmp = (unsigned long)(unsigned char)*password;
|
||||
nr ^= (((nr & 63)+add)*tmp)+(nr << 8);
|
||||
nr2 += (nr2 << 8) ^ nr;
|
||||
add += tmp;
|
||||
}
|
||||
result[0] = nr & (((unsigned long) 1L << 31) -1L);
|
||||
result[1] = nr2 & (((unsigned long) 1L << 31) -1L);
|
||||
}
|
||||
|
||||
void myp_encrypt_pass_323( const char *password, const char seed[SEED_LENGTH_323], char to[SEED_LENGTH_323] ) {
|
||||
rand_ctx r;
|
||||
unsigned long hash_pass[2], hash_seed[2];
|
||||
char extra, *to_start = to;
|
||||
const char *seed_end = seed + SEED_LENGTH_323;
|
||||
hash_password(hash_pass,password,(unsigned int)strlen(password));
|
||||
hash_password(hash_seed,seed,SEED_LENGTH_323);
|
||||
random_init(&r,hash_pass[0] ^ hash_seed[0],hash_pass[1] ^ hash_seed[1]);
|
||||
while( seed < seed_end ) {
|
||||
*to++ = (char)(floor(myp_rnd(&r)*31)+64);
|
||||
seed++;
|
||||
}
|
||||
extra= (char)(floor(myp_rnd(&r)*31));
|
||||
while( to_start != to )
|
||||
*(to_start++) ^= extra;
|
||||
}
|
||||
|
||||
// defined in mysql/strings/ctype-*.c
|
||||
const char *myp_charset_name( int charset ) {
|
||||
switch( charset ) {
|
||||
case 8:
|
||||
case 31:
|
||||
case 47:
|
||||
return "latin1";
|
||||
case 63:
|
||||
return "binary";
|
||||
// 101+ : utf16
|
||||
// 160+ : utf32
|
||||
case 33:
|
||||
case 83:
|
||||
case 223:
|
||||
case 254:
|
||||
return "utf8";
|
||||
case 45:
|
||||
case 46:
|
||||
return "utf8mb4"; // superset of utf8 with up to 4 bytes per-char
|
||||
default:
|
||||
if( charset >= 192 && charset <= 211 )
|
||||
return "utf8";
|
||||
if( charset >= 224 && charset <= 243 )
|
||||
return "utf8mb4";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int myp_supported_charset( int charset ) {
|
||||
return myp_charset_name(charset) != NULL;
|
||||
}
|
||||
|
||||
int myp_escape_string( int charset, char *sout, const char *sin, int length ) {
|
||||
// this is safe for UTF8 as well since mysql protects against invalid UTF8 char injection
|
||||
const char *send = sin + length;
|
||||
char *sbegin = sout;
|
||||
while( sin != send ) {
|
||||
char c = *sin++;
|
||||
switch( c ) {
|
||||
case 0:
|
||||
*sout++ = '\\';
|
||||
*sout++ = '0';
|
||||
break;
|
||||
case '\n':
|
||||
*sout++ = '\\';
|
||||
*sout++ = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*sout++ = '\\';
|
||||
*sout++ = 'r';
|
||||
break;
|
||||
case '\\':
|
||||
*sout++ = '\\';
|
||||
*sout++ = '\\';
|
||||
break;
|
||||
case '\'':
|
||||
*sout++ = '\\';
|
||||
*sout++ = '\'';
|
||||
break;
|
||||
case '"':
|
||||
*sout++ = '\\';
|
||||
*sout++ = '"';
|
||||
break;
|
||||
case '\032':
|
||||
*sout++ = '\\';
|
||||
*sout++ = 'Z';
|
||||
break;
|
||||
default:
|
||||
*sout++ = c;
|
||||
}
|
||||
}
|
||||
*sout = 0;
|
||||
return sout - sbegin;
|
||||
}
|
||||
|
||||
int myp_escape_quotes( int charset, char *sout, const char *sin, int length ) {
|
||||
const char *send = sin + length;
|
||||
char *sbegin = sout;
|
||||
while( sin != send ) {
|
||||
char c = *sin++;
|
||||
*sout++ = c;
|
||||
if( c == '\'' )
|
||||
*sout++ = c;
|
||||
}
|
||||
*sout = 0;
|
||||
return sout - sbegin;
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
||||
174
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/my_proto.h
Normal file
174
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/my_proto.h
Normal file
@ -0,0 +1,174 @@
|
||||
/* ************************************************************************ */
|
||||
/* */
|
||||
/* MYSQL 5.0 Protocol Implementation */
|
||||
/* Copyright (c)2008 Nicolas Cannasse */
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MY_PROTO_H
|
||||
#define MY_PROTO_H
|
||||
|
||||
#include "mysql.h"
|
||||
#include "socket.h"
|
||||
#include "sha1.h"
|
||||
|
||||
typedef enum {
|
||||
FL_LONG_PASSWORD = 1,
|
||||
FL_FOUND_ROWS = 2,
|
||||
FL_LONG_FLAG = 4,
|
||||
FL_CONNECT_WITH_DB = 8,
|
||||
FL_NO_SCHEMA = 16,
|
||||
FL_COMPRESS = 32,
|
||||
FL_ODBC = 64,
|
||||
FL_LOCAL_FILES = 128,
|
||||
FL_IGNORE_SPACE = 256,
|
||||
FL_PROTOCOL_41 = 512,
|
||||
FL_INTERACTIVE = 1024,
|
||||
FL_SSL = 2048,
|
||||
FL_IGNORE_SIGPIPE = 4096,
|
||||
FL_TRANSACTIONS = 8192,
|
||||
FL_RESERVED = 16384,
|
||||
FL_SECURE_CONNECTION = 32768,
|
||||
FL_MULTI_STATEMENTS = 65536,
|
||||
FL_MULTI_RESULTS = 131072,
|
||||
} MYSQL_FLAG;
|
||||
|
||||
typedef enum {
|
||||
COM_SLEEP = 0x00,
|
||||
COM_QUIT = 0x01,
|
||||
COM_INIT_DB = 0x02,
|
||||
COM_QUERY = 0x03,
|
||||
COM_FIELD_LIST = 0x04,
|
||||
//COM_CREATE_DB = 0x05,
|
||||
//COM_DROP_DB = 0x06
|
||||
COM_REFRESH = 0x07,
|
||||
COM_SHUTDOWN = 0x08,
|
||||
COM_STATISTICS = 0x09,
|
||||
COM_PROCESS_INFO = 0x0A,
|
||||
//COM_CONNECT = 0x0B,
|
||||
COM_PROCESS_KILL = 0x0C,
|
||||
COM_DEBUG = 0x0D,
|
||||
COM_PING = 0x0E,
|
||||
//COM_TIME = 0x0F,
|
||||
//COM_DELAYED_INSERT = 0x10,
|
||||
COM_CHANGE_USER = 0x11,
|
||||
COM_BINLOG_DUMP = 0x12,
|
||||
COM_TABLE_DUMP = 0x13,
|
||||
COM_CONNECT_OUT = 0x14,
|
||||
COM_REGISTER_SLAVE = 0x15,
|
||||
COM_STMT_PREPARE = 0x16,
|
||||
COM_STMT_EXECUTE = 0x17,
|
||||
COM_STMT_SEND_LONG_DATA = 0x18,
|
||||
COM_STMT_CLOSE = 0x19,
|
||||
COM_STMT_RESET = 0x1A,
|
||||
COM_SET_OPTION = 0x1B,
|
||||
COM_STMT_FETCH = 0x1C,
|
||||
} MYSQL_COMMAND;
|
||||
|
||||
typedef enum {
|
||||
SERVER_STATUS_IN_TRANS = 1,
|
||||
SERVER_STATUS_AUTOCOMMIT = 2,
|
||||
SERVER_MORE_RESULTS_EXISTS = 8,
|
||||
SERVER_QUERY_NO_GOOD_INDEX_USED = 16,
|
||||
SERVER_QUERY_NO_INDEX_USED = 32,
|
||||
SERVER_STATUS_CURSOR_EXISTS = 64,
|
||||
SERVER_STATUS_LAST_ROW_SENT = 128,
|
||||
SERVER_STATUS_DB_DROPPED = 256,
|
||||
SERVER_STATUS_NO_BACKSLASH_ESCAPES = 512,
|
||||
} MYSQL_SERVER_STATUS;
|
||||
|
||||
typedef struct {
|
||||
unsigned char proto_version;
|
||||
char *server_version;
|
||||
unsigned int thread_id;
|
||||
unsigned int server_flags;
|
||||
unsigned char server_charset;
|
||||
unsigned short server_status;
|
||||
} MYSQL_INFOS;
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
int error;
|
||||
int size;
|
||||
int pos;
|
||||
int mem;
|
||||
char *buf;
|
||||
} MYSQL_PACKET;
|
||||
|
||||
#define MAX_ERR_SIZE 1024
|
||||
#define IS_QUERY -123456
|
||||
|
||||
struct _MYSQL {
|
||||
PSOCK s;
|
||||
MYSQL_INFOS infos;
|
||||
MYSQL_PACKET packet;
|
||||
int is41;
|
||||
int errcode;
|
||||
int last_field_count;
|
||||
int affected_rows;
|
||||
int last_insert_id;
|
||||
char last_error[MAX_ERR_SIZE];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *raw;
|
||||
unsigned long *lengths;
|
||||
char **datas;
|
||||
} MYSQL_ROW_DATA;
|
||||
|
||||
struct _MYSQL_RES {
|
||||
int nfields;
|
||||
MYSQL_FIELD *fields;
|
||||
MYSQL_ROW_DATA *rows;
|
||||
MYSQL_ROW_DATA *current;
|
||||
int row_count;
|
||||
int memory_rows;
|
||||
};
|
||||
|
||||
|
||||
// network
|
||||
int myp_recv_no_gc( MYSQL *m, void *buf, int size );
|
||||
int myp_send_no_gc( MYSQL *m, void *buf, int size );
|
||||
int myp_recv( MYSQL *m, void *buf, int size );
|
||||
int myp_send( MYSQL *m, void *buf, int size );
|
||||
int myp_read_packet( MYSQL *m, MYSQL_PACKET *p );
|
||||
int myp_send_packet( MYSQL *m, MYSQL_PACKET *p, int *packet_counter );
|
||||
|
||||
// packet read
|
||||
int myp_read( MYSQL_PACKET *p, void *buf, int size );
|
||||
unsigned char myp_read_byte( MYSQL_PACKET *p );
|
||||
unsigned short myp_read_ui16( MYSQL_PACKET *p );
|
||||
int myp_read_int( MYSQL_PACKET *p );
|
||||
const char *myp_read_string( MYSQL_PACKET *p );
|
||||
int myp_read_bin( MYSQL_PACKET *p );
|
||||
char *myp_read_bin_str( MYSQL_PACKET *p );
|
||||
|
||||
// packet write
|
||||
void myp_begin_packet( MYSQL_PACKET *p, int minsize );
|
||||
void myp_write( MYSQL_PACKET *p, const void *data, int size );
|
||||
void myp_write_byte( MYSQL_PACKET *p, int b );
|
||||
void myp_write_ui16( MYSQL_PACKET *p, int b );
|
||||
void myp_write_int( MYSQL_PACKET *p, int b );
|
||||
|
||||
void myp_write_string( MYSQL_PACKET *p, const char *str );
|
||||
void myp_write_bin( MYSQL_PACKET *p, int size );
|
||||
|
||||
// passwords
|
||||
#define SEED_LENGTH_323 8
|
||||
|
||||
void myp_crypt( unsigned char *out, const unsigned char *s1, const unsigned char *s2, unsigned int len );
|
||||
void myp_encrypt_password( const char *pass, const char *seed, SHA1_DIGEST out );
|
||||
void myp_encrypt_pass_323( const char *pass, const char seed[SEED_LENGTH_323], char out[SEED_LENGTH_323] );
|
||||
|
||||
// escaping
|
||||
int myp_supported_charset( int charset );
|
||||
const char *myp_charset_name( int charset );
|
||||
int myp_escape_string( int charset, char *sout, const char *sin, int length );
|
||||
int myp_escape_quotes( int charset, char *sout, const char *sin, int length );
|
||||
|
||||
#endif
|
||||
/* ************************************************************************ */
|
||||
120
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/mysql.h
Normal file
120
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/mysql.h
Normal file
@ -0,0 +1,120 @@
|
||||
/* ************************************************************************ */
|
||||
/* */
|
||||
/* MYSQL 5.0 Protocol Implementation */
|
||||
/* Copyright (c)2008 Nicolas Cannasse */
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MYSQL_H
|
||||
#define MYSQL_H
|
||||
|
||||
struct _MYSQL;
|
||||
struct _MYSQL_RES;
|
||||
typedef struct _MYSQL MYSQL;
|
||||
typedef struct _MYSQL_RES MYSQL_RES;
|
||||
typedef char **MYSQL_ROW;
|
||||
|
||||
typedef enum enum_field_types {
|
||||
FIELD_TYPE_DECIMAL = 0x00,
|
||||
FIELD_TYPE_TINY = 0x01,
|
||||
FIELD_TYPE_SHORT = 0x02,
|
||||
FIELD_TYPE_LONG = 0x03,
|
||||
FIELD_TYPE_FLOAT = 0x04,
|
||||
FIELD_TYPE_DOUBLE = 0x05,
|
||||
FIELD_TYPE_NULL = 0x06,
|
||||
FIELD_TYPE_TIMESTAMP = 0x07,
|
||||
FIELD_TYPE_LONGLONG = 0x08,
|
||||
FIELD_TYPE_INT24 = 0x09,
|
||||
FIELD_TYPE_DATE = 0x0A,
|
||||
FIELD_TYPE_TIME = 0x0B,
|
||||
FIELD_TYPE_DATETIME = 0x0C,
|
||||
FIELD_TYPE_YEAR = 0x0D,
|
||||
FIELD_TYPE_NEWDATE = 0x0E,
|
||||
FIELD_TYPE_VARCHAR = 0x0F,
|
||||
FIELD_TYPE_BIT = 0x10,
|
||||
FIELD_TYPE_NEWDECIMAL = 0xF6,
|
||||
FIELD_TYPE_ENUM = 0xF7,
|
||||
FIELD_TYPE_SET = 0xF8,
|
||||
FIELD_TYPE_TINY_BLOB = 0xF9,
|
||||
FIELD_TYPE_MEDIUM_BLOB = 0xFA,
|
||||
FIELD_TYPE_LONG_BLOB = 0xFB,
|
||||
FIELD_TYPE_BLOB = 0xFC,
|
||||
FIELD_TYPE_VAR_STRING = 0xFD,
|
||||
FIELD_TYPE_STRING = 0xFE,
|
||||
FIELD_TYPE_GEOMETRY = 0xFF
|
||||
} FIELD_TYPE;
|
||||
|
||||
typedef enum {
|
||||
NOT_NULL_FLAG = 1,
|
||||
PRI_KEY_FLAG = 2,
|
||||
UNIQUE_KEY_FLAG = 4,
|
||||
MULTIPLE_KEY_FLAG = 8,
|
||||
BLOB_FLAG = 16,
|
||||
UNSIGNED_FLAG = 32,
|
||||
ZEROFILL_FLAG = 64,
|
||||
BINARY_FLAG = 128,
|
||||
ENUM_FLAG = 256,
|
||||
AUTO_INCREMENT_FLAG = 512,
|
||||
TIMESTAMP_FLAG = 1024,
|
||||
SET_FLAG = 2048,
|
||||
NUM_FLAG = 32768,
|
||||
} __FIELD_FLAG;
|
||||
|
||||
typedef struct {
|
||||
char *catalog;
|
||||
char *db;
|
||||
char *table;
|
||||
char *org_table;
|
||||
char *name;
|
||||
char *org_name;
|
||||
int charset;
|
||||
int length;
|
||||
int flags;
|
||||
int decimals;
|
||||
FIELD_TYPE type;
|
||||
} MYSQL_FIELD;
|
||||
|
||||
#define mysql_init mp_init
|
||||
#define mysql_real_connect mp_real_connect
|
||||
#define mysql_select_db mp_select_db
|
||||
#define mysql_real_query mp_real_query
|
||||
#define mysql_store_result mp_store_result
|
||||
#define mysql_field_count mp_field_count
|
||||
#define mysql_affected_rows mp_affected_rows
|
||||
#define mysql_escape_string mp_escape_string
|
||||
#define mysql_real_escape_string mp_real_escape_string
|
||||
#define mysql_close mp_close
|
||||
#define mysql_error mp_error
|
||||
#define mysql_num_rows mp_num_rows
|
||||
#define mysql_num_fields mp_num_fields
|
||||
#define mysql_fetch_fields mp_fetch_fields
|
||||
#define mysql_fetch_lengths mp_fetch_lengths
|
||||
#define mysql_fetch_row mp_fetch_row
|
||||
#define mysql_free_result mp_free_result
|
||||
|
||||
MYSQL *mysql_init( void * );
|
||||
MYSQL *mysql_real_connect( MYSQL *m, const char *host, const char *user, const char *pass, void *unused, int port, const char *socket, int options );
|
||||
int mysql_select_db( MYSQL *m, const char *dbname );
|
||||
int mysql_real_query( MYSQL *m, const char *query, int qlength );
|
||||
MYSQL_RES *mysql_store_result( MYSQL *m );
|
||||
int mysql_field_count( MYSQL *m );
|
||||
int mysql_affected_rows( MYSQL *m );
|
||||
int mysql_escape_string( MYSQL *m, char *sout, const char *sin, int length );
|
||||
int mysql_real_escape_string( MYSQL *m, char *sout, const char *sin, int length );
|
||||
void mysql_close( MYSQL *m );
|
||||
const char *mysql_error( MYSQL *m );
|
||||
const char *mysql_character_set_name( MYSQL *m );
|
||||
|
||||
unsigned int mysql_num_rows( MYSQL_RES *r );
|
||||
int mysql_num_fields( MYSQL_RES *r );
|
||||
MYSQL_FIELD *mysql_fetch_fields( MYSQL_RES *r );
|
||||
unsigned long *mysql_fetch_lengths( MYSQL_RES *r );
|
||||
MYSQL_ROW mysql_fetch_row( MYSQL_RES * r );
|
||||
void mysql_free_result( MYSQL_RES *r );
|
||||
|
||||
#endif
|
||||
/* ************************************************************************ */
|
||||
128
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/sha1.cpp
Normal file
128
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/sha1.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <hxcpp.h>
|
||||
#include "sha1.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// original code by Steve Reid
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
#ifdef HXCPP_BIG_ENDIAN
|
||||
# define blk0(i) block[i]
|
||||
#else
|
||||
# define blk0(i) (block[i] = (rol(block[i],24)&0xFF00FF00) \
|
||||
|(rol(block[i],8)&0x00FF00FF))
|
||||
#endif
|
||||
#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
|
||||
^block[(i+2)&15]^block[i&15],1))
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
static void sha1_transform( unsigned int state[5], unsigned char buffer[64] ) {
|
||||
unsigned int a, b, c, d, e;
|
||||
unsigned int block[16];
|
||||
memcpy(block, buffer, 64);
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
}
|
||||
|
||||
void sha1_init( SHA1_CTX *context ) {
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
context->state[4] = 0xC3D2E1F0;
|
||||
context->count[0] = context->count[1] = 0;
|
||||
}
|
||||
|
||||
void sha1_update( SHA1_CTX *context, const unsigned char *data, unsigned int len ) {
|
||||
unsigned int i, j;
|
||||
j = (context->count[0] >> 3) & 63;
|
||||
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
|
||||
context->count[1] += (len >> 29);
|
||||
if ((j + len) > 63) {
|
||||
memcpy(&context->buffer[j], data, (i = 64-j));
|
||||
sha1_transform(context->state, context->buffer);
|
||||
for ( ; i + 63 < len; i += 64 )
|
||||
sha1_transform(context->state, (unsigned char *)&data[i]);
|
||||
j = 0;
|
||||
} else
|
||||
i = 0;
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
void sha1_final( SHA1_CTX *context, unsigned char digest[SHA1_SIZE] ) {
|
||||
unsigned int i;
|
||||
unsigned char finalcount[8];
|
||||
for (i = 0; i < 8; i++) {
|
||||
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
sha1_update(context, (unsigned char *)"\200", 1);
|
||||
while ((context->count[0] & 504) != 448) {
|
||||
sha1_update(context, (unsigned char *)"\0", 1);
|
||||
}
|
||||
sha1_update(context, finalcount, 8);
|
||||
for (i = 0; i < SHA1_SIZE; i++) {
|
||||
digest[i] = (unsigned char)
|
||||
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
sha1_transform(context->state, context->buffer);
|
||||
}
|
||||
|
||||
40
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/sha1.h
Normal file
40
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/sha1.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SHA1_H
|
||||
#define SHA1_H
|
||||
|
||||
#define SHA1_SIZE 20
|
||||
|
||||
typedef unsigned char SHA1_DIGEST[SHA1_SIZE];
|
||||
|
||||
typedef struct {
|
||||
unsigned int state[5];
|
||||
unsigned int count[2];
|
||||
unsigned char buffer[64];
|
||||
} SHA1_CTX;
|
||||
|
||||
void sha1_init( SHA1_CTX *c );
|
||||
void sha1_update( SHA1_CTX *c, const unsigned char *data, unsigned int len );
|
||||
void sha1_final( SHA1_CTX *c, SHA1_DIGEST digest );
|
||||
|
||||
#endif
|
||||
/* ************************************************************************ */
|
||||
224
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/socket.cpp
Normal file
224
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/socket.cpp
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <hxcpp.h>
|
||||
#include "socket.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
static int init_done = 0;
|
||||
static WSADATA init_data;
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/time.h>
|
||||
# include <netinet/in.h>
|
||||
# include <netinet/tcp.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <unistd.h>
|
||||
# include <netdb.h>
|
||||
# include <fcntl.h>
|
||||
# include <errno.h>
|
||||
# include <stdio.h>
|
||||
# include <poll.h>
|
||||
# define closesocket close
|
||||
# define SOCKET_ERROR (-1)
|
||||
#endif
|
||||
|
||||
#if (defined(NEKO_WINDOWS) || defined(NEKO_MAC)) && !defined(MSG_NOSIGNAL)
|
||||
# define MSG_NOSIGNAL 0
|
||||
#endif
|
||||
|
||||
static SERR block_error() {
|
||||
#ifdef NEKO_WINDOWS
|
||||
int err = WSAGetLastError();
|
||||
if( err == WSAEWOULDBLOCK || err == WSAEALREADY )
|
||||
#else
|
||||
if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY )
|
||||
#endif
|
||||
return PS_BLOCK;
|
||||
return PS_ERROR;
|
||||
}
|
||||
|
||||
void psock_init() {
|
||||
#ifdef NEKO_WINDOWS
|
||||
if( !init_done ) {
|
||||
WSAStartup(MAKEWORD(2,0),&init_data);
|
||||
init_done = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PSOCK psock_create() {
|
||||
hx::AutoGCFreeZone block;
|
||||
PSOCK s = socket(AF_INET,SOCK_STREAM,0);
|
||||
# if defined(NEKO_MAC) || defined(NEKO_BSD)
|
||||
if( s != INVALID_SOCKET )
|
||||
setsockopt(s,SOL_SOCKET,SO_NOSIGPIPE,NULL,0);
|
||||
# endif
|
||||
# ifdef NEKO_POSIX
|
||||
// we don't want sockets to be inherited in case of exec
|
||||
{
|
||||
int old = fcntl(s,F_GETFD,0);
|
||||
if( old >= 0 ) fcntl(s,F_SETFD,old|FD_CLOEXEC);
|
||||
}
|
||||
# endif
|
||||
return s;
|
||||
}
|
||||
|
||||
void psock_close( PSOCK s ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
POSIX_LABEL(close_again);
|
||||
if( closesocket(s) ) {
|
||||
HANDLE_EINTR(close_again);
|
||||
}
|
||||
}
|
||||
|
||||
int psock_send( PSOCK s, const char *buf, int size ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
return psock_send_no_gc(s,buf,size);
|
||||
}
|
||||
|
||||
int psock_send_no_gc( PSOCK s, const char *buf, int size ) {
|
||||
int ret;
|
||||
POSIX_LABEL(send_again);
|
||||
ret = send(s,buf,size,MSG_NOSIGNAL);
|
||||
if( ret == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(send_again);
|
||||
return block_error();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int psock_recv( PSOCK s, char *buf, int size ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
return psock_recv_no_gc(s,buf,size);
|
||||
}
|
||||
|
||||
int psock_recv_no_gc( PSOCK s, char *buf, int size ) {
|
||||
int ret;
|
||||
POSIX_LABEL(recv_again);
|
||||
ret = recv(s,buf,size,MSG_NOSIGNAL);
|
||||
if( ret == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(recv_again);
|
||||
return block_error();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
PHOST phost_resolve( const char *host ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
PHOST ip = inet_addr(host);
|
||||
if( ip == INADDR_NONE ) {
|
||||
struct hostent *h;
|
||||
# if defined(NEKO_WINDOWS) || defined(NEKO_MAC) || defined(BLACKBERRY)
|
||||
h = gethostbyname(host);
|
||||
# else
|
||||
struct hostent hbase;
|
||||
char buf[1024];
|
||||
int errcode;
|
||||
gethostbyname_r(host,&hbase,buf,1024,&h,&errcode);
|
||||
# endif
|
||||
if( h == NULL )
|
||||
return UNRESOLVED_HOST;
|
||||
ip = *((unsigned int*)h->h_addr);
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
SERR psock_connect( PSOCK s, PHOST host, int port ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr,0,sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
*(int*)&addr.sin_addr.s_addr = host;
|
||||
if( connect(s,(struct sockaddr*)&addr,sizeof(addr)) != 0 )
|
||||
return block_error();
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
SERR psock_set_timeout( PSOCK s, double t ) {
|
||||
#ifdef NEKO_WINDOWS
|
||||
int time = (int)(t * 1000);
|
||||
#else
|
||||
struct timeval time;
|
||||
time.tv_usec = (int)((t - (int)t)*1000000);
|
||||
time.tv_sec = (int)t;
|
||||
#endif
|
||||
if( setsockopt(s,SOL_SOCKET,SO_SNDTIMEO,(char*)&time,sizeof(time)) != 0 )
|
||||
return PS_ERROR;
|
||||
if( setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(char*)&time,sizeof(time)) != 0 )
|
||||
return PS_ERROR;
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
|
||||
SERR psock_set_blocking( PSOCK s, int block ) {
|
||||
#ifdef NEKO_WINDOWS
|
||||
{
|
||||
unsigned long arg = !block;
|
||||
if( ioctlsocket(s,FIONBIO,&arg) != 0 )
|
||||
return PS_ERROR;
|
||||
}
|
||||
#else
|
||||
{
|
||||
int rights = fcntl(s,F_GETFL);
|
||||
if( rights == -1 )
|
||||
return PS_ERROR;
|
||||
if( block )
|
||||
rights &= ~O_NONBLOCK;
|
||||
else
|
||||
rights |= O_NONBLOCK;
|
||||
if( fcntl(s,F_SETFL,rights) == -1 )
|
||||
return PS_ERROR;
|
||||
}
|
||||
#endif
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
SERR psock_set_fastsend( PSOCK s, int fast ) {
|
||||
if( setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char*)&fast,sizeof(fast)) )
|
||||
return block_error();
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
void psock_wait( PSOCK s ) {
|
||||
hx::AutoGCFreeZone block;
|
||||
# ifdef NEKO_WINDOWS
|
||||
fd_set set;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(s,&set);
|
||||
select((int)s+1,&set,NULL,NULL,NULL);
|
||||
# else
|
||||
struct pollfd fds;
|
||||
POSIX_LABEL(poll_again);
|
||||
fds.fd = s;
|
||||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
if( poll(&fds,1,-1) < 0 ) {
|
||||
HANDLE_EINTR(poll_again);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
||||
62
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/socket.h
Normal file
62
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/mysql/socket.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SOCKET_H
|
||||
#define SOCKET_H
|
||||
|
||||
#include <hx/OS.h>
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
# include <winsock2.h>
|
||||
typedef SOCKET PSOCK;
|
||||
#else
|
||||
typedef int PSOCK;
|
||||
# define INVALID_SOCKET (-1)
|
||||
#endif
|
||||
|
||||
typedef unsigned int PHOST;
|
||||
|
||||
#define UNRESOLVED_HOST ((PHOST)-1)
|
||||
|
||||
typedef enum {
|
||||
PS_OK = 0,
|
||||
PS_ERROR = -1,
|
||||
PS_BLOCK = -2,
|
||||
} SERR;
|
||||
|
||||
void psock_init();
|
||||
PSOCK psock_create();
|
||||
void psock_close( PSOCK s );
|
||||
SERR psock_connect( PSOCK s, PHOST h, int port );
|
||||
SERR psock_set_timeout( PSOCK s, double timeout );
|
||||
SERR psock_set_blocking( PSOCK s, int block );
|
||||
SERR psock_set_fastsend( PSOCK s, int fast );
|
||||
|
||||
int psock_send( PSOCK s, const char *buf, int size );
|
||||
int psock_recv( PSOCK s, char *buf, int size );
|
||||
|
||||
int psock_send_no_gc( PSOCK s, const char *buf, int size );
|
||||
int psock_recv_no_gc( PSOCK s, char *buf, int size );
|
||||
|
||||
PHOST phost_resolve( const char *hostname );
|
||||
|
||||
#endif
|
||||
/* ************************************************************************ */
|
||||
45
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/regexp/Build.xml
Normal file
45
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/regexp/Build.xml
Normal file
@ -0,0 +1,45 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<set name="PCRE_DIR" value="${HXCPP}/project/thirdparty/pcre2-10.42/src" />
|
||||
|
||||
<files id="pcre2-8" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<compilerflag value="-DPCRE2_CODE_UNIT_WIDTH=8" />
|
||||
<compilerflag value="-DSUPPORT_PCRE2_8" />
|
||||
|
||||
<include name="${this_dir}/pcre2_sources.xml" />
|
||||
</files>
|
||||
|
||||
<files id="pcre2-16" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<compilerflag value="-DPCRE2_CODE_UNIT_WIDTH=16" />
|
||||
<compilerflag value="-DSUPPORT_PCRE2_16" />
|
||||
|
||||
<include name="${this_dir}/pcre2_sources.xml" />
|
||||
</files>
|
||||
|
||||
<files id="hxcpp_regexp">
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<compilerflag value="-I${PCRE_DIR}"/>
|
||||
|
||||
<file name="${this_dir}/RegExp.cpp"/>
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_regexp" />
|
||||
<files id="pcre2-8" />
|
||||
<files id="pcre2-16" if="hxcpp_smart_strings" />
|
||||
</target>
|
||||
|
||||
</xml>
|
||||
294
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/regexp/RegExp.cpp
Normal file
294
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/regexp/RegExp.cpp
Normal file
@ -0,0 +1,294 @@
|
||||
#include <hxcpp.h>
|
||||
#include <string.h>
|
||||
|
||||
//#define PCRE2_STATIC
|
||||
#define PCRE2_CODE_UNIT_WIDTH 0
|
||||
|
||||
//#include <pcre2.h>
|
||||
#include "../../../../project/thirdparty/pcre2-10.42-8/src/pcre2.h"
|
||||
|
||||
#define PCRE(o) ((pcredata*)o.mPtr)
|
||||
|
||||
static void regexp_compilation_error(String pattern, int error_code, size_t error_offset) {
|
||||
PCRE2_UCHAR8 error_buffer[128];
|
||||
pcre2_get_error_message_8(error_code, error_buffer, sizeof(error_buffer));
|
||||
hx::Throw(HX_CSTRING("Regexp compilation error : ") + String((const char*)error_buffer) + HX_CSTRING(" in ") + pattern);
|
||||
}
|
||||
|
||||
struct pcredata : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdPcreData };
|
||||
|
||||
pcre2_code_8 *rUtf8;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
pcre2_code_16 *rUtf16;
|
||||
#endif
|
||||
|
||||
int n_groups;
|
||||
pcre2_match_data_8* match_data8;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
pcre2_match_data_16* match_data16;
|
||||
#endif
|
||||
|
||||
unsigned int flags;
|
||||
String string;
|
||||
String expr;
|
||||
|
||||
void create8(pcre2_code_8 *inR, String inExpr, int inFlags)
|
||||
{
|
||||
rUtf8 = inR;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
rUtf16 = 0;
|
||||
#endif
|
||||
expr = inExpr;
|
||||
HX_OBJ_WB_GET(this, expr.raw_ref());
|
||||
flags = inFlags;
|
||||
|
||||
n_groups = 0;
|
||||
pcre2_pattern_info_8(rUtf8,PCRE2_INFO_CAPTURECOUNT,&n_groups);
|
||||
n_groups++;
|
||||
match_data8 = pcre2_match_data_create_from_pattern_8(rUtf8, NULL);
|
||||
#ifdef HX_SMART_STRINGS
|
||||
match_data16 = 0;
|
||||
#endif
|
||||
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
void create16(pcre2_code_16 *inR, String inExpr, int inFlags)
|
||||
{
|
||||
rUtf8 = 0;
|
||||
rUtf16 = inR;
|
||||
expr = inExpr;
|
||||
HX_OBJ_WB_GET(this, expr.raw_ref());
|
||||
flags = inFlags;
|
||||
|
||||
n_groups = 0;
|
||||
pcre2_pattern_info_16(rUtf16,PCRE2_INFO_CAPTURECOUNT,&n_groups);
|
||||
n_groups++;
|
||||
match_data8 = 0;
|
||||
match_data16 = pcre2_match_data_create_from_pattern_16(rUtf16, NULL);
|
||||
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool run(String string,int pos,int len)
|
||||
{
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (string.isUTF16Encoded())
|
||||
{
|
||||
if (!rUtf16)
|
||||
{
|
||||
int error_code;
|
||||
size_t error_offset;
|
||||
hx::strbuf buf;
|
||||
int utf16Length = 0;
|
||||
PCRE2_SPTR16 utf16 = (PCRE2_SPTR16)expr.wc_str(&buf, &utf16Length);
|
||||
rUtf16 = pcre2_compile_16((PCRE2_SPTR16)expr.wc_str(&buf),utf16Length,flags,&error_code,&error_offset,NULL);
|
||||
if (!rUtf16) {
|
||||
regexp_compilation_error(expr,error_code,error_offset);
|
||||
}
|
||||
match_data16 = pcre2_match_data_create_from_pattern_16(rUtf16, NULL);
|
||||
}
|
||||
|
||||
int n = pcre2_match_16(rUtf16,(PCRE2_SPTR16)string.raw_wptr(),pos+len,pos,PCRE2_NO_UTF_CHECK,match_data16,NULL);
|
||||
return n>=0;
|
||||
}
|
||||
|
||||
if (!rUtf8)
|
||||
{
|
||||
int error_code;
|
||||
size_t error_offset;
|
||||
int utf8Length = 0;
|
||||
PCRE2_SPTR8 utf8 = (PCRE2_SPTR8)expr.utf8_str(NULL, true, &utf8Length);
|
||||
rUtf8 = pcre2_compile_8(utf8, utf8Length, flags, &error_code, &error_offset, NULL);
|
||||
if (!rUtf8) {
|
||||
regexp_compilation_error(expr,error_code,error_offset);
|
||||
}
|
||||
match_data8 = pcre2_match_data_create_from_pattern_8(rUtf8, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
return pcre2_match_8(rUtf8,(PCRE2_SPTR8)string.utf8_str(),pos+len,pos,PCRE2_NO_UTF_CHECK,match_data8,NULL) >= 0;
|
||||
}
|
||||
|
||||
size_t* get_matches() {
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (string.isUTF16Encoded()) {
|
||||
return pcre2_get_ovector_pointer_16(match_data16);
|
||||
}
|
||||
#endif
|
||||
return pcre2_get_ovector_pointer_8(match_data8);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
pcre2_code_free_8( rUtf8 );
|
||||
pcre2_match_data_free_8( match_data8 );
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
pcre2_code_free_16( rUtf16 );
|
||||
pcre2_match_data_free_16( match_data16 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void __Mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(string); HX_MARK_MEMBER(expr); }
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(string); HX_VISIT_MEMBER(expr); }
|
||||
#endif
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((pcredata *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return expr; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
regexp_new_options : reg:string -> options:string -> 'regexp
|
||||
<doc>Build a new regexpr with the following options :
|
||||
<ul>
|
||||
<li>i : case insensitive matching</li>
|
||||
<li>s : . match anything including newlines</li>
|
||||
<li>m : treat the input as a multiline string</li>
|
||||
<li>u : run in utf8 mode</li>
|
||||
<li>g : turn off greedy behavior</li>
|
||||
</ul>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
Dynamic _hx_regexp_new_options(String s, String opt)
|
||||
{
|
||||
hx::strbuf buf;
|
||||
const char *o = opt.utf8_str(&buf);
|
||||
int options = PCRE2_UCP | PCRE2_UTF;
|
||||
while( *o )
|
||||
{
|
||||
switch( *o++ )
|
||||
{
|
||||
case 'i':
|
||||
options |= PCRE2_CASELESS;
|
||||
break;
|
||||
case 's':
|
||||
options |= PCRE2_DOTALL;
|
||||
break;
|
||||
case 'm':
|
||||
options |= PCRE2_MULTILINE;
|
||||
break;
|
||||
case 'g':
|
||||
options |= PCRE2_UNGREEDY;
|
||||
break;
|
||||
case 'u':
|
||||
break;
|
||||
default:
|
||||
hx::Throw( HX_CSTRING("Regexp unknown modifier : ") + String::fromCharCode(o[-1]) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (s.isUTF16Encoded())
|
||||
{
|
||||
int error_code;
|
||||
size_t error_offset;
|
||||
pcre2_code_16 *p = pcre2_compile_16((PCRE2_SPTR16)s.raw_wptr(),s.length,options,&error_code,&error_offset,NULL);
|
||||
if( !p ) {
|
||||
regexp_compilation_error(s,error_code,error_offset);
|
||||
}
|
||||
|
||||
pcredata *pdata = new pcredata;
|
||||
pdata->create16(p,s,options);
|
||||
return pdata;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int error_code = 0;
|
||||
size_t error_offset;
|
||||
pcre2_code_8 *p = pcre2_compile_8((PCRE2_SPTR8)s.utf8_str(),s.length,options,&error_code,&error_offset,NULL);
|
||||
if( !p ) {
|
||||
regexp_compilation_error(s,error_code,error_offset);
|
||||
}
|
||||
|
||||
pcredata *pdata = new pcredata;
|
||||
pdata->create8(p,s,options);
|
||||
return pdata;
|
||||
}
|
||||
}
|
||||
|
||||
bool _hx_regexp_match(Dynamic handle, String string, int pos, int len)
|
||||
{
|
||||
if( pos < 0 || len < 0 || pos > string.length || pos + len > string.length )
|
||||
return false;
|
||||
|
||||
pcredata *d = PCRE(handle);
|
||||
|
||||
if( d->run(string,pos,len) )
|
||||
{
|
||||
d->string = string;
|
||||
HX_OBJ_WB_GET(d, d->string.raw_ref());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->string = String();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String _hx_regexp_matched(Dynamic handle, int m)
|
||||
{
|
||||
pcredata *d = PCRE(handle);
|
||||
|
||||
if( m < 0 || m >= d->n_groups || !d->string.raw_ptr() )
|
||||
return null();
|
||||
//hx::Throw( HX_CSTRING("regexp_matched - no valid match"));
|
||||
|
||||
size_t* matches = d->get_matches();
|
||||
int start = matches[m*2];
|
||||
int len = matches[m*2+1] - start;
|
||||
if( start == -1 )
|
||||
return String();
|
||||
return d->string.substr(start, len);
|
||||
}
|
||||
|
||||
/**
|
||||
regexp_matched_pos : 'regexp -> n:int -> { pos => int, len => int }
|
||||
<doc>Return the [n]th matched block position by the regexp. If [n] is 0 then
|
||||
return the whole matched substring position</doc>
|
||||
**/
|
||||
Dynamic _hx_regexp_matched_pos(Dynamic handle, int m)
|
||||
{
|
||||
pcredata *d = PCRE(handle);
|
||||
if (m < 0 || m >= d->n_groups || !d->string.raw_ptr())
|
||||
return null();
|
||||
|
||||
size_t* matches = d->get_matches();
|
||||
int start = matches[m*2];
|
||||
int len = matches[m*2+1] - start;
|
||||
|
||||
return hx::Anon_obj::Create(2)
|
||||
->setFixed(0,HX_("len",d5,4b,52,00),len)
|
||||
->setFixed(1,HX_("pos",94,5d,55,00),start);
|
||||
}
|
||||
|
||||
/**
|
||||
regexp_matched_num : 'regexp -> int
|
||||
<doc>Return the total number of matched groups, or -1 if the regexp has not
|
||||
been matched yet</doc>
|
||||
**/
|
||||
int _hx_regexp_matched_num(Dynamic handle)
|
||||
{
|
||||
pcredata *d = PCRE(handle);
|
||||
|
||||
if( !d->string.raw_ptr() )
|
||||
return -1;
|
||||
else
|
||||
return d->n_groups;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
<xml>
|
||||
<compilerflag value="-DHAVE_CONFIG_H" />
|
||||
<compilerflag value="-DPCRE2_STATIC" />
|
||||
<compilerflag value="-DSUPPORT_UNICODE" />
|
||||
<compilerflag value="-I${PCRE_DIR}" />
|
||||
<compilerflag value="-std=c99" unless="MSVC_VER" />
|
||||
|
||||
<file name="${PCRE_DIR}/pcre2_auto_possess.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_chartables.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_compile.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_config.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_context.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_convert.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_dfa_match.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_error.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_extuni.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_find_bracket.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_jit_compile.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_maketables.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_match.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_match_data.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_newline.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_ord2utf.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_pattern_info.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_script_run.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_serialize.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_string_utils.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_study.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_substitute.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_substring.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_tables.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_ucd.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_valid_utf.c" />
|
||||
<file name="${PCRE_DIR}/pcre2_xclass.c" />
|
||||
</xml>
|
||||
25
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/sqlite/Build.xml
Normal file
25
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/sqlite/Build.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<set name="SQLITE_DIR" value="${HXCPP}/project/thirdparty/sqlite-3.40.1"/>
|
||||
|
||||
<files id="hxcpp_sqlite" dir="${this_dir}" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
|
||||
<compilerflag value="-I${SQLITE_DIR}"/>
|
||||
|
||||
<file name="Sqlite.cpp"/>
|
||||
|
||||
<depend name="${SQLITE_DIR}/sqlite3.h" />
|
||||
<file name="${SQLITE_DIR}/sqlite3.c"/>
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_sqlite"/>
|
||||
<lib name="-lpthread" if="linux" unless="static_link" />
|
||||
</target>
|
||||
|
||||
</xml>
|
||||
404
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/sqlite/Sqlite.cpp
Normal file
404
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/sqlite/Sqlite.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright (C)2005-2012 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <hxcpp.h>
|
||||
#include "sqlite3.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
// Put in anon-namespace to avoid conflicts if static-linked
|
||||
namespace {
|
||||
|
||||
|
||||
|
||||
struct result : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSqlite };
|
||||
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *r;
|
||||
int ncols;
|
||||
int count;
|
||||
String *names;
|
||||
int *bools;
|
||||
int done;
|
||||
int first;
|
||||
|
||||
void create(sqlite3 *inDb, sqlite3_stmt *inR, String sql)
|
||||
{
|
||||
_hx_set_finalizer(this, finalize);
|
||||
|
||||
db = inDb;
|
||||
r = inR;
|
||||
|
||||
ncols = sqlite3_column_count(r);
|
||||
names = (String *)malloc(sizeof(String)*ncols);
|
||||
bools = (int*)malloc(sizeof(int)*ncols);
|
||||
first = 1;
|
||||
done = 0;
|
||||
for(int i=0;i<ncols;i++)
|
||||
{
|
||||
names[i] = String::createPermanent(sqlite3_column_name(r,i),-1);
|
||||
for(int j=0;j<i;j++)
|
||||
if( names[j] == names[i] )
|
||||
hx::Throw(HX_CSTRING("Error, same field is two times in the request ") + sql);
|
||||
|
||||
const char *dtype = sqlite3_column_decltype(r,i);
|
||||
bools[i] = dtype?(strcmp(dtype,"BOOL") == 0):0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj) { ((result *)(obj.mPtr))->destroy(false); }
|
||||
void destroy(bool inThrowError)
|
||||
{
|
||||
if (bools)
|
||||
{
|
||||
free(bools);
|
||||
bools = 0;
|
||||
}
|
||||
if (names)
|
||||
{
|
||||
free(names);
|
||||
names = 0;
|
||||
}
|
||||
if (r)
|
||||
{
|
||||
first = 0;
|
||||
done = 1;
|
||||
if( ncols == 0 )
|
||||
count = sqlite3_changes(db);
|
||||
|
||||
bool err = sqlite3_finalize(r) != SQLITE_OK;
|
||||
db = 0;
|
||||
r = 0;
|
||||
|
||||
if( err && inThrowError)
|
||||
hx::Throw(HX_CSTRING("Could not finalize request"));
|
||||
}
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("Sqlite Result"); }
|
||||
|
||||
//static void finalize_result( result *r, int exc, bool throwError = true )
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>SQLite</h1>
|
||||
<p>
|
||||
Sqlite is a small embeddable SQL database that store all its data into
|
||||
a single file. See http://sqlite.org for more details.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
struct database : public hx::Object
|
||||
{
|
||||
sqlite3 *db;
|
||||
hx::ObjectPtr<result> last;
|
||||
|
||||
void create(sqlite3 *inDb)
|
||||
{
|
||||
db = inDb;
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
static void finalize(Dynamic obj) { ((database *)(obj.mPtr))->destroy(false); }
|
||||
void destroy(bool inThrowError)
|
||||
{
|
||||
if (db)
|
||||
{
|
||||
if (last.mPtr)
|
||||
{
|
||||
last->destroy(inThrowError);
|
||||
last = null();
|
||||
}
|
||||
|
||||
if( sqlite3_close(db) != SQLITE_OK )
|
||||
{
|
||||
if (inThrowError)
|
||||
hx::Throw(HX_CSTRING("Sqlite: could not close"));
|
||||
}
|
||||
db = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setResult(result *inResult)
|
||||
{
|
||||
if (last.mPtr)
|
||||
last->destroy(true);
|
||||
|
||||
last = inResult;
|
||||
HX_OBJ_WB_GET(this, last.mPtr);
|
||||
}
|
||||
|
||||
void __Mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(last); }
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(last); }
|
||||
#endif
|
||||
|
||||
String toString() { return HX_CSTRING("Sqlite Databse"); }
|
||||
};
|
||||
|
||||
static void sqlite_error( sqlite3 *db ) {
|
||||
hx::Throw( HX_CSTRING("Sqlite error : ") + String(sqlite3_errmsg(db)) );
|
||||
}
|
||||
|
||||
database *getDatabase(Dynamic handle)
|
||||
{
|
||||
database *db = dynamic_cast<database *>(handle.mPtr);
|
||||
if (!db || !db->db)
|
||||
hx::Throw( HX_CSTRING("Invalid sqlite database") );
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
result *getResult(Dynamic handle, bool inRequireStatement)
|
||||
{
|
||||
result *r = dynamic_cast<result *>(handle.mPtr);
|
||||
if (!r || (inRequireStatement && !r->r))
|
||||
hx::Throw( HX_CSTRING("Invalid sqlite result") );
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
} // End anon-namespace
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
connect : filename:string -> 'db
|
||||
<doc>Open or create the database stored in the specified file.</doc>
|
||||
**/
|
||||
Dynamic _hx_sqlite_connect(String filename)
|
||||
{
|
||||
int err;
|
||||
sqlite3 *sqlDb = 0;
|
||||
if( (err = sqlite3_open(filename.utf8_str(),&sqlDb)) != SQLITE_OK )
|
||||
sqlite_error(sqlDb);
|
||||
|
||||
database *db = new database();
|
||||
db->create(sqlDb);
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
close : 'db -> void
|
||||
<doc>Closes the database.</doc>
|
||||
**/
|
||||
void _hx_sqlite_close(Dynamic handle)
|
||||
{
|
||||
database *db = getDatabase(handle);
|
||||
db->destroy(true);
|
||||
}
|
||||
|
||||
/**
|
||||
last_insert_id : 'db -> int
|
||||
<doc>Returns the last inserted auto_increment id.</doc>
|
||||
**/
|
||||
int _hx_sqlite_last_insert_id(Dynamic handle)
|
||||
{
|
||||
database *db = getDatabase(handle);
|
||||
return sqlite3_last_insert_rowid(db->db);
|
||||
}
|
||||
|
||||
/**
|
||||
request : 'db -> sql:string -> 'result
|
||||
<doc>Executes the SQL request and returns its result</doc>
|
||||
**/
|
||||
Dynamic _hx_sqlite_request(Dynamic handle,String sql)
|
||||
{
|
||||
database *db = getDatabase(handle);
|
||||
|
||||
int byteLength = 0;
|
||||
const char * sqlStr = sql.utf8_str(0, true, &byteLength);
|
||||
sqlite3_stmt *statement = 0;
|
||||
const char *tl = 0;
|
||||
if( sqlite3_prepare(db->db,sqlStr,byteLength,&statement,&tl) != SQLITE_OK )
|
||||
{
|
||||
hx::Throw( HX_CSTRING("Sqlite error in ") + sql + HX_CSTRING(" : ") +
|
||||
String(sqlite3_errmsg(db->db) ) );
|
||||
}
|
||||
if( *tl )
|
||||
{
|
||||
sqlite3_finalize(statement);
|
||||
hx::Throw(HX_CSTRING("Cannot execute several SQL requests at the same time"));
|
||||
}
|
||||
|
||||
int i,j;
|
||||
|
||||
result *r = new result();
|
||||
r->create(db->db, statement,sql);
|
||||
|
||||
db->setResult(r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
result_get_length : 'result -> int
|
||||
<doc>Returns the number of rows in the result or the number of rows changed by the request.</doc>
|
||||
**/
|
||||
int _hx_sqlite_result_get_length(Dynamic handle)
|
||||
{
|
||||
result *r = getResult(handle,false);
|
||||
if( r->ncols != 0 )
|
||||
hx::Throw(HX_CSTRING("Getting change count from non-change request")); // ???
|
||||
return r->count;
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_nfields : 'result -> int
|
||||
<doc>Returns the number of fields in the result.</doc>
|
||||
**/
|
||||
int _hx_sqlite_result_get_nfields(Dynamic handle)
|
||||
{
|
||||
return getResult(handle,false)->ncols;
|
||||
}
|
||||
|
||||
/**
|
||||
result_next : 'result -> object?
|
||||
<doc>Returns the next row in the result or [null] if no more result.</doc>
|
||||
**/
|
||||
|
||||
Dynamic _hx_sqlite_result_next(Dynamic handle)
|
||||
{
|
||||
result *r = getResult(handle,false);
|
||||
if( r->done )
|
||||
return null();
|
||||
|
||||
switch( sqlite3_step(r->r) )
|
||||
{
|
||||
case SQLITE_ROW:
|
||||
{
|
||||
hx::Anon v = hx::Anon_obj::Create();
|
||||
r->first = 0;
|
||||
for(int i=0;i<r->ncols;i++)
|
||||
{
|
||||
Dynamic f;
|
||||
switch( sqlite3_column_type(r->r,i) )
|
||||
{
|
||||
case SQLITE_NULL:
|
||||
break;
|
||||
case SQLITE_INTEGER:
|
||||
if( r->bools[i] )
|
||||
f = bool(sqlite3_column_int(r->r,i));
|
||||
else
|
||||
f = int(sqlite3_column_int(r->r,i));
|
||||
break;
|
||||
case SQLITE_FLOAT:
|
||||
f = Float(sqlite3_column_double(r->r,i));
|
||||
break;
|
||||
case SQLITE_TEXT:
|
||||
f = String((char*)sqlite3_column_text(r->r,i));
|
||||
break;
|
||||
case SQLITE_BLOB:
|
||||
{
|
||||
int size = sqlite3_column_bytes(r->r,i);
|
||||
f = Array_obj<unsigned char>::fromData((const unsigned char *)sqlite3_column_blob(r->r,i),size);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
hx::Throw( HX_CSTRING("Unknown Sqlite type #") +
|
||||
String((int)sqlite3_column_type(r->r,i)));
|
||||
}
|
||||
}
|
||||
v->__SetField(r->names[i],f,hx::paccDynamic);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
case SQLITE_DONE:
|
||||
r->destroy(true);
|
||||
return null();
|
||||
case SQLITE_BUSY:
|
||||
hx::Throw(HX_CSTRING("Database is busy"));
|
||||
case SQLITE_ERROR:
|
||||
sqlite_error(r->db);
|
||||
default:
|
||||
hx::Throw(HX_CSTRING("Unkown sqlite result"));
|
||||
}
|
||||
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
static sqlite3_stmt *prepStatement(Dynamic handle,int n)
|
||||
{
|
||||
result *r = getResult(handle,true);
|
||||
if( n < 0 || n >= r->ncols )
|
||||
hx::Throw( HX_CSTRING("Sqlite: Invalid index") );
|
||||
|
||||
if( r->first )
|
||||
_hx_sqlite_result_next(handle);
|
||||
|
||||
if( r->done )
|
||||
hx::Throw( HX_CSTRING("Sqlite: no more results") );
|
||||
|
||||
return r->r;
|
||||
}
|
||||
|
||||
/**
|
||||
result_get : 'result -> n:int -> string
|
||||
<doc>Return the [n]th field of the current result row.</doc>
|
||||
**/
|
||||
|
||||
|
||||
String _hx_sqlite_result_get(Dynamic handle,int n)
|
||||
{
|
||||
sqlite3_stmt *r = prepStatement(handle,n);
|
||||
return String((char*)sqlite3_column_text(r,n));
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_int : 'result -> n:int -> int
|
||||
<doc>Return the [n]th field of the current result row as an integer.</doc>
|
||||
**/
|
||||
int _hx_sqlite_result_get_int(Dynamic handle,int n)
|
||||
{
|
||||
sqlite3_stmt *r = prepStatement(handle,n);
|
||||
return sqlite3_column_int(r,n);
|
||||
}
|
||||
|
||||
/**
|
||||
result_get_float : 'result -> n:int -> float
|
||||
<doc>Return the [n]th field of the current result row as a float.</doc>
|
||||
**/
|
||||
Float _hx_sqlite_result_get_float(Dynamic handle,int n)
|
||||
{
|
||||
sqlite3_stmt *r = prepStatement(handle,n);
|
||||
return sqlite3_column_double(r,n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
129
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/ssl/Build.xml
Normal file
129
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/ssl/Build.xml
Normal file
@ -0,0 +1,129 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<set name="MBEDTLS_DIR" value="${HXCPP}/project/thirdparty/mbedtls-2.28.2" />
|
||||
|
||||
<files id="hxcpp_ssl" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="true" />
|
||||
<compilerflag value="-I${MBEDTLS_DIR}/include"/>
|
||||
<compilerflag value="-I${this_dir}"/>
|
||||
|
||||
<file name="${this_dir}/SSL.cpp"/>
|
||||
|
||||
<compilerflag value="-DMBEDTLS_USER_CONFIG_FILE=<mbedtls_config.h>"/>
|
||||
|
||||
<file name="${MBEDTLS_DIR}/library/aes.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/aesni.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/arc4.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/aria.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/asn1parse.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/asn1write.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/base64.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/bignum.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/blowfish.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/camellia.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ccm.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/chacha20.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/chachapoly.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/cipher.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/cipher_wrap.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/constant_time.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/cmac.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ctr_drbg.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/des.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/dhm.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecdh.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecdsa.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecjpake.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecp.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ecp_curves.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/entropy.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/entropy_poll.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/error.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/gcm.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/havege.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/hkdf.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/hmac_drbg.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/md.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/md2.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/md4.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/md5.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/memory_buffer_alloc.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/mps_reader.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/mps_trace.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/nist_kw.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/oid.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/padlock.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pem.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pk.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pk_wrap.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkcs12.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkcs5.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkparse.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkwrite.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/platform.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/platform_util.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/poly1305.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_aead.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_cipher.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_client.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_driver_wrappers.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_ecp.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_hash.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_mac.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_rsa.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_se.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_slot_management.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_crypto_storage.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/psa_its_file.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ripemd160.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/rsa.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/rsa_internal.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/sha1.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/sha256.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/sha512.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/threading.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/timing.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/version.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/version_features.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/xtea.c"/>
|
||||
|
||||
<file name="${MBEDTLS_DIR}/library/certs.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/pkcs11.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509_create.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509_crl.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509_crt.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509_csr.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509write_crt.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/x509write_csr.c"/>
|
||||
|
||||
<file name="${MBEDTLS_DIR}/library/debug.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/net_sockets.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_cache.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_ciphersuites.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_cli.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_cookie.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_msg.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_srv.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_ticket.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_tls.c"/>
|
||||
<file name="${MBEDTLS_DIR}/library/ssl_tls13_keys.c"/>
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_ssl" />
|
||||
|
||||
<lib name="advapi32.lib" if="windows" unless="static_link" />
|
||||
<lib name="crypt32.lib" if="windows" unless="static_link" />
|
||||
<lib name="ws2_32.lib" if="windows" unless="static_link" />
|
||||
|
||||
<flag value="-framework" if="macos"/>
|
||||
<flag value="Security" if="macos"/>
|
||||
</target>
|
||||
|
||||
</xml>
|
||||
861
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/ssl/SSL.cpp
Normal file
861
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/ssl/SSL.cpp
Normal file
@ -0,0 +1,861 @@
|
||||
#include <string.h>
|
||||
|
||||
#ifndef KINC_CONSOLE
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wparentheses"
|
||||
#endif
|
||||
|
||||
#ifdef HX_WINDOWS
|
||||
# include <winsock2.h>
|
||||
# include <wincrypt.h>
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <strings.h>
|
||||
# include <errno.h>
|
||||
typedef int SOCKET;
|
||||
#endif
|
||||
|
||||
|
||||
#include <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
#if defined(NEKO_MAC) && !defined(IPHONE) && !defined(APPLETV)
|
||||
#include <Security/Security.h>
|
||||
#endif
|
||||
|
||||
typedef size_t socket_int;
|
||||
|
||||
#define SOCKET_ERROR (-1)
|
||||
#define NRETRYS 20
|
||||
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/pk.h"
|
||||
#include "mbedtls/oid.h"
|
||||
#include "mbedtls/x509_crt.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/debug.h"
|
||||
|
||||
#define val_ssl(o) ((sslctx*)o.mPtr)
|
||||
#define val_conf(o) ((sslconf*)o.mPtr)
|
||||
#define val_cert(o) ((sslcert*)o.mPtr)
|
||||
#define val_pkey(o) ((sslpkey*)o.mPtr)
|
||||
|
||||
struct SocketWrapper : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSocket };
|
||||
SOCKET socket;
|
||||
};
|
||||
|
||||
struct sslctx : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSsl };
|
||||
|
||||
mbedtls_ssl_context *s;
|
||||
|
||||
void create()
|
||||
{
|
||||
s = (mbedtls_ssl_context *)malloc(sizeof(mbedtls_ssl_context));
|
||||
mbedtls_ssl_init(s);
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if( s )
|
||||
{
|
||||
mbedtls_ssl_free( s );
|
||||
free(s);
|
||||
s = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((sslctx *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("sslctx"); }
|
||||
};
|
||||
|
||||
struct sslconf : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSslConf };
|
||||
|
||||
mbedtls_ssl_config *c;
|
||||
|
||||
void create()
|
||||
{
|
||||
c = (mbedtls_ssl_config *)malloc(sizeof(mbedtls_ssl_config));
|
||||
mbedtls_ssl_config_init(c);
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if( c )
|
||||
{
|
||||
mbedtls_ssl_config_free( c );
|
||||
free(c);
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((sslconf *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("sslconfig"); }
|
||||
};
|
||||
|
||||
struct sslcert : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSslCert };
|
||||
|
||||
mbedtls_x509_crt *c;
|
||||
bool head;
|
||||
|
||||
void create(const mbedtls_x509_crt *inC)
|
||||
{
|
||||
|
||||
if( inC ){
|
||||
c = (mbedtls_x509_crt *)inC;
|
||||
head = false;
|
||||
}else{
|
||||
c = (mbedtls_x509_crt *)malloc(sizeof(mbedtls_x509_crt));
|
||||
mbedtls_x509_crt_init(c);
|
||||
head = true;
|
||||
}
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if( c && head )
|
||||
{
|
||||
mbedtls_x509_crt_free( c );
|
||||
free(c);
|
||||
head = 0;
|
||||
}
|
||||
c = 0;
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((sslcert *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("sslcert"); }
|
||||
};
|
||||
|
||||
struct sslpkey : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSslKey };
|
||||
|
||||
mbedtls_pk_context *k;
|
||||
|
||||
void create()
|
||||
{
|
||||
k = (mbedtls_pk_context *)malloc(sizeof(mbedtls_pk_context));
|
||||
mbedtls_pk_init(k);
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if( k )
|
||||
{
|
||||
mbedtls_pk_free(k);
|
||||
free(k);
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((sslpkey *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("sslpkey"); }
|
||||
};
|
||||
|
||||
static mbedtls_entropy_context entropy;
|
||||
static mbedtls_ctr_drbg_context ctr_drbg;
|
||||
|
||||
static bool is_ssl_blocking( int r ) {
|
||||
return r == MBEDTLS_ERR_SSL_WANT_READ || r == MBEDTLS_ERR_SSL_WANT_WRITE;
|
||||
}
|
||||
|
||||
static bool is_block_error() {
|
||||
#ifdef NEKO_WINDOWS
|
||||
int err = WSAGetLastError();
|
||||
if( err == WSAEWOULDBLOCK || err == WSAEALREADY || err == WSAETIMEDOUT )
|
||||
#else
|
||||
if( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EALREADY )
|
||||
#endif
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ssl_error( int ret ){
|
||||
char buf[256];
|
||||
mbedtls_strerror(ret, buf, sizeof(buf));
|
||||
hx::Throw( String(buf) );
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_new( Dynamic hconf ) {
|
||||
int ret;
|
||||
sslctx *ssl = new sslctx();
|
||||
ssl->create();
|
||||
sslconf *conf = val_conf(hconf);
|
||||
if( ret = mbedtls_ssl_setup(ssl->s, conf->c) != 0 ){
|
||||
ssl->destroy();
|
||||
ssl_error(ret);
|
||||
}
|
||||
return ssl;
|
||||
}
|
||||
|
||||
void _hx_ssl_close( Dynamic hssl ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
ssl->destroy();
|
||||
}
|
||||
|
||||
void _hx_ssl_debug_set (int i) {
|
||||
mbedtls_debug_set_threshold(i);
|
||||
}
|
||||
|
||||
void _hx_ssl_handshake( Dynamic hssl ) {
|
||||
int r;
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
POSIX_LABEL(handshake_again);
|
||||
r = mbedtls_ssl_handshake( ssl->s );
|
||||
if ( is_ssl_blocking(r) ) {
|
||||
HANDLE_EINTR(handshake_again);
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( r == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(handshake_again);
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}else if( r != 0 )
|
||||
ssl_error(r);
|
||||
}
|
||||
|
||||
int net_read( void *fd, unsigned char *buf, size_t len ){
|
||||
hx::EnterGCFreeZone();
|
||||
int r = recv((SOCKET)(socket_int)fd, (char *)buf, len, 0);
|
||||
if( r == SOCKET_ERROR && is_block_error() )
|
||||
r = MBEDTLS_ERR_SSL_WANT_READ;
|
||||
hx::ExitGCFreeZone();
|
||||
return r;
|
||||
}
|
||||
|
||||
int net_write( void *fd, const unsigned char *buf, size_t len ){
|
||||
hx::EnterGCFreeZone();
|
||||
int r = send((SOCKET)(socket_int)fd, (char *)buf, len, 0);
|
||||
if( r == SOCKET_ERROR && is_block_error() )
|
||||
r = MBEDTLS_ERR_SSL_WANT_WRITE;
|
||||
hx::ExitGCFreeZone();
|
||||
return r;
|
||||
}
|
||||
|
||||
void _hx_ssl_set_socket( Dynamic hssl, Dynamic hsocket ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
SocketWrapper *socket = (SocketWrapper *)hsocket.mPtr;
|
||||
mbedtls_ssl_set_bio( ssl->s, (void *)(socket_int)socket->socket, net_write, net_read, NULL );
|
||||
}
|
||||
|
||||
void _hx_ssl_set_hostname( Dynamic hssl, String hostname ){
|
||||
int ret;
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
hx::strbuf buf;
|
||||
if( ret = mbedtls_ssl_set_hostname(ssl->s, hostname.utf8_str(&buf)) != 0 )
|
||||
ssl_error(ret);
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_get_peer_certificate( Dynamic hssl ){
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(ssl->s);
|
||||
if( crt == NULL )
|
||||
return null();
|
||||
sslcert *cert = new sslcert();
|
||||
cert->create( crt );
|
||||
return cert;
|
||||
}
|
||||
|
||||
bool _hx_ssl_get_verify_result( Dynamic hssl ){
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
int r = mbedtls_ssl_get_verify_result( ssl->s );
|
||||
if( r == 0 )
|
||||
return true;
|
||||
else if( r != -1 )
|
||||
return false;
|
||||
hx::Throw( HX_CSTRING("not available") );
|
||||
return false;
|
||||
}
|
||||
|
||||
void _hx_ssl_send_char( Dynamic hssl, int c ) {
|
||||
if( c < 0 || c > 255 )
|
||||
hx::Throw( HX_CSTRING("invalid char") );
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
const unsigned char cc = c;
|
||||
mbedtls_ssl_write( ssl->s, &cc, 1 );
|
||||
}
|
||||
|
||||
int _hx_ssl_send( Dynamic hssl, Array<unsigned char> buf, int p, int l ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
int dlen = buf->length;
|
||||
if( p < 0 || l < 0 || p > dlen || p + l > dlen )
|
||||
hx::Throw( HX_CSTRING("ssl_send") );
|
||||
POSIX_LABEL(send_again);
|
||||
const unsigned char *base = (const unsigned char *)&buf[0];
|
||||
dlen = mbedtls_ssl_write( ssl->s, base + p, l );
|
||||
if ( is_ssl_blocking(dlen) ) {
|
||||
HANDLE_EINTR(send_again);
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( dlen == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(send_again);
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}
|
||||
return dlen;
|
||||
}
|
||||
|
||||
void _hx_ssl_write( Dynamic hssl, Array<unsigned char> buf ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
int len = buf->length;
|
||||
unsigned char *cdata = &buf[0];
|
||||
while( len > 0 ) {
|
||||
POSIX_LABEL( write_again );
|
||||
int slen = mbedtls_ssl_write( ssl->s, cdata, len );
|
||||
if ( is_ssl_blocking(slen) ) {
|
||||
HANDLE_EINTR( write_again );
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( slen == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR( write_again );
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}
|
||||
cdata += slen;
|
||||
len -= slen;
|
||||
}
|
||||
}
|
||||
|
||||
int _hx_ssl_recv_char( Dynamic hssl ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
unsigned char cc;
|
||||
int r = mbedtls_ssl_read( ssl->s, &cc, 1 );
|
||||
if( r <= 0 )
|
||||
hx::Throw( HX_CSTRING("ssl_recv_char") );
|
||||
return (int)cc;
|
||||
}
|
||||
|
||||
int _hx_ssl_recv( Dynamic hssl, Array<unsigned char> buf, int p, int l ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
int dlen = buf->length;
|
||||
if( p < 0 || l < 0 || p > dlen || p + l > dlen )
|
||||
hx::Throw( HX_CSTRING("ssl_recv") );
|
||||
|
||||
unsigned char *base = &buf[0];
|
||||
POSIX_LABEL(recv_again);
|
||||
dlen = mbedtls_ssl_read( ssl->s, base + p, l );
|
||||
if ( is_ssl_blocking(dlen) ) {
|
||||
HANDLE_EINTR(recv_again);
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( dlen == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(recv_again);
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}
|
||||
if( dlen < 0 ) {
|
||||
if( dlen == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ) {
|
||||
mbedtls_ssl_close_notify( ssl->s );
|
||||
return 0;
|
||||
}
|
||||
hx::Throw( HX_CSTRING("ssl_recv") );
|
||||
}
|
||||
return dlen;
|
||||
}
|
||||
|
||||
Array<unsigned char> _hx_ssl_read( Dynamic hssl ) {
|
||||
sslctx *ssl = val_ssl(hssl);
|
||||
Array<unsigned char> result = Array_obj<unsigned char>::__new();
|
||||
unsigned char buf[256];
|
||||
|
||||
while( true ) {
|
||||
POSIX_LABEL(read_again);
|
||||
int len = mbedtls_ssl_read( ssl->s, buf, 256 );
|
||||
if ( is_ssl_blocking(len) ) {
|
||||
HANDLE_EINTR(read_again);
|
||||
hx::Throw(HX_CSTRING("Blocking"));
|
||||
}else if( len == SOCKET_ERROR ) {
|
||||
HANDLE_EINTR(read_again);
|
||||
hx::Throw(HX_CSTRING("ssl network error"));
|
||||
}
|
||||
if( len == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ) {
|
||||
mbedtls_ssl_close_notify( ssl->s );
|
||||
len = 0;
|
||||
}
|
||||
if( len == 0 )
|
||||
break;
|
||||
result->memcpy(result->length, buf, len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_conf_new( bool server ) {
|
||||
int ret;
|
||||
sslconf *conf = new sslconf();
|
||||
conf->create();
|
||||
if( ret = mbedtls_ssl_config_defaults( conf->c,
|
||||
server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM, 0 ) != 0 ){
|
||||
conf->destroy();
|
||||
ssl_error( ret );
|
||||
}
|
||||
mbedtls_ssl_conf_rng( conf->c, mbedtls_ctr_drbg_random, &ctr_drbg );
|
||||
return conf;
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_close( Dynamic hconf ) {
|
||||
sslconf *conf = val_conf(hconf);
|
||||
conf->destroy();
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_set_ca( Dynamic hconf, Dynamic hcert ) {
|
||||
sslconf *conf = val_conf(hconf);
|
||||
if( hconf.mPtr ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
mbedtls_ssl_conf_ca_chain( conf->c, cert->c, NULL );
|
||||
}else{
|
||||
mbedtls_ssl_conf_ca_chain( conf->c, NULL, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_set_verify( Dynamic hconf, int mode ) {
|
||||
sslconf *conf = val_conf(hconf);
|
||||
if( mode == 2 )
|
||||
mbedtls_ssl_conf_authmode(conf->c, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||
else if( mode == 1 )
|
||||
mbedtls_ssl_conf_authmode(conf->c, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
else
|
||||
mbedtls_ssl_conf_authmode(conf->c, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_set_cert( Dynamic hconf, Dynamic hcert, Dynamic hpkey ) {
|
||||
int r;
|
||||
sslconf *conf = val_conf(hconf);
|
||||
sslcert *cert = val_cert(hcert);
|
||||
sslpkey *pkey = val_pkey(hpkey);
|
||||
|
||||
if( r = mbedtls_ssl_conf_own_cert(conf->c, cert->c, pkey->k) != 0 )
|
||||
ssl_error(r);
|
||||
}
|
||||
|
||||
static int sni_callback( void *arg, mbedtls_ssl_context *ctx, const unsigned char *name, size_t len ){
|
||||
if( name && arg ){
|
||||
Dynamic cb = new Dynamic();
|
||||
cb.mPtr = (hx::Object*)arg;
|
||||
const char *n = (const char *)name;
|
||||
Dynamic ret = cb->__run( String(n,strlen(n)) );
|
||||
if( ret != null() ){
|
||||
// TODO authmode and ca
|
||||
Dynamic hcert = ret->__Field(HX_CSTRING("cert"), hx::paccDynamic);
|
||||
Dynamic hpkey = ret->__Field(HX_CSTRING("key"), hx::paccDynamic);
|
||||
sslcert *cert = val_cert(hcert);
|
||||
sslpkey *pk = val_pkey(hpkey);
|
||||
|
||||
return mbedtls_ssl_set_hs_own_cert( ctx, cert->c, pk->k );
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void _hx_ssl_conf_set_servername_callback( Dynamic hconf, Dynamic cb ){
|
||||
sslconf *conf = val_conf(hconf);
|
||||
mbedtls_ssl_conf_sni( conf->c, sni_callback, (void *)cb.mPtr );
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_load_defaults(){
|
||||
#if defined(NEKO_WINDOWS) && !defined(KINC_WINDOWSAPP)
|
||||
HCERTSTORE store;
|
||||
PCCERT_CONTEXT cert;
|
||||
sslcert *chain = NULL;
|
||||
if( store = CertOpenSystemStoreA(0, (LPCSTR)"Root") ){
|
||||
cert = NULL;
|
||||
while( cert = CertEnumCertificatesInStore(store, cert) ){
|
||||
if( chain == NULL ){
|
||||
chain = new sslcert();
|
||||
chain->create( NULL );
|
||||
}
|
||||
mbedtls_x509_crt_parse_der( chain->c, (unsigned char *)cert->pbCertEncoded, cert->cbCertEncoded );
|
||||
}
|
||||
CertCloseStore(store, 0);
|
||||
}
|
||||
if( chain != NULL )
|
||||
return chain;
|
||||
#elif defined(NEKO_MAC) && !defined(IPHONE) && !defined(APPLETV)
|
||||
CFMutableDictionaryRef search;
|
||||
CFArrayRef result;
|
||||
SecKeychainRef keychain;
|
||||
SecCertificateRef item;
|
||||
CFDataRef dat;
|
||||
sslcert *chain = NULL;
|
||||
|
||||
// Load keychain
|
||||
if( SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain",&keychain) != errSecSuccess )
|
||||
return null();
|
||||
|
||||
// Search for certificates
|
||||
search = CFDictionaryCreateMutable( NULL, 0, NULL, NULL );
|
||||
CFDictionarySetValue( search, kSecClass, kSecClassCertificate );
|
||||
CFDictionarySetValue( search, kSecMatchLimit, kSecMatchLimitAll );
|
||||
CFDictionarySetValue( search, kSecReturnRef, kCFBooleanTrue );
|
||||
CFDictionarySetValue( search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL) );
|
||||
if( SecItemCopyMatching( search, (CFTypeRef *)&result ) == errSecSuccess ){
|
||||
CFIndex n = CFArrayGetCount( result );
|
||||
for( CFIndex i = 0; i < n; i++ ){
|
||||
item = (SecCertificateRef)CFArrayGetValueAtIndex( result, i );
|
||||
|
||||
// Get certificate in DER format
|
||||
dat = SecCertificateCopyData( item );
|
||||
if( dat ){
|
||||
if( chain == NULL ){
|
||||
chain = new sslcert();
|
||||
chain->create( NULL );
|
||||
}
|
||||
mbedtls_x509_crt_parse_der( chain->c, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat) );
|
||||
CFRelease( dat );
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(keychain);
|
||||
if( chain != NULL )
|
||||
return chain;
|
||||
#endif
|
||||
return null();
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_load_file( String file ){
|
||||
int r;
|
||||
sslcert *cert = new sslcert();
|
||||
cert->create( NULL );
|
||||
hx::strbuf buf;
|
||||
if( r = mbedtls_x509_crt_parse_file(cert->c, file.utf8_str(&buf)) != 0 ){
|
||||
cert->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_load_path( String path ){
|
||||
int r;
|
||||
sslcert *cert = new sslcert();
|
||||
cert->create( NULL );
|
||||
hx::strbuf buf;
|
||||
if( r = mbedtls_x509_crt_parse_path(cert->c, path.utf8_str(&buf)) != 0 ){
|
||||
cert->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
static String asn1_buf_to_string( mbedtls_asn1_buf *dat ){
|
||||
unsigned int i, c;
|
||||
HX_CHAR *result = hx::NewString( dat->len );
|
||||
for( i = 0; i < dat->len; i++ ) {
|
||||
c = dat->p[i];
|
||||
if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
|
||||
result[i] = '?';
|
||||
else
|
||||
result[i] = c;
|
||||
}
|
||||
result[i] = '\0';
|
||||
return String(result,dat->len);
|
||||
}
|
||||
|
||||
String _hx_ssl_cert_get_subject( Dynamic hcert, String objname ){
|
||||
mbedtls_x509_name *obj;
|
||||
int r;
|
||||
const char *oname;
|
||||
sslcert *cert = val_cert(hcert);
|
||||
obj = &cert->c->subject;
|
||||
if( obj == NULL )
|
||||
hx::Throw( HX_CSTRING("cert_get_subject") );
|
||||
hx::strbuf buf;
|
||||
while( obj != NULL ){
|
||||
r = mbedtls_oid_get_attr_short_name( &obj->oid, &oname );
|
||||
if( r == 0 && strcmp( oname, objname.utf8_str(&buf) ) == 0 )
|
||||
return asn1_buf_to_string( &obj->val );
|
||||
obj = obj->next;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
String _hx_ssl_cert_get_issuer( Dynamic hcert, String objname ){
|
||||
mbedtls_x509_name *obj;
|
||||
int r;
|
||||
const char *oname;
|
||||
sslcert *cert = val_cert(hcert);
|
||||
obj = &cert->c->issuer;
|
||||
if( obj == NULL )
|
||||
hx::Throw( HX_CSTRING("cert_get_issuer") );
|
||||
hx::strbuf buf;
|
||||
while( obj != NULL ){
|
||||
r = mbedtls_oid_get_attr_short_name( &obj->oid, &oname );
|
||||
if( r == 0 && strcmp( oname, objname.utf8_str(&buf) ) == 0 )
|
||||
return asn1_buf_to_string( &obj->val );
|
||||
obj = obj->next;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
Array<String> _hx_ssl_cert_get_altnames( Dynamic hcert ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
mbedtls_asn1_sequence *cur;
|
||||
Array<String> result(0,1);
|
||||
if( cert->c->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ){
|
||||
cur = &cert->c->subject_alt_names;
|
||||
|
||||
while( cur != NULL ){
|
||||
result.Add( asn1_buf_to_string(&cur->buf) );
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Array<int> x509_time_to_array( mbedtls_x509_time *t ){
|
||||
if( !t )
|
||||
hx::Throw( HX_CSTRING("x509_time_to_array") );
|
||||
Array<int> result(6,6);
|
||||
result[0] = t->year;
|
||||
result[1] = t->mon;
|
||||
result[2] = t->day;
|
||||
result[3] = t->hour;
|
||||
result[4] = t->min;
|
||||
result[5] = t->sec;
|
||||
return result;
|
||||
}
|
||||
|
||||
Array<int> _hx_ssl_cert_get_notbefore( Dynamic hcert ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
if( !cert->c )
|
||||
hx::Throw( HX_CSTRING("cert_get_notbefore") );
|
||||
return x509_time_to_array( &cert->c->valid_from );
|
||||
}
|
||||
|
||||
Array<int> _hx_ssl_cert_get_notafter( Dynamic hcert ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
if( !cert->c )
|
||||
hx::Throw( HX_CSTRING("cert_get_notafter") );
|
||||
return x509_time_to_array( &cert->c->valid_to );
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_get_next( Dynamic hcert ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
mbedtls_x509_crt *crt = cert->c->next;
|
||||
if( crt == NULL )
|
||||
return null();
|
||||
cert = new sslcert();
|
||||
cert->create(crt);
|
||||
return cert;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_add_pem( Dynamic hcert, String data ){
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (data.isUTF16Encoded())
|
||||
hx::Throw( HX_CSTRING("Invalid data encoding") );
|
||||
#endif
|
||||
sslcert *cert = val_cert(hcert);
|
||||
int r;
|
||||
bool isnew = 0;
|
||||
if( !cert ){
|
||||
cert = new sslcert();
|
||||
cert->create( NULL );
|
||||
isnew = 1;
|
||||
}
|
||||
unsigned char *b = (unsigned char *)malloc((data.length+1) * sizeof(unsigned char));
|
||||
memcpy(b,data.raw_ptr(),data.length);
|
||||
b[data.length] = '\0';
|
||||
r = mbedtls_x509_crt_parse( cert->c, b, data.length+1 );
|
||||
free(b);
|
||||
if( r < 0 ){
|
||||
if( isnew )
|
||||
cert->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_cert_add_der( Dynamic hcert, Array<unsigned char> buf ){
|
||||
sslcert *cert = val_cert(hcert);
|
||||
int r;
|
||||
bool isnew = 0;
|
||||
if( !cert ){
|
||||
cert = new sslcert();
|
||||
cert->create( NULL );
|
||||
isnew = 1;
|
||||
}
|
||||
if( (r = mbedtls_x509_crt_parse_der( cert->c, &buf[0], buf->length)) < 0 ){
|
||||
if( isnew )
|
||||
cert->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_key_from_der( Array<unsigned char> buf, bool pub ){
|
||||
sslpkey *pk = new sslpkey();
|
||||
pk->create();
|
||||
int r;
|
||||
if( pub )
|
||||
r = mbedtls_pk_parse_public_key( pk->k, &buf[0], buf->length );
|
||||
else
|
||||
r = mbedtls_pk_parse_key( pk->k, &buf[0], buf->length, NULL, 0 );
|
||||
if( r != 0 ){
|
||||
pk->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return pk;
|
||||
}
|
||||
|
||||
Dynamic _hx_ssl_key_from_pem( String data, bool pub, String pass ){
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (data.isUTF16Encoded())
|
||||
hx::Throw( HX_CSTRING("Invalid data encoding") );
|
||||
#endif
|
||||
sslpkey *pk = new sslpkey();
|
||||
pk->create();
|
||||
int r;
|
||||
unsigned char *b = (unsigned char *)malloc((data.length+1) * sizeof(unsigned char));
|
||||
memcpy(b,data.raw_ptr(),data.length);
|
||||
b[data.length] = '\0';
|
||||
if( pub ){
|
||||
r = mbedtls_pk_parse_public_key( pk->k, b, data.length+1 );
|
||||
}else if( pass == null() ){
|
||||
r = mbedtls_pk_parse_key( pk->k, b, data.length+1, NULL, 0 );
|
||||
}else{
|
||||
Array<unsigned char> pbytes(0,0);
|
||||
__hxcpp_bytes_of_string(pbytes,pass);
|
||||
r = mbedtls_pk_parse_key( pk->k, b, data.length+1, (const unsigned char *)pbytes->GetBase(), pbytes->length );
|
||||
}
|
||||
free(b);
|
||||
if( r != 0 ){
|
||||
pk->destroy();
|
||||
ssl_error(r);
|
||||
}
|
||||
return pk;
|
||||
}
|
||||
|
||||
Array<unsigned char> _hx_ssl_dgst_make( Array<unsigned char> buf, String alg ){
|
||||
hx::strbuf ubuf;
|
||||
const mbedtls_md_info_t *md = mbedtls_md_info_from_string(alg.utf8_str(&ubuf));
|
||||
if( md == NULL )
|
||||
hx::Throw( HX_CSTRING("Invalid hash algorithm") );
|
||||
|
||||
int size = mbedtls_md_get_size(md);
|
||||
Array<unsigned char> out = Array_obj<int>::__new(size,size);
|
||||
int r = -1;
|
||||
if( r = mbedtls_md( md, &buf[0], buf->length, &out[0] ) != 0 )
|
||||
ssl_error(r);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Array<unsigned char> _hx_ssl_dgst_sign( Array<unsigned char> buf, Dynamic hpkey, String alg ){
|
||||
int r = -1;
|
||||
size_t olen = 0;
|
||||
unsigned char hash[32];
|
||||
sslpkey *pk = val_pkey(hpkey);
|
||||
|
||||
hx::strbuf ubuf;
|
||||
const mbedtls_md_info_t *md = mbedtls_md_info_from_string( alg.utf8_str(&ubuf) );
|
||||
if( md == NULL )
|
||||
hx::Throw( HX_CSTRING("Invalid hash algorithm") );
|
||||
|
||||
if( r = mbedtls_md( md, &buf[0], buf->length, hash ) != 0 )
|
||||
ssl_error(r);
|
||||
|
||||
Array<unsigned char> result = Array_obj<unsigned char>::__new(MBEDTLS_MPI_MAX_SIZE,MBEDTLS_MPI_MAX_SIZE);
|
||||
if( r = mbedtls_pk_sign( pk->k, mbedtls_md_get_type(md), hash, 0, &result[0], &olen, mbedtls_ctr_drbg_random, &ctr_drbg ) != 0 )
|
||||
ssl_error(r);
|
||||
|
||||
result[olen] = 0;
|
||||
result->__SetSize(olen);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool _hx_ssl_dgst_verify( Array<unsigned char> buf, Array<unsigned char> sign, Dynamic hpkey, String alg ){
|
||||
const mbedtls_md_info_t *md;
|
||||
int r = -1;
|
||||
unsigned char hash[32];
|
||||
sslpkey *pk = val_pkey(hpkey);
|
||||
|
||||
hx::strbuf ubuf;
|
||||
md = mbedtls_md_info_from_string( alg.utf8_str(&ubuf) );
|
||||
if( md == NULL )
|
||||
hx::Throw( HX_CSTRING("Invalid hash algorithm") );
|
||||
|
||||
if( r = mbedtls_md( md, &buf[0], buf->length, hash ) != 0 )
|
||||
ssl_error(r);
|
||||
|
||||
if( r = mbedtls_pk_verify( pk->k, mbedtls_md_get_type(md), hash, 0, &sign[0], sign->length ) != 0 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if (_MSC_VER || defined(WIN32))
|
||||
|
||||
static void threading_mutex_init_alt( mbedtls_threading_mutex_t *mutex ){
|
||||
if( mutex == NULL )
|
||||
return;
|
||||
InitializeCriticalSection( &mutex->cs );
|
||||
mutex->is_valid = 1;
|
||||
}
|
||||
|
||||
static void threading_mutex_free_alt( mbedtls_threading_mutex_t *mutex ){
|
||||
if( mutex == NULL || !mutex->is_valid )
|
||||
return;
|
||||
DeleteCriticalSection( &mutex->cs );
|
||||
mutex->is_valid = 0;
|
||||
}
|
||||
|
||||
static int threading_mutex_lock_alt( mbedtls_threading_mutex_t *mutex ){
|
||||
if( mutex == NULL || !mutex->is_valid )
|
||||
return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA );
|
||||
|
||||
EnterCriticalSection( &mutex->cs );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int threading_mutex_unlock_alt( mbedtls_threading_mutex_t *mutex ){
|
||||
if( mutex == NULL || !mutex->is_valid )
|
||||
return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA );
|
||||
|
||||
LeaveCriticalSection( &mutex->cs );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool _hx_ssl_inited = false;
|
||||
void _hx_ssl_init() {
|
||||
if (_hx_ssl_inited) return;
|
||||
_hx_ssl_inited = true;
|
||||
|
||||
#if (_MSC_VER || defined(WIN32))
|
||||
mbedtls_threading_set_alt( threading_mutex_init_alt, threading_mutex_free_alt,
|
||||
threading_mutex_lock_alt, threading_mutex_unlock_alt );
|
||||
#endif
|
||||
|
||||
// Init RNG
|
||||
mbedtls_entropy_init( &entropy );
|
||||
mbedtls_ctr_drbg_init( &ctr_drbg );
|
||||
mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0 );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,10 @@
|
||||
#ifdef HX_WINDOWS
|
||||
#define MBEDTLS_THREADING_ALT
|
||||
#endif
|
||||
#ifndef HX_WINDOWS
|
||||
#define MBEDTLS_THREADING_PTHREAD
|
||||
#endif
|
||||
|
||||
#undef MBEDTLS_NET_C
|
||||
|
||||
#define MBEDTLS_THREADING_C
|
||||
@ -0,0 +1,6 @@
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
CRITICAL_SECTION cs;
|
||||
char is_valid;
|
||||
} mbedtls_threading_mutex_t;
|
||||
26
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Build.xml
Normal file
26
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Build.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<files id="hxcpp_std" dir="${this_dir}" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="1" asLibrary="true" />
|
||||
|
||||
<file name="File.cpp"/>
|
||||
<file name="Sys.cpp"/>
|
||||
<file name="Process.cpp"/>
|
||||
<file name="Random.cpp"/>
|
||||
<file name="Socket.cpp" />
|
||||
|
||||
</files>
|
||||
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_std"/>
|
||||
<lib name="ws2_32.lib" if="windows" unless="static_link" />
|
||||
<lib name="-lsocket" if="blackberry" unless="static_link" />
|
||||
</target>
|
||||
|
||||
|
||||
</xml>
|
||||
404
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/File.cpp
Normal file
404
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/File.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
#include <hxcpp.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include <hx/OS.h>
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>File</h1>
|
||||
<p>
|
||||
The file api can be used for different kind of file I/O.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct fio : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdFio };
|
||||
|
||||
String name;
|
||||
FILE *io;
|
||||
bool closeIo;
|
||||
|
||||
void create(FILE *inFile, String inName, bool inClose)
|
||||
{
|
||||
name = inName;
|
||||
HX_OBJ_WB_GET(this,name.raw_ref());
|
||||
io = inFile;
|
||||
closeIo = inClose;
|
||||
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy(bool inForceClose = false)
|
||||
{
|
||||
if (io && (inForceClose || closeIo))
|
||||
fclose(io);
|
||||
io = 0;
|
||||
name = String();
|
||||
}
|
||||
|
||||
void __Mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(name); }
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(name); }
|
||||
#endif
|
||||
|
||||
static void finalize(Dynamic inObj)
|
||||
{
|
||||
((fio *)(inObj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("fio:") + name; }
|
||||
|
||||
};
|
||||
|
||||
fio *getFio(Dynamic handle, bool inRequireFile=true)
|
||||
{
|
||||
fio *result = dynamic_cast<fio *>(handle.mPtr);
|
||||
if (!result || (!result->io && inRequireFile))
|
||||
hx::Throw( HX_CSTRING("Bad file handle") );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void file_error(const char *msg, String inName)
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
Array<String> err = Array_obj<String>::__new(2,2);
|
||||
err[0] = String(msg);
|
||||
err[1] = inName;
|
||||
hx::Throw(err);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
file_open : f:string -> r:string -> 'file
|
||||
<doc>
|
||||
Call the C function [fopen] with the file path and access rights.
|
||||
Return the opened file or throw an exception if the file couldn't be open.
|
||||
</doc>
|
||||
**/
|
||||
Dynamic _hx_std_file_open( String fname, String r )
|
||||
{
|
||||
FILE *file = 0;
|
||||
|
||||
hx::strbuf buf0;
|
||||
hx::strbuf buf1;
|
||||
#ifdef NEKO_WINDOWS
|
||||
hx::EnterGCFreeZone();
|
||||
file = _wfopen(fname.wchar_str(&buf0),r.wchar_str(&buf1));
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
file = fopen(fname.utf8_str(&buf0),r.utf8_str(&buf1));
|
||||
#endif
|
||||
if (!file)
|
||||
file_error("file_open",fname);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
fio *f = new fio;
|
||||
f->create(file,fname,true);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
file_close : 'file -> void
|
||||
<doc>Close an file. Any other operations on this file will fail</doc>
|
||||
**/
|
||||
void _hx_std_file_close( Dynamic handle )
|
||||
{
|
||||
fio *fio = getFio(handle);
|
||||
fio->destroy(true);
|
||||
}
|
||||
|
||||
/**
|
||||
file_name : 'file -> string
|
||||
<doc>Return the name of the file which was opened</doc>
|
||||
**/
|
||||
String hx_std_file_name( Dynamic handle )
|
||||
{
|
||||
fio *fio = getFio(handle);
|
||||
return fio->name;
|
||||
}
|
||||
|
||||
/**
|
||||
file_write : 'file -> s:string -> p:int -> l:int -> int
|
||||
<doc>
|
||||
Write up to [l] chars of string [s] starting at position [p].
|
||||
Returns the number of chars written which is >= 0.
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_file_write( Dynamic handle, Array<unsigned char> s, int p, int n )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
|
||||
int buflen = s->length;
|
||||
int len = n;
|
||||
if( p < 0 || len < 0 || p > buflen || p + len > buflen )
|
||||
return 0;
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
while( len > 0 )
|
||||
{
|
||||
POSIX_LABEL(file_write_again);
|
||||
int d = (int)fwrite(&s[p],1,len,f->io);
|
||||
if( d <= 0 )
|
||||
{
|
||||
HANDLE_FINTR(f->io,file_write_again);
|
||||
file_error("file_write",f->name);
|
||||
}
|
||||
p += d;
|
||||
len -= d;
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
file_read : 'file -> s:string -> p:int -> l:int -> int
|
||||
<doc>
|
||||
Read up to [l] chars into the string [s] starting at position [p].
|
||||
Returns the number of chars readed which is > 0 (or 0 if l == 0).
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_file_read( Dynamic handle, Array<unsigned char> buf, int p, int n )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
|
||||
int buf_len = buf->length;
|
||||
int len = n;
|
||||
if( p < 0 || len < 0 || p > buf_len || p + len > buf_len )
|
||||
return 0;
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
// Attempt to increase the chances of pinning on the stack...
|
||||
unsigned char *bufPtr = &buf[0];
|
||||
while( len > 0 )
|
||||
{
|
||||
POSIX_LABEL(file_read_again);
|
||||
int d = (int)fread(bufPtr + p,1,len,f->io);
|
||||
if( d <= 0 )
|
||||
{
|
||||
int size = n - len;
|
||||
HANDLE_FINTR(f->io,file_read_again);
|
||||
if( size == 0 )
|
||||
file_error("file_read",f->name);
|
||||
hx::ExitGCFreeZone();
|
||||
return size;
|
||||
}
|
||||
p += d;
|
||||
len -= d;
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
file_write_char : 'file -> c:int -> void
|
||||
<doc>Write the char [c]. Error if [c] outside of the range 0..255</doc>
|
||||
**/
|
||||
void _hx_std_file_write_char( Dynamic handle, int c )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
if( c < 0 || c > 255 )
|
||||
return;
|
||||
char cc = (char)c;
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
POSIX_LABEL(write_char_again);
|
||||
if( fwrite(&cc,1,1,f->io) != 1 )
|
||||
{
|
||||
HANDLE_FINTR(f->io,write_char_again);
|
||||
file_error("file_write_char",f->name);
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
file_read_char : 'file -> int
|
||||
<doc>Read a char from the file. Exception on error</doc>
|
||||
**/
|
||||
int _hx_std_file_read_char( Dynamic handle )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
|
||||
unsigned char cc = 0;
|
||||
hx::EnterGCFreeZone();
|
||||
POSIX_LABEL(read_char_again);
|
||||
if( fread(&cc,1,1,f->io) != 1 )
|
||||
{
|
||||
HANDLE_FINTR(f->io,read_char_again);
|
||||
file_error("file_read_char",f->name);
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
return cc;
|
||||
}
|
||||
|
||||
/**
|
||||
file_seek : 'file -> pos:int -> mode:int -> void
|
||||
<doc>Use [fseek] to move the file pointer.</doc>
|
||||
**/
|
||||
void _hx_std_file_seek( Dynamic handle, int pos, int kind )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
hx::EnterGCFreeZone();
|
||||
if( fseek(f->io,pos,kind) != 0 )
|
||||
file_error("file_seek",f->name);
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
file_tell : 'file -> int
|
||||
<doc>Return the current position in the file</doc>
|
||||
**/
|
||||
int _hx_std_file_tell( Dynamic handle )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
hx::EnterGCFreeZone();
|
||||
int p = ftell(f->io);
|
||||
if( p == -1 )
|
||||
file_error("file_tell",f->name);
|
||||
hx::ExitGCFreeZone();
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
file_eof : 'file -> bool
|
||||
<doc>Tell if we have reached the end of the file</doc>
|
||||
**/
|
||||
bool _hx_std_file_eof( Dynamic handle )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
return feof(f->io);
|
||||
}
|
||||
|
||||
/**
|
||||
file_flush : 'file -> void
|
||||
<doc>Flush the file buffer</doc>
|
||||
**/
|
||||
void _hx_std_file_flush( Dynamic handle )
|
||||
{
|
||||
fio *f = getFio(handle);
|
||||
hx::EnterGCFreeZone();
|
||||
if( fflush( f->io ) != 0 )
|
||||
file_error("file_flush",f->name);
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
file_contents : f:string -> string
|
||||
<doc>Read the content of the file [f] and return it.</doc>
|
||||
**/
|
||||
String _hx_std_file_contents_string( String name )
|
||||
{
|
||||
std::vector<char> buffer;
|
||||
|
||||
hx::strbuf buf;
|
||||
#ifdef NEKO_WINDOWS
|
||||
hx::EnterGCFreeZone();
|
||||
FILE *file = _wfopen(name.wchar_str(&buf), L"rb");
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
FILE *file = fopen(name.utf8_str(&buf), "rb");
|
||||
#endif
|
||||
if(!file)
|
||||
file_error("file_contents",name);
|
||||
|
||||
fseek(file,0,SEEK_END);
|
||||
int len = ftell(file);
|
||||
if (len<0)
|
||||
file_error("file_ftell",name);
|
||||
if (len==0)
|
||||
{
|
||||
fclose(file);
|
||||
hx::ExitGCFreeZone();
|
||||
return String::emptyString;
|
||||
}
|
||||
|
||||
fseek(file,0,SEEK_SET);
|
||||
buffer.resize(len);
|
||||
int p = 0;
|
||||
while( len > 0 )
|
||||
{
|
||||
POSIX_LABEL(file_contents);
|
||||
int d = (int)fread(&buffer[p],1,len,file);
|
||||
if( d <= 0 )
|
||||
{
|
||||
HANDLE_FINTR(file,file_contents);
|
||||
fclose(file);
|
||||
file_error("file_contents",name);
|
||||
}
|
||||
p += d;
|
||||
len -= d;
|
||||
}
|
||||
fclose(file);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
return String::create(&buffer[0], buffer.size());
|
||||
}
|
||||
|
||||
#include <kinc/io/filereader.h>
|
||||
|
||||
|
||||
/**
|
||||
file_contents : f:string -> string
|
||||
<doc>Read the content of the file [f] and return it.</doc>
|
||||
**/
|
||||
Array<unsigned char> _hx_std_file_contents_bytes( String name )
|
||||
{
|
||||
hx::strbuf buf;
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
kinc_file_reader_t file;
|
||||
|
||||
if(!kinc_file_reader_open(&file, name.utf8_str(&buf), KINC_FILE_TYPE_ASSET))
|
||||
file_error("file_contents",name);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
Array<unsigned char> buffer = Array_obj<unsigned char>::__new(kinc_file_reader_size(&file),kinc_file_reader_size(&file));
|
||||
hx::EnterGCFreeZone();
|
||||
if (kinc_file_reader_size(&file))
|
||||
{
|
||||
char *dest = (char *)&buffer[0];
|
||||
|
||||
kinc_file_reader_read(&file, dest, kinc_file_reader_size(&file));
|
||||
}
|
||||
kinc_file_reader_close(&file);
|
||||
hx::ExitGCFreeZone();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Dynamic _hx_std_file_stdin()
|
||||
{
|
||||
fio *f = new fio();
|
||||
f->create(stdin, HX_CSTRING("stdin"), false);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
Dynamic _hx_std_file_stdout()
|
||||
{
|
||||
fio *f = new fio();
|
||||
f->create(stdout, HX_CSTRING("stdout"), false);
|
||||
return f;
|
||||
}
|
||||
|
||||
Dynamic _hx_std_file_stderr()
|
||||
{
|
||||
fio *f = new fio();
|
||||
f->create(stderr, HX_CSTRING("stderr"), false);
|
||||
return f;
|
||||
}
|
||||
|
||||
621
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Process.cpp
Normal file
621
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Process.cpp
Normal file
@ -0,0 +1,621 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
#if !defined(HX_WINRT) && !defined(EPPC)
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
# include <memory.h>
|
||||
# include <errno.h>
|
||||
# include <signal.h>
|
||||
# if (defined(ANDROID) || defined(BLACKBERRY) || defined(EMSCRIPTEN) || defined(__FreeBSD__)) && !defined(KINC_CONSOLE)
|
||||
# include <sys/wait.h>
|
||||
# elif !defined(NEKO_MAC) && !defined(KINC_CONSOLE)
|
||||
# include <wait.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
#ifndef NEKO_WINDOWS
|
||||
static int do_close( int fd )
|
||||
{
|
||||
#ifndef KINC_CONSOLE
|
||||
POSIX_LABEL(close_again);
|
||||
if( close(fd) != 0 ) {
|
||||
HANDLE_EINTR(close_again);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
struct vprocess : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdProcess };
|
||||
|
||||
bool open;
|
||||
#ifdef NEKO_WINDOWS
|
||||
HANDLE oread;
|
||||
HANDLE eread;
|
||||
HANDLE iwrite;
|
||||
PROCESS_INFORMATION pinf;
|
||||
#define HANDLE_INIT 0
|
||||
#else
|
||||
int oread;
|
||||
int eread;
|
||||
int iwrite;
|
||||
int pid;
|
||||
#define HANDLE_INIT -1
|
||||
#endif
|
||||
|
||||
void create()
|
||||
{
|
||||
open = true;
|
||||
oread = HANDLE_INIT;
|
||||
eread = HANDLE_INIT;
|
||||
iwrite = HANDLE_INIT;
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (open)
|
||||
{
|
||||
#ifdef NEKO_WINDOWS
|
||||
if (eread)
|
||||
CloseHandle(eread);
|
||||
if (oread)
|
||||
CloseHandle(oread);
|
||||
if (iwrite)
|
||||
CloseHandle(iwrite);
|
||||
CloseHandle(pinf.hProcess);
|
||||
CloseHandle(pinf.hThread);
|
||||
#else
|
||||
if (eread!=-1)
|
||||
do_close(eread);
|
||||
if (oread!=-1)
|
||||
do_close(oread);
|
||||
if (iwrite!=-1)
|
||||
do_close(iwrite);
|
||||
#endif
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((vprocess *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
String toString() { return HX_CSTRING("vprocess"); }
|
||||
};
|
||||
|
||||
vprocess *getProcess(Dynamic handle)
|
||||
{
|
||||
vprocess *p = dynamic_cast<vprocess *>(handle.mPtr);
|
||||
if (!p)
|
||||
hx::Throw(HX_CSTRING("Invalid process"));
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>Process</h1>
|
||||
<p>
|
||||
An API for starting and communication with sub processes.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
} // end anon namespace
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
static String TQuoted(const T *ptr, int len)
|
||||
{
|
||||
std::vector<T> quoted;
|
||||
quoted.reserve(len*2);
|
||||
|
||||
unsigned int bs_count = 0;
|
||||
for(int j=0;j<len;j++)
|
||||
{
|
||||
T c = ptr[j];
|
||||
switch( c )
|
||||
{
|
||||
case '"':
|
||||
// Double backslashes.
|
||||
for (int k=0;k<bs_count*2;k++)
|
||||
quoted.push_back('\\');
|
||||
bs_count = 0;
|
||||
quoted.push_back('\\');
|
||||
quoted.push_back('"');
|
||||
break;
|
||||
case '\\':
|
||||
// Don't know if we need to double yet.
|
||||
bs_count++;
|
||||
break;
|
||||
default:
|
||||
// Normal char
|
||||
for (int k=0;k<bs_count;k++)
|
||||
quoted.push_back('\\');
|
||||
bs_count = 0;
|
||||
quoted.push_back(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Add remaining backslashes, if any.
|
||||
for (int k=0;k<bs_count*2;k++)
|
||||
quoted.push_back('\\');
|
||||
int qlen = (int)quoted.size();
|
||||
quoted.push_back('\0');
|
||||
|
||||
return String::create( "ed[0], qlen );
|
||||
}
|
||||
|
||||
#if defined(NEKO_WINDOWS)
|
||||
static String quoteString(String v)
|
||||
{
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (v.isUTF16Encoded())
|
||||
return TQuoted(v.raw_wptr(),v.length);
|
||||
#endif
|
||||
return TQuoted(v.raw_ptr(),v.length);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
process_run : cmd:string -> args:string array -> 'process
|
||||
<doc>
|
||||
Start a process using a command.
|
||||
When args is not null, cmd and args will be auto-quoted/escaped.
|
||||
If no auto-quoting/escaping is desired, you should append necessary
|
||||
arguments to cmd as if it is inputted to the shell directly, and pass
|
||||
null to args.
|
||||
|
||||
inShowParam = only for windows, SHOW_* from "ShowWindow" function
|
||||
default = 1 = SHOW_WINDOW
|
||||
</doc>
|
||||
**/
|
||||
Dynamic _hx_std_process_run( String cmd, Array<String> vargs, int inShowParam )
|
||||
{
|
||||
#if defined(APPLETV) || defined(HX_APPLEWATCH) || defined(KINC_CONSOLE)
|
||||
return null();
|
||||
|
||||
#else
|
||||
vprocess *p = 0;
|
||||
bool isRaw = !vargs.mPtr;
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
{
|
||||
SECURITY_ATTRIBUTES sattr;
|
||||
STARTUPINFOW sinf;
|
||||
HANDLE proc = GetCurrentProcess();
|
||||
HANDLE oread,eread,iwrite;
|
||||
// creates commandline
|
||||
String b;
|
||||
if (isRaw)
|
||||
{
|
||||
b = HX_CSTRING("\"");
|
||||
const char* cmdexe = getenv("COMSPEC");
|
||||
if (!cmdexe) cmdexe = "cmd.exe";
|
||||
b += String(cmdexe) + HX_CSTRING("\" /C \"") + cmd + HX_CSTRING("\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
b = HX_CSTRING("\"") + cmd + HX_CSTRING("\"");
|
||||
|
||||
for(int i=0;i<vargs->length;i++)
|
||||
{
|
||||
b += HX_CSTRING(" \"");
|
||||
if (vargs[i].length)
|
||||
b += quoteString(vargs[i]);
|
||||
b += HX_CSTRING("\"");
|
||||
}
|
||||
}
|
||||
|
||||
const wchar_t *name = b.__WCStr();
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
// startup process
|
||||
sattr.nLength = sizeof(sattr);
|
||||
sattr.bInheritHandle = TRUE;
|
||||
sattr.lpSecurityDescriptor = NULL;
|
||||
memset(&sinf,0,sizeof(sinf));
|
||||
sinf.cb = sizeof(sinf);
|
||||
sinf.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
||||
sinf.wShowWindow = inShowParam;
|
||||
CreatePipe(&oread,&sinf.hStdOutput,&sattr,0);
|
||||
CreatePipe(&eread,&sinf.hStdError,&sattr,0);
|
||||
CreatePipe(&sinf.hStdInput,&iwrite,&sattr,0);
|
||||
|
||||
HANDLE procOread,procEread,procIwrite;
|
||||
|
||||
DuplicateHandle(proc,oread,proc,&procOread,0,FALSE,DUPLICATE_SAME_ACCESS);
|
||||
DuplicateHandle(proc,eread,proc,&procEread,0,FALSE,DUPLICATE_SAME_ACCESS);
|
||||
DuplicateHandle(proc,iwrite,proc,&procIwrite,0,FALSE,DUPLICATE_SAME_ACCESS);
|
||||
CloseHandle(oread);
|
||||
CloseHandle(eread);
|
||||
CloseHandle(iwrite);
|
||||
//printf("Cmd %s\n",val_string(cmd));
|
||||
PROCESS_INFORMATION pinf;
|
||||
memset(&pinf,0,sizeof(pinf));
|
||||
if( !CreateProcessW(NULL,(wchar_t *)name,NULL,NULL,TRUE,CREATE_NO_WINDOW,NULL,NULL,&sinf,&pinf) )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
hx::Throw(HX_CSTRING("Could not start process"));
|
||||
}
|
||||
// close unused pipes
|
||||
CloseHandle(sinf.hStdOutput);
|
||||
CloseHandle(sinf.hStdError);
|
||||
CloseHandle(sinf.hStdInput);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
p = new vprocess;
|
||||
p->create();
|
||||
p->oread = procOread;
|
||||
p->eread = procEread;
|
||||
p->iwrite = procIwrite;
|
||||
p->pinf = pinf;
|
||||
}
|
||||
#else // not windows ...
|
||||
{
|
||||
int input[2], output[2], error[2];
|
||||
if( pipe(input) || pipe(output) || pipe(error) )
|
||||
return null();
|
||||
|
||||
hx::strbuf buf;
|
||||
std::vector< std::string > values;
|
||||
if (isRaw)
|
||||
{
|
||||
values.resize(3);
|
||||
values[0] = "/bin/sh";
|
||||
values[1] = "-c";
|
||||
values[2] = cmd.utf8_str(&buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
values.resize(vargs->length+1);
|
||||
|
||||
values[0] = cmd.utf8_str(&buf);
|
||||
for(int i=0;i<vargs->length;i++)
|
||||
values[i+1] = vargs[i].utf8_str(&buf);
|
||||
}
|
||||
|
||||
std::vector<const char *> argv(values.size()+1);
|
||||
for(int i=0;i<values.size();i++)
|
||||
argv[i] = values[i].c_str();
|
||||
|
||||
int pid = fork();
|
||||
if( pid == -1 )
|
||||
return null();
|
||||
|
||||
// child
|
||||
if( pid == 0 )
|
||||
{
|
||||
close(input[1]);
|
||||
close(output[0]);
|
||||
close(error[0]);
|
||||
dup2(input[0],0);
|
||||
dup2(output[1],1);
|
||||
dup2(error[1],2);
|
||||
execvp(argv[0],(char* const*)&argv[0]);
|
||||
fprintf(stderr,"Command not found : %S\n",cmd.wchar_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// parent
|
||||
do_close(input[0]);
|
||||
do_close(output[1]);
|
||||
do_close(error[1]);
|
||||
|
||||
p = new vprocess;
|
||||
p->create();
|
||||
p->iwrite = input[1];
|
||||
p->oread = output[0];
|
||||
p->eread = error[0];
|
||||
p->pid = pid;
|
||||
}
|
||||
#endif
|
||||
|
||||
return p;
|
||||
|
||||
#endif // not APPLETV/HX_APPLEWATCH
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
process_stdout_read : 'process -> buf:string -> pos:int -> len:int -> int
|
||||
<doc>
|
||||
Read up to [len] bytes in [buf] starting at [pos] from the process stdout.
|
||||
Returns the number of bytes readed this way. Raise an exception if this
|
||||
process stdout is closed and no more data is available for reading.
|
||||
|
||||
For hxcpp, the input buffer is in bytes, not characters
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_process_stdout_read( Dynamic handle, Array<unsigned char> buf, int pos, int len )
|
||||
{
|
||||
if( pos < 0 || len < 0 || pos + len > buf->length )
|
||||
return 0;
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
unsigned char *dest = &buf[0];
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
DWORD nbytes = 0;
|
||||
if( !ReadFile(p->oread,dest+pos,len,&nbytes,0) )
|
||||
nbytes = 0;
|
||||
#elif !defined(KINC_CONSOLE)
|
||||
int nbytes = read(p->oread,dest + pos,len);
|
||||
if( nbytes <= 0 )
|
||||
nbytes = 0;
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
#ifdef KINC_CONSOLE
|
||||
return 0;
|
||||
#else
|
||||
return nbytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
process_stderr_read : 'process -> buf:string -> pos:int -> len:int -> int
|
||||
<doc>
|
||||
Read up to [len] bytes in [buf] starting at [pos] from the process stderr.
|
||||
Returns the number of bytes readed this way. Raise an exception if this
|
||||
process stderr is closed and no more data is available for reading.
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_process_stderr_read( Dynamic handle, Array<unsigned char> buf, int pos, int len )
|
||||
{
|
||||
if( pos < 0 || len < 0 || pos + len > buf->length )
|
||||
return 0;
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
unsigned char *dest = &buf[0];
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
DWORD nbytes = 0;
|
||||
if( !ReadFile(p->eread,dest+pos,len,&nbytes,0) )
|
||||
nbytes = 0;
|
||||
#elif !defined(KINC_CONSOLE)
|
||||
int nbytes = read(p->eread,dest + pos,len);
|
||||
if( nbytes <= 0 )
|
||||
nbytes = 0;
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
#ifdef KINC_CONSOLE
|
||||
return 0;
|
||||
#else
|
||||
return nbytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
process_stdin_write : 'process -> buf:string -> pos:int -> len:int -> int
|
||||
<doc>
|
||||
Write up to [len] bytes from [buf] starting at [pos] to the process stdin.
|
||||
Returns the number of bytes writen this way. Raise an exception if this
|
||||
process stdin is closed.
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_process_stdin_write( Dynamic handle, Array<unsigned char> buf, int pos, int len )
|
||||
{
|
||||
if( pos < 0 || len < 0 || pos + len > buf->length )
|
||||
return 0;
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
unsigned char *src = &buf[0];
|
||||
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
DWORD nbytes =0;
|
||||
if( !WriteFile(p->iwrite,src+pos,len,&nbytes,0) )
|
||||
nbytes = 0;
|
||||
#elif !defined(KINC_CONSOLE)
|
||||
int nbytes = write(p->iwrite,src+pos,len);
|
||||
if( nbytes == -1 )
|
||||
nbytes = 0;
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
#ifdef KINC_CONSOLE
|
||||
return 0;
|
||||
#else
|
||||
return nbytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
process_stdin_close : 'process -> void
|
||||
<doc>
|
||||
Close the process standard input.
|
||||
</doc>
|
||||
**/
|
||||
void _hx_std_process_stdin_close( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
if ( p->iwrite )
|
||||
CloseHandle(p->iwrite);
|
||||
#else
|
||||
if( p->iwrite!=-1 )
|
||||
do_close(p->iwrite);
|
||||
#endif
|
||||
p->iwrite = HANDLE_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
process_exit : 'process -> int
|
||||
<doc>
|
||||
Wait until the process terminate, then returns its exit code.
|
||||
</doc>
|
||||
**/
|
||||
#if (HXCPP_API_LEVEL > 420)
|
||||
Dynamic _hx_std_process_exit( Dynamic handle, bool block )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
{
|
||||
DWORD rval;
|
||||
DWORD wait = INFINITE;
|
||||
if (!block)
|
||||
wait = 0;
|
||||
|
||||
WaitForSingleObject(p->pinf.hProcess,wait);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
if( !GetExitCodeProcess(p->pinf.hProcess,&rval) && block)
|
||||
return 0;
|
||||
else if (!block && rval == STILL_ACTIVE)
|
||||
return null();
|
||||
else
|
||||
return rval;
|
||||
}
|
||||
#else
|
||||
int options=0;
|
||||
if (!block)
|
||||
options = WNOHANG;
|
||||
|
||||
int rval=0;
|
||||
pid_t ret=-1;
|
||||
while( (ret = waitpid(p->pid,&rval,options)) != p->pid )
|
||||
{
|
||||
if( errno == EINTR )
|
||||
continue;
|
||||
|
||||
if (!block && ret == 0)
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
return null();
|
||||
}
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
return 0;
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
if( !WIFEXITED(rval) )
|
||||
return 0;
|
||||
|
||||
return WEXITSTATUS(rval);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
int _hx_std_process_exit( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
#ifdef NEKO_WINDOWS
|
||||
{
|
||||
DWORD rval;
|
||||
WaitForSingleObject(p->pinf.hProcess,INFINITE);
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
if( !GetExitCodeProcess(p->pinf.hProcess,&rval) )
|
||||
return 0;
|
||||
return rval;
|
||||
}
|
||||
#elif !defined(KINC_CONSOLE)
|
||||
int rval=0;
|
||||
while( waitpid(p->pid,&rval,0) != p->pid )
|
||||
{
|
||||
if( errno == EINTR )
|
||||
continue;
|
||||
hx::ExitGCFreeZone();
|
||||
return 0;
|
||||
}
|
||||
hx::ExitGCFreeZone();
|
||||
if( !WIFEXITED(rval) )
|
||||
return 0;
|
||||
|
||||
return WEXITSTATUS(rval);
|
||||
#else
|
||||
hx::ExitGCFreeZone();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
process_pid : 'process -> int
|
||||
<doc>
|
||||
Returns the process id.
|
||||
</doc>
|
||||
**/
|
||||
int _hx_std_process_pid( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
return p->pinf.dwProcessId;
|
||||
#else
|
||||
return p->pid;
|
||||
#endif
|
||||
}
|
||||
|
||||
void _hx_std_process_kill( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
TerminateProcess(p->pinf.hProcess, -1);
|
||||
#else
|
||||
kill(p->pid, SIGTERM);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
process_close : 'process -> void
|
||||
<doc>
|
||||
Close the process I/O.
|
||||
</doc>
|
||||
**/
|
||||
void _hx_std_process_close( Dynamic handle )
|
||||
{
|
||||
vprocess *p = getProcess(handle);
|
||||
p->destroy();
|
||||
}
|
||||
|
||||
#else // !HX_WINRT
|
||||
|
||||
Dynamic _hx_std_process_run( String cmd, Array<String> vargs, int inShowParam ){ return null(); }
|
||||
int _hx_std_process_stdout_read( Dynamic handle, Array<unsigned char> buf, int pos, int len ) { return 0; }
|
||||
int _hx_std_process_stderr_read( Dynamic handle, Array<unsigned char> buf, int pos, int len ) { return 0; }
|
||||
int _hx_std_process_stdin_write( Dynamic handle, Array<unsigned char> buf, int pos, int len ) { return 0; }
|
||||
void _hx_std_process_stdin_close( Dynamic handle ) { }
|
||||
#if (HXCPP_API_LEVEL > 420)
|
||||
Dynamic _hx_std_process_exit( Dynamic handle, bool block ) { return 0; }
|
||||
#else
|
||||
int _hx_std_process_exit( Dynamic handle ) { return 0; }
|
||||
#endif
|
||||
int _hx_std_process_pid( Dynamic handle ) { return 0; }
|
||||
void _hx_std_process_close( Dynamic handle ) { }
|
||||
void _hx_std_process_kill( Dynamic handle ) { }
|
||||
|
||||
#endif // HX_WINRT
|
||||
|
||||
181
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Random.cpp
Normal file
181
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Random.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#ifdef HX_WINDOWS
|
||||
# include <windows.h>
|
||||
# include <process.h>
|
||||
#elif defined(EPPC) || defined(KINC_CONSOLE)
|
||||
# include <time.h>
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>Random</h1>
|
||||
<p>A seeded pseudo-random generator</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
|
||||
|
||||
#define NSEEDS 25
|
||||
#ifdef MAX
|
||||
#undef MAX
|
||||
#endif
|
||||
#define MAX 7
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct rnd : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdRandom };
|
||||
|
||||
unsigned long seeds[NSEEDS];
|
||||
unsigned long cur;
|
||||
|
||||
String toString() { return HX_CSTRING("rand"); }
|
||||
};
|
||||
|
||||
static unsigned long mag01[2]={
|
||||
0x0, 0x8ebfd028 // magic, don't change
|
||||
};
|
||||
|
||||
static const unsigned long init_seeds[] = {
|
||||
0x95f24dab, 0x0b685215, 0xe76ccae7, 0xaf3ec239, 0x715fad23,
|
||||
0x24a590ad, 0x69e4b5ef, 0xbf456141, 0x96bc1b7b, 0xa7bdf825,
|
||||
0xc1de75b7, 0x8858a9c9, 0x2da87693, 0xb657f9dd, 0xffdc8a9f,
|
||||
0x8121da71, 0x8b823ecb, 0x885d05f5, 0x4e20cd47, 0x5a9ad5d9,
|
||||
0x512c0c03, 0xea857ccd, 0x4cc1d30f, 0x8891a8a1, 0xa6b7aadb
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void rnd_set_seed( rnd *r, int s )
|
||||
{
|
||||
int i;
|
||||
r->cur = 0;
|
||||
memcpy(r->seeds,init_seeds,sizeof(init_seeds));
|
||||
for(i=0;i<NSEEDS;i++)
|
||||
r->seeds[i] ^= s;
|
||||
}
|
||||
|
||||
rnd *getRnd(Dynamic handle)
|
||||
{
|
||||
rnd *r = dynamic_cast<rnd *>(handle.mPtr);
|
||||
if (!r)
|
||||
hx::Throw(HX_CSTRING("Invalid random handle"));
|
||||
return r;
|
||||
}
|
||||
|
||||
} // end anon namespace
|
||||
|
||||
Dynamic _hx_std_random_new()
|
||||
{
|
||||
rnd *r = new rnd();
|
||||
|
||||
#if defined(NEKO_WINDOWS) && !defined(KINC_CONSOLE)
|
||||
#if defined(HX_WINRT) && defined(__cplusplus_winrt)
|
||||
int pid = Windows::Security::Cryptography::CryptographicBuffer::GenerateRandomNumber();
|
||||
#else
|
||||
int pid = GetCurrentProcessId();
|
||||
#endif
|
||||
#elif defined(EPPC) || defined(KINC_CONSOLE)
|
||||
int pid = 1;
|
||||
#else
|
||||
int pid = getpid();
|
||||
#endif
|
||||
|
||||
unsigned int t;
|
||||
#ifdef HX_WINRT
|
||||
t = (unsigned int)GetTickCount64();
|
||||
#elif defined(NEKO_WINDOWS) && !defined(KINC_CONSOLE)
|
||||
t = GetTickCount();
|
||||
#elif defined(EPPC) || defined(KINC_CONSOLE)
|
||||
time_t tod;
|
||||
time(&tod);
|
||||
t = (double)tod;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
t = tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
#endif
|
||||
|
||||
|
||||
rnd_set_seed(r,t ^ (pid | (pid << 16)));
|
||||
return r;
|
||||
}
|
||||
|
||||
static unsigned int rnd_int( rnd *r )
|
||||
{
|
||||
unsigned int y;
|
||||
int pos = r->cur++;
|
||||
if( pos >= NSEEDS ) {
|
||||
int kk;
|
||||
for(kk=0;kk<NSEEDS-MAX;kk++)
|
||||
r->seeds[kk] = r->seeds[kk+MAX] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2];
|
||||
for(;kk<NSEEDS;kk++)
|
||||
r->seeds[kk] = r->seeds[kk+(MAX-NSEEDS)] ^ (r->seeds[kk] >> 1) ^ mag01[r->seeds[kk] % 2];
|
||||
r->cur = 1;
|
||||
pos = 0;
|
||||
}
|
||||
y = r->seeds[pos];
|
||||
y ^= (y << 7) & 0x2b5b2500;
|
||||
y ^= (y << 15) & 0xdb8b0000;
|
||||
y ^= (y >> 16);
|
||||
return y;
|
||||
}
|
||||
|
||||
static double rnd_float( rnd *r )
|
||||
{
|
||||
double big = 4294967296.0;
|
||||
return ((rnd_int(r) / big + rnd_int(r)) / big + rnd_int(r)) / big;
|
||||
}
|
||||
|
||||
/**
|
||||
random_new : void -> 'random
|
||||
<doc>Create a new random with random seed</doc>
|
||||
**/
|
||||
|
||||
|
||||
#include<stdlib.h>
|
||||
|
||||
|
||||
/**
|
||||
random_set_seed : 'random -> int -> void
|
||||
<doc>Set the generator seed</doc>
|
||||
**/
|
||||
void _hx_std_random_set_seed( Dynamic handle, int v )
|
||||
{
|
||||
rnd_set_seed( getRnd(handle) ,v);
|
||||
}
|
||||
|
||||
/**
|
||||
random_int : 'random -> max:int -> int
|
||||
<doc>Return a random integer modulo [max]</doc>
|
||||
**/
|
||||
int _hx_std_random_int( Dynamic handle, int max )
|
||||
{
|
||||
if( max <= 0 )
|
||||
return 0;
|
||||
return (rnd_int( getRnd(handle)) & 0x3FFFFFFF) % max;
|
||||
}
|
||||
|
||||
/**
|
||||
random_float : 'random -> float
|
||||
<doc>Return a random float</doc>
|
||||
**/
|
||||
double _hx_std_random_float( Dynamic handle )
|
||||
{
|
||||
return rnd_float(getRnd(handle));
|
||||
}
|
||||
|
||||
|
||||
1374
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Socket.cpp
Normal file
1374
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Socket.cpp
Normal file
File diff suppressed because it is too large
Load Diff
915
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Sys.cpp
Normal file
915
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/std/Sys.cpp
Normal file
@ -0,0 +1,915 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef EPPC
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifndef __clang__
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <conio.h>
|
||||
#include <locale.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#if !defined(EPPC) && !defined(KINC_CONSOLE)
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <termios.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#ifndef ANDROID
|
||||
#include <locale.h>
|
||||
#if !defined(BLACKBERRY) && !defined(EPPC) && !defined(GCW0) && !defined(__GLIBC__) && !defined(KINC_CONSOLE)
|
||||
#include <xlocale.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#if !defined(IPHONE) && !defined(APPLETV) && !defined(HX_APPLEWATCH)
|
||||
#ifdef NEKO_MAC
|
||||
#include <sys/syslimits.h>
|
||||
#include <limits.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HX_WINRT) && !defined(_XBOX_ONE)
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#ifdef HX_ANDROID
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifndef CLK_TCK
|
||||
#define CLK_TCK 100
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>System</h1>
|
||||
<p>
|
||||
Interactions with the operating system.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
/**
|
||||
get_env : string -> string?
|
||||
<doc>Get some environment variable if exists</doc>
|
||||
**/
|
||||
|
||||
String _hx_std_get_env( String v )
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(KINC_CONSOLE)
|
||||
return String();
|
||||
#else
|
||||
#if defined(NEKO_WINDOWS) && defined(HX_SMART_STRINGS)
|
||||
hx::strbuf wbuf;
|
||||
return String::create( _wgetenv( v.wchar_str(&wbuf) ) );
|
||||
#else
|
||||
hx::strbuf buf;
|
||||
return String::create( getenv(v.utf8_str(&buf)) );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
put_env : var:string -> val:string -> void
|
||||
<doc>Set some environment variable value</doc>
|
||||
**/
|
||||
void _hx_std_put_env( String e, String v )
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(KINC_CONSOLE)
|
||||
// Do nothing
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
String set = e + HX_CSTRING("=") + (v != null()?v:"");
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (set.isUTF16Encoded())
|
||||
_wputenv(set.wchar_str());
|
||||
else
|
||||
#endif
|
||||
putenv(set.utf8_str());
|
||||
#else
|
||||
if (v == null())
|
||||
unsetenv(e.utf8_str());
|
||||
else
|
||||
setenv(e.utf8_str(),v.utf8_str(),1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_sleep : number -> void
|
||||
<doc>Sleep a given number of seconds</doc>
|
||||
**/
|
||||
|
||||
void _hx_std_sys_sleep( double f )
|
||||
{
|
||||
hx::EnterGCFreeZone();
|
||||
#if defined(NEKO_WINDOWS)
|
||||
Sleep((DWORD)(f * 1000));
|
||||
#elif defined(EPPC) || defined(KINC_CONSOLE)
|
||||
//TODO: Implement sys_sleep for EPPC
|
||||
#else
|
||||
{
|
||||
struct timespec t;
|
||||
struct timespec tmp;
|
||||
t.tv_sec = (int)(f);
|
||||
t.tv_nsec = (int)(((f) - t.tv_sec) * 1e9);
|
||||
while( nanosleep(&t,&tmp) == -1 )
|
||||
{
|
||||
if( errno != EINTR )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
return;
|
||||
}
|
||||
t = tmp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
set_time_locale : string -> bool
|
||||
<doc>Set the locale for LC_TIME, returns true on success</doc>
|
||||
**/
|
||||
bool _hx_std_set_time_locale( String l )
|
||||
{
|
||||
#if defined(ANDROID) || defined(GCW0) || defined(KINC_CONSOLE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
#if defined(NEKO_POSIX)
|
||||
locale_t lc, old;
|
||||
lc = newlocale(LC_TIME_MASK,l.utf8_str(),NULL);
|
||||
if( !lc )
|
||||
return false;
|
||||
old = uselocale(lc);
|
||||
if( !old )
|
||||
{
|
||||
freelocale(lc);
|
||||
return false;
|
||||
}
|
||||
if( old != LC_GLOBAL_LOCALE )
|
||||
freelocale(old);
|
||||
return true;
|
||||
#else
|
||||
#if defined(NEKO_WINDOWS) && defined(HX_SMART_STRINGS)
|
||||
if (l.isUTF16Encoded())
|
||||
return _wsetlocale(LC_TIME,l.wchar_str());
|
||||
#endif
|
||||
return setlocale(LC_TIME,l.utf8_str());
|
||||
#endif
|
||||
|
||||
#endif // !Android
|
||||
}
|
||||
|
||||
/**
|
||||
get_cwd : void -> string
|
||||
<doc>Return current working directory</doc>
|
||||
**/
|
||||
String _hx_std_get_cwd()
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(KINC_CONSOLE)
|
||||
return HX_CSTRING("ms-appdata:///local/");
|
||||
#elif defined(EPPC)
|
||||
return String();
|
||||
#else
|
||||
#ifdef NEKO_WINDOWS
|
||||
wchar_t buf[261];
|
||||
int l;
|
||||
if( !GetCurrentDirectoryW(260,buf) )
|
||||
return String();
|
||||
l = (int)wcslen(buf);
|
||||
if( buf[l-1] != '/' && buf[l-1] != '\\' ) {
|
||||
buf[l] = '/';
|
||||
buf[l+1] = 0;
|
||||
}
|
||||
#else
|
||||
char buf[1025];
|
||||
int l;
|
||||
if( getcwd(buf,1024) == NULL )
|
||||
return String();
|
||||
l = (int)strlen(buf);
|
||||
if( buf[l-1] != '/' && buf[l-1] != '\\' ) {
|
||||
buf[l] = '/';
|
||||
buf[l+1] = 0;
|
||||
}
|
||||
#endif
|
||||
return String::create(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
set_cwd : string -> void
|
||||
<doc>Set current working directory</doc>
|
||||
**/
|
||||
bool _hx_std_set_cwd( String d )
|
||||
{
|
||||
#if !defined(HX_WINRT) && !defined(EPPC) && !defined(KINC_CONSOLE)
|
||||
#ifdef NEKO_WINDOWS
|
||||
return SetCurrentDirectoryW(d.wchar_str()) == 0;
|
||||
#else
|
||||
return chdir(d.utf8_str()) == 0;
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
sys_string : void -> string
|
||||
<doc>
|
||||
Return the local system string. The current value are possible :
|
||||
<ul>
|
||||
<li>[Windows]</li>
|
||||
<li>[Linux]</li>
|
||||
<li>[BSD]</li>
|
||||
<li>[Mac]</li>
|
||||
</ul>
|
||||
</doc>
|
||||
**/
|
||||
String _hx_std_sys_string()
|
||||
{
|
||||
#if defined(KINC_CONSOLE)
|
||||
return HX_CSTRING("Kinc Console");
|
||||
#elif defined(HX_WINRT)
|
||||
return HX_CSTRING("WinRT");
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
return HX_CSTRING("Windows");
|
||||
#elif defined(NEKO_GNUKBSD)
|
||||
return HX_CSTRING("GNU/kFreeBSD");
|
||||
#elif defined(NEKO_LINUX)
|
||||
return HX_CSTRING("Linux");
|
||||
#elif defined(NEKO_BSD)
|
||||
return HX_CSTRING("BSD");
|
||||
#elif defined(NEKO_MAC)
|
||||
return HX_CSTRING("Mac");
|
||||
#elif defined(ANDROID)
|
||||
return HX_CSTRING("Android");
|
||||
#elif defined(BLACKBERRY)
|
||||
return HX_CSTRING("BlackBerry");
|
||||
#elif defined(EMSCRIPTEN)
|
||||
return HX_CSTRING("Emscripten");
|
||||
#elif defined(EPPC)
|
||||
return HX_CSTRING("EPPC");
|
||||
#else
|
||||
#error Unknow system string
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_is64 : void -> bool
|
||||
<doc>
|
||||
Returns true if we are on a 64-bit system
|
||||
</doc>
|
||||
**/
|
||||
bool _hx_std_sys_is64()
|
||||
{
|
||||
#ifdef NEKO_64BITS
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_command : string -> int
|
||||
<doc>Run the shell command and return exit code</doc>
|
||||
**/
|
||||
int _hx_std_sys_command( String cmd )
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(EMSCRIPTEN) || defined(EPPC) || defined(IPHONE) || defined(APPLETV) || defined(HX_APPLEWATCH) || defined(KINC_CONSOLE)
|
||||
return -1;
|
||||
#else
|
||||
if( !cmd.raw_ptr() || !cmd.length )
|
||||
return -1;
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
int result = 0;
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (!cmd.isUTF16Encoded())
|
||||
result = system(cmd.raw_ptr());
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf wbuf;
|
||||
result = _wsystem(cmd.wchar_str(&wbuf));
|
||||
}
|
||||
#else
|
||||
hx::strbuf buf;
|
||||
hx::EnterGCFreeZone();
|
||||
int result = system(cmd.utf8_str(&buf));
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
#if !defined(NEKO_WINDOWS) && !defined(__FreeBSD__)
|
||||
result = WEXITSTATUS(result) | (WTERMSIG(result) << 8);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
sys_exit : int -> void
|
||||
<doc>Exit with the given errorcode. Never returns.</doc>
|
||||
**/
|
||||
void _hx_std_sys_exit( int code )
|
||||
{
|
||||
exit(code);
|
||||
}
|
||||
|
||||
/**
|
||||
sys_exists : string -> bool
|
||||
<doc>Returns true if the file or directory exists.</doc>
|
||||
**/
|
||||
bool _hx_std_sys_exists( String path )
|
||||
{
|
||||
#if defined(EPPC) || defined(KINC_CONSOLE)
|
||||
return true;
|
||||
#else
|
||||
|
||||
#ifdef NEKO_WINDOWS
|
||||
const wchar_t * wpath = path.wchar_str();
|
||||
hx::EnterGCFreeZone();
|
||||
bool result = GetFileAttributesW(wpath) != INVALID_FILE_ATTRIBUTES;
|
||||
#else
|
||||
struct stat st;
|
||||
hx::EnterGCFreeZone();
|
||||
hx::strbuf buf;
|
||||
bool result = stat(path.utf8_str(&buf),&st) == 0;
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
file_delete : string -> void
|
||||
<doc>Delete the file. Exception on error.</doc>
|
||||
**/
|
||||
void _hx_std_file_delete( String path )
|
||||
{
|
||||
#if !defined(EPPC) && !defined(KINC_CONSOLE)
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
bool err = false;
|
||||
#if defined(NEKO_WINDOWS) && defined(HX_SMART_STRINGS)
|
||||
if (path.isUTF16Encoded())
|
||||
err = _wunlink(path.wchar_str());
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = unlink(path.utf8_str(&buf));
|
||||
}
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
if (err)
|
||||
hx::Throw( HX_CSTRING("Could not delete ") + path );
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_rename : from:string -> to:string -> void
|
||||
<doc>Rename the file or directory. Exception on error.</doc>
|
||||
**/
|
||||
void _hx_std_sys_rename( String path, String newname )
|
||||
{
|
||||
#ifdef KINC_CONSOLE
|
||||
bool err = true;
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
hx::strbuf buf0;
|
||||
hx::strbuf buf1;
|
||||
#ifdef NEKO_WINDOWS
|
||||
bool err = _wrename(path.wchar_str(&buf0),newname.wchar_str(&buf1));
|
||||
#else
|
||||
bool err = rename(path.utf8_str(&buf0),newname.utf8_str(&buf1));
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
#endif
|
||||
if (err)
|
||||
hx::Throw(HX_CSTRING("Could not rename"));
|
||||
}
|
||||
|
||||
#define STATF(f) o->Add(HX_CSTRING(#f),(int)(s.st_##f))
|
||||
|
||||
/**
|
||||
sys_stat : string -> {
|
||||
gid => int,
|
||||
uid => int,
|
||||
atime => 'int,
|
||||
mtime => 'int,
|
||||
ctime => 'int,
|
||||
dev => int,
|
||||
ino => int,
|
||||
nlink => int,
|
||||
rdev => int,
|
||||
mode => int,
|
||||
size => int
|
||||
}
|
||||
<doc>Run the [stat] command on the given file or directory.</doc>
|
||||
**/
|
||||
Dynamic _hx_std_sys_stat( String path )
|
||||
{
|
||||
#if defined(EPPC) || defined(KINC_CONSOLE)
|
||||
return null();
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
bool err = false;
|
||||
#if defined(NEKO_WINDOWS)
|
||||
struct _stat s;
|
||||
#if defined(HX_SMART_STRINGS)
|
||||
if (path.isUTF16Encoded())
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = _wstat(path.wchar_str(&buf),&s);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = _stat(path.utf8_str(&buf),&s);
|
||||
}
|
||||
#else
|
||||
struct stat s;
|
||||
hx::strbuf buf;
|
||||
err = stat(path.utf8_str(&buf),&s);
|
||||
#endif
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
if (err)
|
||||
return null();
|
||||
hx::Anon o = hx::Anon_obj::Create();
|
||||
|
||||
STATF(gid);
|
||||
STATF(uid);
|
||||
STATF(atime);
|
||||
STATF(mtime);
|
||||
STATF(ctime);
|
||||
STATF(dev);
|
||||
STATF(ino);
|
||||
STATF(mode);
|
||||
STATF(nlink);
|
||||
STATF(rdev);
|
||||
STATF(size);
|
||||
STATF(mode);
|
||||
|
||||
return o;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_file_type : string -> string
|
||||
<doc>
|
||||
Return the type of the file. The current values are possible :
|
||||
<ul>
|
||||
<li>[file]</li>
|
||||
<li>[dir]</li>
|
||||
<li>[symlink]</li>
|
||||
<li>[sock]</li>
|
||||
<li>[char]</li>
|
||||
<li>[block]</li>
|
||||
<li>[fifo]</li>
|
||||
</ul>
|
||||
</doc>
|
||||
**/
|
||||
String _hx_std_sys_file_type( String path )
|
||||
{
|
||||
if (path==null())
|
||||
return String();
|
||||
#if defined(EPPC) || defined(KINC_CONSOLE)
|
||||
return String();
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
bool err = false;
|
||||
#if defined(NEKO_WINDOWS)
|
||||
struct _stat s;
|
||||
#if defined(HX_SMART_STRINGS)
|
||||
if (path.isUTF16Encoded())
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = _wstat(path.wchar_str(&buf),&s);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf buf;
|
||||
err = _stat(path.utf8_str(&buf),&s);
|
||||
}
|
||||
#else
|
||||
struct stat s;
|
||||
hx::strbuf buf;
|
||||
err = stat(path.utf8_str(&buf),&s);
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
if (err)
|
||||
return String();
|
||||
|
||||
if( s.st_mode & S_IFREG )
|
||||
return HX_CSTRING("file");
|
||||
if( s.st_mode & S_IFDIR )
|
||||
return HX_CSTRING("dir");
|
||||
if( s.st_mode & S_IFCHR )
|
||||
return HX_CSTRING("char");
|
||||
#ifndef NEKO_WINDOWS
|
||||
if( s.st_mode & S_IFLNK )
|
||||
return HX_CSTRING("symlink");
|
||||
if( s.st_mode & S_IFBLK )
|
||||
return HX_CSTRING("block");
|
||||
if( s.st_mode & S_IFIFO )
|
||||
return HX_CSTRING("fifo");
|
||||
if( s.st_mode & S_IFSOCK )
|
||||
return HX_CSTRING("sock");
|
||||
#endif
|
||||
return String();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_create_dir : string -> mode:int -> void
|
||||
<doc>Create a directory with the specified rights</doc>
|
||||
**/
|
||||
bool _hx_std_sys_create_dir( String path, int mode )
|
||||
{
|
||||
#if defined(EPPC) || defined(KINC_CONSOLE)
|
||||
return true;
|
||||
#else
|
||||
#ifdef NEKO_WINDOWS
|
||||
const wchar_t * wpath = path.wchar_str();
|
||||
hx::EnterGCFreeZone();
|
||||
bool err = _wmkdir(wpath);
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
hx::strbuf buf;
|
||||
bool err = mkdir(path.utf8_str(&buf), mode);
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
return !err;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_remove_dir : string -> void
|
||||
<doc>Remove a directory. Exception on error</doc>
|
||||
**/
|
||||
void _hx_std_sys_remove_dir( String path )
|
||||
{
|
||||
#if defined(EPPC) || defined(KINC_CONSOLE)
|
||||
|
||||
#else
|
||||
hx::EnterGCFreeZone();
|
||||
|
||||
bool ok = false;
|
||||
|
||||
#if defined(NEKO_WINDOWS) && defined(HX_SMART_STRINGS)
|
||||
if (path.isUTF16Encoded())
|
||||
{
|
||||
ok = _wrmdir(path.wchar_str()) == 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hx::strbuf buf;
|
||||
ok = rmdir(path.utf8_str(&buf)) == 0;
|
||||
}
|
||||
|
||||
|
||||
hx::ExitGCFreeZone();
|
||||
if (!ok)
|
||||
hx::Throw(HX_CSTRING("Could not remove directory"));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_time : void -> float
|
||||
<doc>Return an accurate local time stamp in seconds since Jan 1 1970</doc>
|
||||
**/
|
||||
double _hx_std_sys_time()
|
||||
{
|
||||
#ifdef NEKO_WINDOWS
|
||||
#define EPOCH_DIFF (134774*24*60*60.0)
|
||||
SYSTEMTIME t;
|
||||
FILETIME ft;
|
||||
ULARGE_INTEGER ui;
|
||||
GetSystemTime(&t);
|
||||
if( !SystemTimeToFileTime(&t,&ft) )
|
||||
return 0;
|
||||
ui.LowPart = ft.dwLowDateTime;
|
||||
ui.HighPart = ft.dwHighDateTime;
|
||||
return ( ((double)ui.QuadPart) / 10000000.0 - EPOCH_DIFF );
|
||||
#elif defined(EPPC) || defined(KINC_CONSOLE)
|
||||
time_t tod;
|
||||
time(&tod);
|
||||
return ((double)tod);
|
||||
#else
|
||||
struct timeval tv;
|
||||
if( gettimeofday(&tv,NULL) != 0 )
|
||||
return 0;
|
||||
return ( tv.tv_sec + ((double)tv.tv_usec) / 1000000.0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_cpu_time : void -> float
|
||||
<doc>Return the most accurate CPU time spent since the process started (in seconds)</doc>
|
||||
**/
|
||||
double _hx_std_sys_cpu_time()
|
||||
{
|
||||
#if defined(HX_WINRT) && !defined(_XBOX_ONE)
|
||||
return ((double)GetTickCount64()/1000.0);
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
FILETIME unused;
|
||||
FILETIME stime;
|
||||
FILETIME utime;
|
||||
if( !GetProcessTimes(GetCurrentProcess(),&unused,&unused,&stime,&utime) )
|
||||
return 0;
|
||||
return ( ((double)(utime.dwHighDateTime+stime.dwHighDateTime)) * 65.536 * 6.5536 + (((double)utime.dwLowDateTime + (double)stime.dwLowDateTime) / 10000000) );
|
||||
#elif defined(EPPC) || defined(KINC_CONSOLE)
|
||||
return ((double)clock()/(double)CLOCKS_PER_SEC);
|
||||
#else
|
||||
struct tms t;
|
||||
times(&t);
|
||||
return ( ((double)(t.tms_utime + t.tms_stime)) / CLK_TCK );
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_read_dir : string -> string list
|
||||
<doc>Return the content of a directory</doc>
|
||||
**/
|
||||
Array<String> _hx_std_sys_read_dir( String p )
|
||||
{
|
||||
Array<String> result = Array_obj<String>::__new();
|
||||
|
||||
#if defined(NEKO_WINDOWS)
|
||||
const wchar_t *path = p.wchar_str();
|
||||
size_t len = wcslen(path);
|
||||
if (len>MAX_PATH)
|
||||
return null();
|
||||
|
||||
WIN32_FIND_DATAW d;
|
||||
HANDLE handle;
|
||||
#if defined(HX_WINRT) && !defined(_XBOX_ONE)
|
||||
std::wstring tempWStr(path);
|
||||
std::string searchPath(tempWStr.begin(), tempWStr.end());
|
||||
#else
|
||||
wchar_t searchPath[ MAX_PATH + 4 ];
|
||||
memcpy(searchPath,path, len*sizeof(wchar_t));
|
||||
#endif
|
||||
|
||||
|
||||
if( len && path[len-1] != '/' && path[len-1] != '\\' )
|
||||
searchPath[len++] = '/';
|
||||
searchPath[len++] = '*';
|
||||
searchPath[len++] = '.';
|
||||
searchPath[len++] = '*';
|
||||
searchPath[len] = '\0';
|
||||
|
||||
hx::EnterGCFreeZone();
|
||||
#if defined(HX_WINRT) && !defined(_XBOX_ONE)
|
||||
handle = FindFirstFileExA(searchPath.c_str(), FindExInfoStandard, &d, FindExSearchNameMatch, NULL, 0);
|
||||
#else
|
||||
handle = FindFirstFileW(searchPath,&d);
|
||||
#endif
|
||||
if( handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
return null();
|
||||
}
|
||||
while( true )
|
||||
{
|
||||
// skip magic dirs
|
||||
if( d.cFileName[0] != '.' || (d.cFileName[1] != 0 && (d.cFileName[1] != '.' || d.cFileName[2] != 0)) )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
result->push(String::create(d.cFileName));
|
||||
hx::EnterGCFreeZone();
|
||||
}
|
||||
if( !FindNextFileW(handle,&d) )
|
||||
break;
|
||||
}
|
||||
FindClose(handle);
|
||||
#elif !defined(EPPC) && !defined(KINC_CONSOLE)
|
||||
const char *name = p.utf8_str();
|
||||
hx::EnterGCFreeZone();
|
||||
DIR *d = opendir(name);
|
||||
if( d == NULL )
|
||||
{
|
||||
hx::ExitGCFreeZone();
|
||||
hx::Throw(HX_CSTRING("Invalid directory"));
|
||||
}
|
||||
while( true )
|
||||
{
|
||||
struct dirent *e = readdir(d);
|
||||
if( e == NULL )
|
||||
break;
|
||||
// skip magic dirs
|
||||
if( e->d_name[0] == '.' && (e->d_name[1] == 0 || (e->d_name[1] == '.' && e->d_name[2] == 0)) )
|
||||
continue;
|
||||
hx::ExitGCFreeZone();
|
||||
result->push( String::create(e->d_name) );
|
||||
hx::EnterGCFreeZone();
|
||||
}
|
||||
closedir(d);
|
||||
#endif
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
file_full_path : string -> string
|
||||
<doc>Return an absolute path from a relative one. The file or directory must exists</doc>
|
||||
**/
|
||||
String _hx_std_file_full_path( String path )
|
||||
{
|
||||
#if defined(HX_WINRT)
|
||||
return path;
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
wchar_t buf[MAX_PATH+1];
|
||||
hx::strbuf wbuf;
|
||||
if( GetFullPathNameW(path.wchar_str(&wbuf),MAX_PATH+1,buf,NULL) == 0 )
|
||||
return null();
|
||||
return String::create(buf);
|
||||
#elif defined(EPPC) || defined(KINC_CONSOLE)
|
||||
return path;
|
||||
#else
|
||||
char buf[PATH_MAX];
|
||||
hx::strbuf ubuf;
|
||||
if( realpath(path.utf8_str(&ubuf),buf) == NULL )
|
||||
return null();
|
||||
return String::create(buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_exe_path : void -> string
|
||||
<doc>Return the path of the executable</doc>
|
||||
**/
|
||||
String _hx_std_sys_exe_path()
|
||||
{
|
||||
#if defined(HX_WINRT) && defined(__cplusplus_winrt)
|
||||
Windows::ApplicationModel::Package^ package = Windows::ApplicationModel::Package::Current;
|
||||
Windows::Storage::StorageFolder^ installedLocation = package->InstalledLocation;
|
||||
return(String::create(installedLocation->Path->Data()));
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
wchar_t path[MAX_PATH];
|
||||
if( GetModuleFileNameW(NULL,path,MAX_PATH) == 0 )
|
||||
return null();
|
||||
return String::create(path);
|
||||
#elif defined(NEKO_MAC) && !defined(IPHONE) && !defined(APPLETV) && !defined(HX_APPLEWATCH)
|
||||
char path[PATH_MAX+1];
|
||||
uint32_t path_len = PATH_MAX;
|
||||
if( _NSGetExecutablePath(path, &path_len) )
|
||||
return null();
|
||||
return String::create(path);
|
||||
#elif defined(EPPC) || defined(KINC_CONSOLE)
|
||||
return HX_CSTRING("");
|
||||
#else
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int length = readlink("/proc/self/exe", path, sizeof(path));
|
||||
if( length < 0 )
|
||||
{
|
||||
const char *p = getenv("_");
|
||||
if (p)
|
||||
return String::create(p);
|
||||
return null();
|
||||
}
|
||||
path[length] = '\0';
|
||||
return String::create(path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(IPHONE) && !defined(APPLETV) && !defined(HX_APPLEWATCH)
|
||||
#ifdef NEKO_MAC
|
||||
#include <crt_externs.h>
|
||||
# define environ (*_NSGetEnviron())
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NEKO_WINDOWS
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
/**
|
||||
sys_env : void -> #list
|
||||
<doc>Return all the (key,value) pairs in the environment as a chained list</doc>
|
||||
**/
|
||||
Array<String> _hx_std_sys_env()
|
||||
{
|
||||
Array<String> result = Array_obj<String>::__new();
|
||||
#if !defined(HX_WINRT) && !defined(KINC_CONSOLE)
|
||||
char **e = environ;
|
||||
while( *e )
|
||||
{
|
||||
char *x = strchr(*e,'=');
|
||||
if( x == NULL )
|
||||
{
|
||||
e++;
|
||||
continue;
|
||||
}
|
||||
result->push(String::create(*e,(int)(x-*e)));
|
||||
result->push(String::create(x+1));
|
||||
e++;
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef HX_ANDROID
|
||||
#define tcsetattr(fd,opt,s) ioctl(fd,opt,s)
|
||||
#define tcgetattr(fd,s) ioctl(fd,TCGETS,s)
|
||||
|
||||
static __inline__ void inline_cfmakeraw(struct termios *s)
|
||||
{
|
||||
s->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
||||
s->c_oflag &= ~OPOST;
|
||||
s->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
||||
s->c_cflag &= ~(CSIZE|PARENB);
|
||||
s->c_cflag |= CS8;
|
||||
}
|
||||
|
||||
#define cfmakeraw inline_cfmakeraw
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
sys_getch : bool -> int
|
||||
<doc>Read a character from stdin with or without echo</doc>
|
||||
**/
|
||||
int _hx_std_sys_getch( bool b )
|
||||
{
|
||||
#if defined(HX_WINRT) || defined(EMSCRIPTEN) || defined(EPPC) || defined(KINC_CONSOLE) || defined(__FreeBSD__)
|
||||
return 0;
|
||||
#elif defined(NEKO_WINDOWS)
|
||||
hx::EnterGCFreeZone();
|
||||
int result = b?getche():getch();
|
||||
hx::ExitGCFreeZone();
|
||||
|
||||
return result;
|
||||
#else
|
||||
// took some time to figure out how to do that
|
||||
// without relying on ncurses, which clear the
|
||||
// terminal on initscr()
|
||||
int c;
|
||||
struct termios term, old;
|
||||
hx::EnterGCFreeZone();
|
||||
tcgetattr(fileno(stdin), &old);
|
||||
term = old;
|
||||
cfmakeraw(&term);
|
||||
tcsetattr(fileno(stdin), 0, &term);
|
||||
c = getchar();
|
||||
tcsetattr(fileno(stdin), 0, &old);
|
||||
if( b ) fputc(c,stdout);
|
||||
hx::ExitGCFreeZone();
|
||||
return c;
|
||||
# endif
|
||||
}
|
||||
|
||||
/**
|
||||
sys_get_pid : void -> int
|
||||
<doc>Returns the current process identifier</doc>
|
||||
**/
|
||||
int _hx_std_sys_get_pid()
|
||||
{
|
||||
# ifdef NEKO_WINDOWS
|
||||
return (int)(GetCurrentProcessId());
|
||||
#elif defined(EPPC) || defined(KINC_CONSOLE)
|
||||
return (1);
|
||||
# else
|
||||
return (getpid());
|
||||
# endif
|
||||
}
|
||||
42
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/zlib/Build.xml
Normal file
42
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/zlib/Build.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<xml>
|
||||
|
||||
<pragma once="true" />
|
||||
|
||||
<set name="ZLIB_DIR" value="${HXCPP}/project/thirdparty/zlib-1.2.13"/>
|
||||
|
||||
<files id="hxcpp_zlib" dir="${this_dir}" >
|
||||
<depend files="hxcpp-depends"/>
|
||||
<depend name="${this_dir}/Build.xml" dateOnly="true" />
|
||||
<cache value="true" asLibrary="1" />
|
||||
|
||||
<compilerflag value="-I${ZLIB_DIR}"/>
|
||||
<compilerflag value="-DSTDC" unless="windows" />
|
||||
<compilerflag value="-DHAVE_UNISTD_H" unless="windows" />
|
||||
|
||||
<file name="ZLib.cpp"/>
|
||||
|
||||
<!-- HXCPP_LINK_NO_ZLIB may be set too late, so use filterout as well. -->
|
||||
<section unless="HXCPP_LINK_NO_ZLIB" >
|
||||
<file name="${ZLIB_DIR}/adler32.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/compress.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/crc32.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/deflate.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/gzclose.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/gzlib.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/gzread.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/gzwrite.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/infback.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/inffast.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/inflate.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/inftrees.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/trees.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/uncompr.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
<file name="${ZLIB_DIR}/zutil.c" filterout="HXCPP_LINK_NO_ZLIB" />
|
||||
</section>
|
||||
</files>
|
||||
|
||||
<target id="haxe">
|
||||
<files id="hxcpp_zlib" />
|
||||
</target>
|
||||
|
||||
</xml>
|
||||
284
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/zlib/ZLib.cpp
Normal file
284
Kha/Backends/Kore-hxcpp/khacpp/src/hx/libs/zlib/ZLib.cpp
Normal file
@ -0,0 +1,284 @@
|
||||
#include <hxcpp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
/**
|
||||
<doc>
|
||||
<h1>ZLib</h1>
|
||||
<p>
|
||||
Give access to the popular ZLib compression library, used in several file
|
||||
formats such as ZIP and PNG.
|
||||
</p>
|
||||
</doc>
|
||||
**/
|
||||
|
||||
namespace {
|
||||
|
||||
struct ZipResult
|
||||
{
|
||||
inline ZipResult(bool inOk, bool inDone, int inRead, int inWrite)
|
||||
: ok(inOk)
|
||||
, done(inDone)
|
||||
, read(inRead)
|
||||
, write(inWrite) { }
|
||||
bool ok;
|
||||
bool done;
|
||||
int read;
|
||||
int write;
|
||||
};
|
||||
|
||||
struct ZStream : public hx::Object
|
||||
{
|
||||
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdZLib };
|
||||
|
||||
z_stream *z;
|
||||
bool isInflate;
|
||||
int flush;
|
||||
|
||||
void create(bool inIsInflate, int inParam)
|
||||
{
|
||||
isInflate = inIsInflate;
|
||||
flush = Z_NO_FLUSH;
|
||||
z = (z_stream*)malloc(sizeof(z_stream));
|
||||
memset(z,0,sizeof(z_stream));
|
||||
int err = 0;
|
||||
if (!isInflate)
|
||||
{
|
||||
if( (err = deflateInit(z,inParam)) != Z_OK )
|
||||
{
|
||||
free(z);
|
||||
z = 0;
|
||||
onError(err);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (err = inflateInit2(z,inParam)) != Z_OK )
|
||||
{
|
||||
free(z);
|
||||
z = 0;
|
||||
onError(err);
|
||||
}
|
||||
}
|
||||
|
||||
_hx_set_finalizer(this, finalize);
|
||||
}
|
||||
|
||||
static void finalize(Dynamic obj)
|
||||
{
|
||||
((ZStream *)(obj.mPtr))->destroy();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (z)
|
||||
{
|
||||
if (isInflate)
|
||||
inflateEnd(z);
|
||||
else
|
||||
deflateEnd(z);
|
||||
free(z);
|
||||
z = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ZipResult deflate(Array<unsigned char> src, int srcpos, Array<unsigned char> dest, int dstpos)
|
||||
{
|
||||
if( srcpos < 0 || dstpos < 0 )
|
||||
return ZipResult( 0,0,0,0 );
|
||||
|
||||
int slen = src->length - srcpos;
|
||||
int dlen = dest->length - dstpos;
|
||||
if( slen < 0 || dlen < 0 )
|
||||
return ZipResult( 0,0,0,0 );
|
||||
|
||||
z->next_in = (Bytef*)(&src[srcpos]);
|
||||
z->next_out = (Bytef*)(&dest[dstpos]);
|
||||
z->avail_in = slen;
|
||||
z->avail_out = dlen;
|
||||
int err = 0;
|
||||
if( (err = ::deflate(z,flush)) < 0 )
|
||||
onError(err);
|
||||
|
||||
z->next_in = 0;
|
||||
z->next_out = 0;
|
||||
return ZipResult( true, err == Z_STREAM_END, (int)(slen - z->avail_in), (int)(dlen - z->avail_out) );
|
||||
}
|
||||
|
||||
ZipResult inflate(Array<unsigned char> src, int srcpos, Array<unsigned char> dest, int dstpos)
|
||||
{
|
||||
int slen = src->length;
|
||||
int dlen = dest->length;
|
||||
|
||||
if( srcpos < 0 || dstpos < 0 )
|
||||
return ZipResult( 0,0,0,0 );
|
||||
slen -= srcpos;
|
||||
dlen -= dstpos;
|
||||
if( slen < 0 || dlen < 0 )
|
||||
return ZipResult( 0,0,0,0 );
|
||||
|
||||
z->next_in = (Bytef*)&src[srcpos];
|
||||
z->next_out = (Bytef*)&dest[dstpos];
|
||||
z->avail_in = slen;
|
||||
z->avail_out = dlen;
|
||||
int err = 0;
|
||||
if( (err = ::inflate(z,flush)) < 0 )
|
||||
onError(err);
|
||||
z->next_in = 0;
|
||||
z->next_out = 0;
|
||||
return ZipResult( true, err == Z_STREAM_END, (int)(slen - z->avail_in), (int)(dlen - z->avail_out) );
|
||||
}
|
||||
|
||||
int getDeflateBound(int inLength)
|
||||
{
|
||||
return deflateBound(z,inLength);
|
||||
}
|
||||
|
||||
void setFlushMode(String inMode)
|
||||
{
|
||||
if( inMode == HX_CSTRING("NO") )
|
||||
flush = Z_NO_FLUSH;
|
||||
else if( inMode==HX_CSTRING("SYNC"))
|
||||
flush = Z_SYNC_FLUSH;
|
||||
else if( inMode==HX_CSTRING("FULL"))
|
||||
flush = Z_FULL_FLUSH;
|
||||
else if( inMode==HX_CSTRING("FINISH"))
|
||||
flush = Z_FINISH;
|
||||
else if( inMode==HX_CSTRING("BLOCK"))
|
||||
flush = Z_BLOCK;
|
||||
}
|
||||
|
||||
|
||||
void onError(int inCode)
|
||||
{
|
||||
String message = HX_CSTRING("ZLib Error : ");
|
||||
if( z && z->msg )
|
||||
message += String(z->msg) + HX_CSTRING("(") + String(inCode) + HX_CSTRING(")");
|
||||
else
|
||||
message += String(inCode);
|
||||
hx::Throw(message);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
ZStream *GetDeflateStream(Dynamic inHandle)
|
||||
{
|
||||
ZStream *z = dynamic_cast<ZStream *>(inHandle.mPtr);
|
||||
if (!z || !z->z || z->isInflate)
|
||||
hx::Throw( HX_CSTRING("ZLib: Not a valid deflate stream"));
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
ZStream *GetInflateStream(Dynamic inHandle)
|
||||
{
|
||||
ZStream *z = dynamic_cast<ZStream *>(inHandle.mPtr);
|
||||
if (!z || !z->z || !z->isInflate)
|
||||
hx::Throw( HX_CSTRING("ZLib: Not a valid inflate stream"));
|
||||
return z;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
deflate_init : level:int -> 'dstream
|
||||
<doc>Open a compression stream with the given level of compression</doc>
|
||||
**/
|
||||
Dynamic _hx_deflate_init(int level)
|
||||
{
|
||||
ZStream *zStream = new ZStream;
|
||||
zStream->create(false, level);
|
||||
return zStream;
|
||||
}
|
||||
|
||||
/**
|
||||
deflate_buffer : 'dstream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int }
|
||||
**/
|
||||
Dynamic _hx_deflate_buffer(Dynamic handle, Array<unsigned char> src, int srcPos, Array<unsigned char> dest, int destPos)
|
||||
{
|
||||
ZipResult result = GetDeflateStream(handle)->deflate(src,srcPos,dest,destPos);
|
||||
if (!result.ok)
|
||||
return null();
|
||||
|
||||
return hx::Anon_obj::Create(3)
|
||||
->setFixed(0,HX_("write",df,6c,59,d0),result.write)
|
||||
->setFixed(1,HX_("done",82,f0,6d,42),result.done)
|
||||
->setFixed(2,HX_("read",56,4b,a7,4b),result.read);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
deflate_bound : 'dstream -> n:int -> int
|
||||
<doc>Return the maximum buffer size needed to write [n] bytes</doc>
|
||||
**/
|
||||
int _hx_deflate_bound(Dynamic handle,int length)
|
||||
{
|
||||
return GetDeflateStream(handle)->getDeflateBound(length);
|
||||
}
|
||||
|
||||
void _hx_deflate_end(Dynamic handle)
|
||||
{
|
||||
GetDeflateStream(handle)->destroy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
set_flush_mode : 'stream -> string -> void
|
||||
<doc>Change the flush mode ("NO","SYNC","FULL","FINISH","BLOCK")</doc>
|
||||
**/
|
||||
void _hx_zip_set_flush_mode(Dynamic handle, String flushMode)
|
||||
{
|
||||
ZStream *zstream = dynamic_cast<ZStream *>(handle.mPtr);
|
||||
if (!zstream || !zstream->z)
|
||||
hx::Throw( HX_CSTRING("ZLib flush: not a valid stream") );
|
||||
|
||||
zstream->setFlushMode(flushMode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
inflate_init : window_size:int? -> 'istream
|
||||
<doc>Open a decompression stream</doc>
|
||||
**/
|
||||
Dynamic _hx_inflate_init(Dynamic windowBits)
|
||||
{
|
||||
int bits = windowBits==null() ? MAX_WBITS : (int)windowBits;
|
||||
|
||||
ZStream *zStream = new ZStream();
|
||||
zStream->create(true, bits);
|
||||
return zStream;
|
||||
}
|
||||
|
||||
/**
|
||||
inflate_buffer : 'istream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int }
|
||||
**/
|
||||
Dynamic _hx_inflate_buffer(Dynamic handle, Array<unsigned char> src, int srcPos, Array<unsigned char> dest, int destPos)
|
||||
{
|
||||
ZipResult result = GetInflateStream(handle)->inflate(src,srcPos,dest,destPos);
|
||||
if (!result.ok)
|
||||
return null();
|
||||
|
||||
return hx::Anon_obj::Create(3)
|
||||
->setFixed(0,HX_("write",df,6c,59,d0),result.write)
|
||||
->setFixed(1,HX_("done",82,f0,6d,42),result.done)
|
||||
->setFixed(2,HX_("read",56,4b,a7,4b),result.read);
|
||||
}
|
||||
|
||||
/**
|
||||
inflate_end : 'istream -> void
|
||||
<doc>Close a decompression stream</doc>
|
||||
**/
|
||||
void _hx_inflate_end(Dynamic handle)
|
||||
{
|
||||
GetInflateStream(handle)->destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user