This commit is contained in:
Dante
2026-05-22 11:54:15 -07:00
parent 05f197c291
commit b47ea35fe4
935 changed files with 1016163 additions and 1 deletions

View 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)

View 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

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

View 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();
}
}

File diff suppressed because it is too large Load Diff

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

View 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));
}

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

View 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

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

View 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); }

View 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

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

View 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();
}
}
}

View 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);
}
}

View 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);
}

View 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);
}

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

File diff suppressed because it is too large Load Diff

View 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

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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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();
}

View 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)

View 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

View 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

View 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

View 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

View 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

View 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)

View File

@ -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

View File

@ -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

View File

@ -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();
}

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

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

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

View File

@ -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

View File

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

View File

@ -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

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

View 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 // }

View 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

File diff suppressed because it is too large Load Diff

View 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>

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

View 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);
}
/* ************************************************************************ */

View 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;
}
/* ************************************************************************ */

View 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
/* ************************************************************************ */

View 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
/* ************************************************************************ */

View 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);
}

View 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
/* ************************************************************************ */

View 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
}
/* ************************************************************************ */

View 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
/* ************************************************************************ */

View 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>

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

View File

@ -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>

View 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>

View 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);
}

View 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=&lt;mbedtls_config.h&gt;"/>
<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>

View 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

View File

@ -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

View File

@ -0,0 +1,6 @@
#include <windows.h>
typedef struct {
CRITICAL_SECTION cs;
char is_valid;
} mbedtls_threading_mutex_t;

View 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>

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

View 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( &quoted[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

View 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));
}

File diff suppressed because it is too large Load Diff

View 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
}

View 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>

View 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();
}