Update
This commit is contained in:
2192
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/ArrayBuiltin.cpp
Normal file
2192
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/ArrayBuiltin.cpp
Normal file
File diff suppressed because it is too large
Load Diff
972
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/ArrayVirtual.cpp
Normal file
972
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/ArrayVirtual.cpp
Normal file
@ -0,0 +1,972 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
#if (HXCPP_API_LEVEL>=330)
|
||||
#define BasePtr(x) x
|
||||
typedef cpp::VirtualArray_obj ArrayAnyImpl;
|
||||
#define CALL(x) x
|
||||
#else
|
||||
#define BasePtr(x) x.mPtr
|
||||
typedef ArrayBase ArrayAnyImpl;
|
||||
#define CALL(x) __##x
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static hx::Object * SLJIT_CALL objGetItem(hx::Object *inObj, int inIndex)
|
||||
{
|
||||
return inObj->__GetItem(inIndex).mPtr;
|
||||
}
|
||||
static int SLJIT_CALL arrayContains(ArrayAnyImpl *inObj, hx::Object *inValue)
|
||||
{
|
||||
return inObj->contains(inValue);
|
||||
}
|
||||
static int SLJIT_CALL arrayRemove(ArrayAnyImpl *inObj, hx::Object *inValue)
|
||||
{
|
||||
return inObj->remove(inValue);
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arrayConcat(ArrayAnyImpl *inObj, hx::Object *inValue)
|
||||
{
|
||||
return inObj->concat(Dynamic(inValue)).mPtr;
|
||||
}
|
||||
static void SLJIT_CALL arraySetSizeExact(ArrayAnyImpl *inObj, int inSize)
|
||||
{
|
||||
inObj->__SetSizeExact(inSize);
|
||||
}
|
||||
static void SLJIT_CALL arrayResize(ArrayAnyImpl *inObj, int inSize)
|
||||
{
|
||||
inObj->resize(inSize);
|
||||
}
|
||||
|
||||
|
||||
static hx::Object * SLJIT_CALL arraySplice(ArrayAnyImpl *inObj, hx::Object *a0, hx::Object *a1)
|
||||
{
|
||||
return inObj->splice( Dynamic(a0), Dynamic(a1) ).mPtr;
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arraySlice(ArrayAnyImpl *inObj, hx::Object *a0, hx::Object *a1)
|
||||
{
|
||||
return inObj->slice( Dynamic(a0), Dynamic(a1) ).mPtr;
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arrayPop(ArrayAnyImpl *inObj)
|
||||
{
|
||||
return inObj->pop().mPtr;
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arrayShift(ArrayAnyImpl *inObj)
|
||||
{
|
||||
return inObj->shift().mPtr;
|
||||
}
|
||||
|
||||
static void SLJIT_CALL runSort( ArrayAnyImpl *inArray, hx::Object *inFunc)
|
||||
{
|
||||
TRY_NATIVE
|
||||
inArray->sort( Dynamic(inFunc) );
|
||||
CATCH_NATIVE
|
||||
}
|
||||
static void SLJIT_CALL runReverse( ArrayAnyImpl *inArray)
|
||||
{
|
||||
inArray->reverse();
|
||||
}
|
||||
|
||||
static hx::Object * SLJIT_CALL runCopy( ArrayAnyImpl *inArray)
|
||||
{
|
||||
return (inArray->copy()).mPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SLJIT_CALL runJoin( ArrayAnyImpl *inArray, String *ioValue)
|
||||
{
|
||||
TRY_NATIVE
|
||||
*ioValue = inArray->join( *ioValue );
|
||||
CATCH_NATIVE
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int SLJIT_CALL arrayPushInt( ArrayAnyImpl *inArray, int inVal)
|
||||
{
|
||||
return inArray->push(inVal);
|
||||
}
|
||||
static int SLJIT_CALL arrayPushObject( ArrayAnyImpl *inArray, hx::Object *inVal)
|
||||
{
|
||||
return inArray->push(Dynamic(inVal));
|
||||
}
|
||||
static int SLJIT_CALL arrayPushFloat( ArrayAnyImpl *inArray, double *inVal)
|
||||
{
|
||||
return inArray->push(*inVal);
|
||||
}
|
||||
static int SLJIT_CALL arrayPushString( ArrayAnyImpl *inArray, String *inVal)
|
||||
{
|
||||
return inArray->push(*inVal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int SLJIT_CALL arraySetInt( ArrayAnyImpl *inArray, int inIndex, int inVal)
|
||||
{
|
||||
inArray->set(inIndex,inVal);
|
||||
return inVal;
|
||||
}
|
||||
static hx::Object * SLJIT_CALL arraySetObject( ArrayAnyImpl *inArray, int inIndex, hx::Object *inVal)
|
||||
{
|
||||
inArray->set(inIndex,Dynamic(inVal));
|
||||
return inVal;
|
||||
}
|
||||
static void SLJIT_CALL arraySetFloat( ArrayAnyImpl *inArray, int inIndex, double *inVal)
|
||||
{
|
||||
inArray->set(inIndex,*inVal);
|
||||
}
|
||||
static void SLJIT_CALL arraySetString( ArrayAnyImpl *inArray, int inIndex, String *inVal)
|
||||
{
|
||||
inArray->set(inIndex,*inVal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void SLJIT_CALL arrayUnshiftInt( ArrayAnyImpl *inArray, int inVal)
|
||||
{
|
||||
inArray->unshift(inVal);
|
||||
}
|
||||
static void SLJIT_CALL arrayUnshiftObject( ArrayAnyImpl *inArray, hx::Object *inVal)
|
||||
{
|
||||
inArray->unshift(Dynamic(inVal));
|
||||
}
|
||||
static void SLJIT_CALL arrayUnshiftFloat( ArrayAnyImpl *inArray, double *inVal)
|
||||
{
|
||||
inArray->unshift(*inVal);
|
||||
}
|
||||
|
||||
static void SLJIT_CALL arrayUnshiftString( ArrayAnyImpl *inArray, String *inVal)
|
||||
{
|
||||
inArray->unshift(*inVal);
|
||||
}
|
||||
|
||||
|
||||
static void SLJIT_CALL runBlit( JitMultiArg *inArgs)
|
||||
{
|
||||
// this, inDestElement, inSourceArray, inSourceElement, inElementCount
|
||||
ArrayAnyImpl *dest = (ArrayAnyImpl *)inArgs[0].obj;
|
||||
ArrayAnyImpl *src = (ArrayAnyImpl *)inArgs[2].obj;
|
||||
dest->blit( inArgs[1].ival, src, inArgs[3].ival, inArgs[4].ival );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
template<int FUNC,int OP>
|
||||
struct ArrayBuiltinAny : public ArrayBuiltinBase
|
||||
{
|
||||
|
||||
|
||||
|
||||
ArrayBuiltinAny(CppiaExpr *inSrc, CppiaExpr *inThisExpr, Expressions &ioExpressions)
|
||||
: ArrayBuiltinBase(inSrc,inThisExpr,ioExpressions)
|
||||
{
|
||||
}
|
||||
const char *getName() { return gArrayFuncNames[FUNC]; }
|
||||
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
if (FUNC==afPush)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object * val = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(push)(Dynamic(val));
|
||||
}
|
||||
if (FUNC==afContains)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object * val = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(contains)(val);
|
||||
}
|
||||
if (FUNC==afRemove)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object * val = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(remove)(val);
|
||||
}
|
||||
if (FUNC==afIndexOf)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object *a1 = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(indexOf)( a0, a1 );
|
||||
}
|
||||
if (FUNC==afLastIndexOf)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object *a1 = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(lastIndexOf)( a0, a1 );
|
||||
}
|
||||
|
||||
return Dynamic( runObject(ctx) );
|
||||
}
|
||||
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
return runInt(ctx);
|
||||
}
|
||||
|
||||
|
||||
::String runString(CppiaCtx *ctx)
|
||||
{
|
||||
if (FUNC==afJoin)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(join)( a0 );
|
||||
}
|
||||
|
||||
if (FUNC==afToString)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->toString();
|
||||
}
|
||||
|
||||
hx::Object *obj = runObject(ctx);
|
||||
return obj ? obj->toString() : ::String();
|
||||
}
|
||||
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
if (FUNC==afPush || FUNC==afContains || FUNC==afRemove || FUNC==afIndexOf || FUNC==afLastIndexOf)
|
||||
return Dynamic(runInt(ctx)).mPtr;
|
||||
|
||||
if (FUNC==afRemove)
|
||||
return Dynamic((bool)runInt(ctx)).mPtr;
|
||||
|
||||
if (FUNC==afJoin || FUNC==afToString)
|
||||
return Dynamic(runString(ctx)).mPtr;
|
||||
|
||||
if (FUNC==afSort || FUNC==afInsert || FUNC==afUnshift || FUNC==af__SetSizeExact || FUNC==afBlit)
|
||||
{
|
||||
runVoid(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
CPPIA_CHECK(thisVal);
|
||||
|
||||
if (FUNC==af__get)
|
||||
{
|
||||
int idx = args[0]->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->__GetItem(idx).mPtr;
|
||||
}
|
||||
if (FUNC==af__set)
|
||||
{
|
||||
int i = args[0]->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
if (OP==aoSet)
|
||||
{
|
||||
Dynamic val = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->__SetItem(i, val).mPtr;
|
||||
}
|
||||
|
||||
Dynamic orig = thisVal->__GetItem(i);
|
||||
CPPIA_CHECK(orig.mPtr);
|
||||
|
||||
Dynamic val = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
switch(OP)
|
||||
{
|
||||
case aoSet: break;
|
||||
|
||||
case aoAdd:
|
||||
val = orig + val;
|
||||
break;
|
||||
case aoMult:
|
||||
val = orig * val;
|
||||
break;
|
||||
case aoDiv:
|
||||
val = orig / val;
|
||||
break;
|
||||
case aoSub:
|
||||
val = orig - val;
|
||||
break;
|
||||
case aoAnd:
|
||||
val = orig->__ToInt() & val->__ToInt();
|
||||
break;
|
||||
case aoOr:
|
||||
val = orig->__ToInt() | val->__ToInt();
|
||||
break;
|
||||
case aoXOr:
|
||||
val = orig->__ToInt() ^ val->__ToInt();
|
||||
break;
|
||||
case aoShl:
|
||||
val = orig->__ToInt() << val->__ToInt();
|
||||
break;
|
||||
case aoShr:
|
||||
val = orig->__ToInt() >> val->__ToInt();
|
||||
break;
|
||||
case aoUShr:
|
||||
val = hx::UShr(orig,val);
|
||||
break;
|
||||
case aoMod:
|
||||
val = orig % val;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
return thisVal->__SetItem(i,val).mPtr;
|
||||
}
|
||||
if (FUNC==af__crement)
|
||||
{
|
||||
int i = args[0]->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
if (OP==coPreInc)
|
||||
return thisVal->__SetItem(i, thisVal->__GetItem(i) + 1).mPtr;
|
||||
if (OP==coPreDec)
|
||||
return thisVal->__SetItem(i, thisVal->__GetItem(i) - 1).mPtr;
|
||||
|
||||
Dynamic result = thisVal->__GetItem(i);
|
||||
if (OP==coPostDec)
|
||||
thisVal->__SetItem(i, thisVal->__GetItem(i) - 1);
|
||||
if (OP==coPostInc)
|
||||
thisVal->__SetItem(i, thisVal->__GetItem(i) + 1);
|
||||
return result.mPtr;
|
||||
}
|
||||
|
||||
if (FUNC==afPop)
|
||||
{
|
||||
return thisVal->CALL(pop)().mPtr;
|
||||
}
|
||||
if (FUNC==afShift)
|
||||
{
|
||||
return thisVal->CALL(shift)().mPtr;
|
||||
}
|
||||
|
||||
if (FUNC==afConcat)
|
||||
{
|
||||
Dynamic val = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(concat)(val).mPtr;
|
||||
}
|
||||
if (FUNC==afCopy)
|
||||
{
|
||||
return thisVal->CALL(copy)().mPtr;
|
||||
}
|
||||
if (FUNC==afSplice)
|
||||
{
|
||||
Dynamic pos = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic end = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(splice)(pos,end).mPtr;
|
||||
}
|
||||
if (FUNC==afSlice)
|
||||
{
|
||||
Dynamic pos = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic end = args[1]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(slice)(pos,end).mPtr;
|
||||
}
|
||||
if (FUNC==afMap)
|
||||
{
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(map)(a0).mPtr;
|
||||
}
|
||||
if (FUNC==afFilter)
|
||||
{
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
return thisVal->CALL(filter)(a0).mPtr;
|
||||
}
|
||||
|
||||
if (FUNC==afIterator)
|
||||
{
|
||||
return thisVal->CALL(iterator)().mPtr;
|
||||
}
|
||||
if (FUNC==afKeyValueIterator)
|
||||
{
|
||||
return thisVal->CALL(keyValueIterator)().mPtr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
void runVoid(CppiaCtx *ctx)
|
||||
{
|
||||
if (FUNC==afSort)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic a0 = args[0]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
|
||||
thisVal->CALL(sort)(a0);
|
||||
return;
|
||||
}
|
||||
if (FUNC==afInsert)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic pos = args[0]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic val = args[1]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
thisVal->CALL(insert)(pos, val);
|
||||
return;
|
||||
}
|
||||
if (FUNC==afUnshift)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic val = args[0]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
thisVal->CALL(unshift)(val);
|
||||
return;
|
||||
}
|
||||
if (FUNC==af__SetSizeExact)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
int size = args[0]->runInt(ctx);
|
||||
BCR_VCHECK;
|
||||
thisVal->__SetSizeExact(size);
|
||||
return;
|
||||
}
|
||||
if (FUNC==afBlit)
|
||||
{
|
||||
ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
int destElem = args[0]->runInt(ctx);
|
||||
BCR_VCHECK;
|
||||
Dynamic srcArray = args[1]->runObject(ctx);
|
||||
BCR_VCHECK;
|
||||
int srcElem = args[2]->runInt(ctx);
|
||||
BCR_VCHECK;
|
||||
int elemCount = args[3]->runInt(ctx);
|
||||
BCR_VCHECK;
|
||||
thisVal->blit(destElem, srcArray, srcElem, elemCount);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch(inlineGetType())
|
||||
{
|
||||
case etString:
|
||||
runString(ctx);
|
||||
return;
|
||||
case etInt:
|
||||
runInt(ctx);
|
||||
return;
|
||||
default:
|
||||
runObject(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
CppiaExpr *makeSetter(AssignOp op,CppiaExpr *inValue)
|
||||
{
|
||||
if (FUNC==af__get)
|
||||
{
|
||||
args.push_back(inValue);
|
||||
CppiaExpr *replace = 0;
|
||||
|
||||
switch(op)
|
||||
{
|
||||
case aoSet:
|
||||
replace = new ArrayBuiltinAny<af__set,aoSet>(this,thisExpr,args);
|
||||
break;
|
||||
case aoAdd:
|
||||
replace = new ArrayBuiltinAny<af__set,aoAdd>(this,thisExpr,args);
|
||||
break;
|
||||
case aoMult:
|
||||
replace = new ArrayBuiltinAny<af__set,aoMult>(this,thisExpr,args);
|
||||
break;
|
||||
case aoDiv:
|
||||
replace = new ArrayBuiltinAny<af__set,aoDiv>(this,thisExpr,args);
|
||||
break;
|
||||
case aoSub:
|
||||
replace = new ArrayBuiltinAny<af__set,aoSub>(this,thisExpr,args);
|
||||
break;
|
||||
case aoAnd:
|
||||
replace = new ArrayBuiltinAny<af__set,aoAnd>(this,thisExpr,args);
|
||||
break;
|
||||
case aoOr:
|
||||
replace = new ArrayBuiltinAny<af__set,aoOr>(this,thisExpr,args);
|
||||
break;
|
||||
case aoXOr:
|
||||
replace = new ArrayBuiltinAny<af__set,aoXOr>(this,thisExpr,args);
|
||||
break;
|
||||
case aoShl:
|
||||
replace = new ArrayBuiltinAny<af__set,aoShl>(this,thisExpr,args);
|
||||
break;
|
||||
case aoShr:
|
||||
replace = new ArrayBuiltinAny<af__set,aoShr>(this,thisExpr,args);
|
||||
break;
|
||||
case aoUShr:
|
||||
replace = new ArrayBuiltinAny<af__set,aoUShr>(this,thisExpr,args);
|
||||
break;
|
||||
case aoMod:
|
||||
replace = new ArrayBuiltinAny<af__set,aoMod>(this,thisExpr,args);
|
||||
break;
|
||||
|
||||
default: ;
|
||||
printf("make setter %d\n", op);
|
||||
throw "setter not implemented";
|
||||
}
|
||||
|
||||
delete this;
|
||||
return replace;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
CppiaExpr *makeCrement(CrementOp inOp)
|
||||
{
|
||||
if (FUNC==af__get)
|
||||
{
|
||||
CppiaExpr *replace = 0;
|
||||
|
||||
switch(inOp)
|
||||
{
|
||||
case coPreInc :
|
||||
replace = new ArrayBuiltinAny<af__crement,coPreInc>(this,thisExpr,args);
|
||||
break;
|
||||
case coPostInc :
|
||||
replace = new ArrayBuiltinAny<af__crement,coPostInc>(this,thisExpr,args);
|
||||
break;
|
||||
case coPreDec :
|
||||
replace = new ArrayBuiltinAny<af__crement,coPreDec>(this,thisExpr,args);
|
||||
break;
|
||||
case coPostDec :
|
||||
replace = new ArrayBuiltinAny<af__crement,coPostDec>(this,thisExpr,args);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return replace;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
inline ExprType inlineGetType()
|
||||
{
|
||||
switch(FUNC)
|
||||
{
|
||||
case afJoin:
|
||||
case afToString:
|
||||
return etString;
|
||||
|
||||
case afSort:
|
||||
case afInsert:
|
||||
case afUnshift:
|
||||
case af__SetSizeExact:
|
||||
case afBlit:
|
||||
return etVoid;
|
||||
|
||||
case afPush:
|
||||
case afContains:
|
||||
case afRemove:
|
||||
case afIndexOf:
|
||||
case afLastIndexOf:
|
||||
return etInt;
|
||||
|
||||
default:
|
||||
return etObject;
|
||||
}
|
||||
|
||||
return etObject;
|
||||
}
|
||||
ExprType getType() { return inlineGetType(); }
|
||||
|
||||
bool isBoolInt() { return FUNC==afRemove || FUNC==afContains; }
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
|
||||
static hx::Object * SLJIT_CALL runProcess( ArrayAnyImpl *inArray, hx::Object *inFunction)
|
||||
{
|
||||
TRY_NATIVE
|
||||
if (FUNC==afMap)
|
||||
{
|
||||
return inArray->map(inFunction).mPtr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return inArray->filter(inFunction).mPtr;
|
||||
}
|
||||
CATCH_NATIVE
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SLJIT_CALL runIndexOf( ArrayAnyImpl *inArray, hx::Object *inItem)
|
||||
{
|
||||
return inArray->indexOf(inItem);
|
||||
}
|
||||
|
||||
static int SLJIT_CALL runLastIndexOf( ArrayAnyImpl *inArray, hx::Object *inItem)
|
||||
{
|
||||
return inArray->lastIndexOf(inItem);
|
||||
}
|
||||
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest, ExprType destType)
|
||||
{
|
||||
JitTemp thisVal(compiler,etObject);
|
||||
if (FUNC!=afBlit)
|
||||
thisExpr->genCode(compiler,thisVal,etObject);
|
||||
|
||||
switch(FUNC)
|
||||
{
|
||||
case af__get:
|
||||
args[0]->genCode(compiler, sJitArg1, etInt);
|
||||
compiler->callNative( (void *)objGetItem, thisVal, sJitArg1.as(jtInt));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
break;
|
||||
|
||||
case afPop:
|
||||
compiler->callNative( (void *)arrayPop, thisVal);
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
break;
|
||||
|
||||
case afShift:
|
||||
compiler->callNative( (void *)arrayShift, thisVal);
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
break;
|
||||
|
||||
case afContains:
|
||||
args[0]->genCode(compiler, sJitArg1, etObject);
|
||||
compiler->callNative( (void *)arrayContains, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->convertReturnReg(etInt, inDest, destType,true);
|
||||
break;
|
||||
|
||||
case afRemove:
|
||||
args[0]->genCode(compiler, sJitArg1, etObject);
|
||||
compiler->callNative( (void *)arrayRemove, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->convertReturnReg(etInt, inDest, destType,true);
|
||||
break;
|
||||
|
||||
case afSplice:
|
||||
{
|
||||
JitTemp a0(compiler,etObject);
|
||||
args[0]->genCode(compiler, a0, etObject);
|
||||
args[1]->genCode(compiler, sJitArg2, etObject);
|
||||
compiler->callNative( (void *)arraySplice, thisVal, a0.as(jtPointer), sJitArg2.as(jtPointer));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
case afSlice:
|
||||
{
|
||||
JitTemp a0(compiler,etObject);
|
||||
args[0]->genCode(compiler, a0, etObject);
|
||||
args[1]->genCode(compiler, sJitArg2, etObject);
|
||||
compiler->callNative( (void *)arraySlice, thisVal, a0.as(jtPointer), sJitArg2.as(jtPointer));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
case afSort:
|
||||
{
|
||||
args[0]->genCode(compiler, sJitArg1, etObject);
|
||||
compiler->callNative( (void *)runSort, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->checkException();
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case afReverse:
|
||||
compiler->callNative( (void *)runReverse, thisVal);
|
||||
break;
|
||||
|
||||
case afCopy:
|
||||
compiler->callNative( (void *)runCopy, thisVal);
|
||||
compiler->convertReturnReg(etObject, inDest, destType );
|
||||
break;
|
||||
|
||||
case afMap:
|
||||
case afFilter:
|
||||
{
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtPointer), etObject);
|
||||
|
||||
compiler->callNative( (void *)runProcess, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->checkException();
|
||||
compiler->convertReturnReg(etObject, inDest, destType );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case afIndexOf:
|
||||
case afLastIndexOf:
|
||||
{
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtPointer), etObject);
|
||||
compiler->callNative( (void *)(FUNC==afIndexOf ? runIndexOf : runLastIndexOf), thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->convertReturnReg(etInt, inDest, destType );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case afJoin:
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
args[0]->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)runJoin, thisVal, value);
|
||||
compiler->checkException();
|
||||
compiler->convert(value,etString, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case afConcat:
|
||||
{
|
||||
args[0]->genCode(compiler, sJitArg1, etObject);
|
||||
compiler->callNative( (void *)arrayConcat, thisVal, sJitArg1.as(jtPointer));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
case af__SetSizeExact:
|
||||
{
|
||||
JitTemp thisVal(compiler,jtPointer);
|
||||
thisExpr->genCode(compiler, thisVal, etObject);
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arraySetSizeExact, thisVal, sJitArg1.as(jtInt));
|
||||
break;
|
||||
}
|
||||
|
||||
case afResize:
|
||||
{
|
||||
JitTemp thisVal(compiler,jtPointer);
|
||||
thisExpr->genCode(compiler, thisVal, etObject);
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arrayResize, thisVal, sJitArg1.as(jtInt));
|
||||
break;
|
||||
}
|
||||
|
||||
case afBlit:
|
||||
{
|
||||
|
||||
// this, inDestElement, inSourceArray, inSourceElement, inElementCount
|
||||
JitMultiArgs fargs(compiler, 5);
|
||||
thisExpr->genCode(compiler, fargs.arg(0,jtPointer), etObject);
|
||||
args[0]->genCode(compiler, fargs.arg(1,jtInt), etInt);
|
||||
args[1]->genCode(compiler, fargs.arg(2,jtPointer), etObject);
|
||||
args[2]->genCode(compiler, fargs.arg(3,jtInt), etInt);
|
||||
args[3]->genCode(compiler, fargs.arg(4,jtInt), etInt);
|
||||
compiler->callNative( (void *)runBlit, fargs );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case af__set:
|
||||
{
|
||||
JitTemp index(compiler,etInt);
|
||||
args[0]->genCode(compiler, index, etInt);
|
||||
|
||||
switch(args[1]->getType())
|
||||
{
|
||||
case etInt:
|
||||
args[1]->genCode(compiler, sJitArg2.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arraySetInt, thisVal, index, sJitArg2.as(jtInt));
|
||||
compiler->convertReturnReg(etInt, inDest, destType);
|
||||
break;
|
||||
case etFloat:
|
||||
{
|
||||
JitTemp value(compiler, jtFloat);
|
||||
args[1]->genCode(compiler, value, etFloat);
|
||||
compiler->callNative( (void *)arraySetFloat, thisVal, index, value);
|
||||
compiler->convert(value,etFloat, inDest, destType);
|
||||
}
|
||||
break;
|
||||
case etString:
|
||||
{
|
||||
JitTemp value(compiler, jtString);
|
||||
args[1]->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)arraySetString, thisVal, index, value);
|
||||
compiler->convert(value,etString, inDest, destType);
|
||||
}
|
||||
break;
|
||||
case etObject:
|
||||
args[1]->genCode(compiler, sJitArg2.as(jtPointer), etObject);
|
||||
compiler->callNative( (void *)arraySetObject, thisVal, index, sJitArg2.as(jtPointer));
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
break;
|
||||
default: ; //?
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case afPush:
|
||||
{
|
||||
switch(args[0]->getType())
|
||||
{
|
||||
case etInt:
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arrayPushInt, thisVal, sJitArg1.as(jtInt));
|
||||
break;
|
||||
case etFloat:
|
||||
{
|
||||
JitTemp value(compiler, jtFloat);
|
||||
args[0]->genCode(compiler, value, etFloat);
|
||||
compiler->callNative( (void *)arrayPushFloat, thisVal, value);
|
||||
}
|
||||
break;
|
||||
case etString:
|
||||
{
|
||||
JitTemp value(compiler, jtString);
|
||||
args[0]->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)arrayPushString, thisVal, value);
|
||||
}
|
||||
break;
|
||||
case etObject:
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtPointer), etObject);
|
||||
compiler->callNative( (void *)arrayPushObject, thisVal, sJitArg1.as(jtPointer));
|
||||
break;
|
||||
default: ; //?
|
||||
}
|
||||
compiler->convertReturnReg(etInt, inDest, destType);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case afUnshift:
|
||||
{
|
||||
switch(args[0]->getType())
|
||||
{
|
||||
case etInt:
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt);
|
||||
compiler->callNative( (void *)arrayUnshiftInt, thisVal, sJitArg1.as(jtInt));
|
||||
break;
|
||||
case etFloat:
|
||||
{
|
||||
JitTemp value(compiler, jtFloat);
|
||||
args[0]->genCode(compiler, value, etFloat);
|
||||
compiler->callNative( (void *)arrayUnshiftFloat, thisVal, value);
|
||||
}
|
||||
break;
|
||||
case etString:
|
||||
{
|
||||
JitTemp value(compiler, jtString);
|
||||
args[0]->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)arrayUnshiftString, thisVal, value);
|
||||
}
|
||||
break;
|
||||
case etObject:
|
||||
args[0]->genCode(compiler, sJitArg1.as(jtPointer), etObject);
|
||||
compiler->callNative( (void *)arrayUnshiftObject, thisVal, sJitArg1.as(jtPointer));
|
||||
break;
|
||||
default: ; //?
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
compiler->traceStrings("Unknown ArrayBuiltinAny:", getName() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<int FUNC>
|
||||
CppiaExpr *TCreateArrayAnyBuiltin(CppiaExpr *inSrc, CppiaExpr *thisExpr, Expressions &args, bool inUnsafe = false)
|
||||
{
|
||||
if (gArrayArgCount[FUNC]!=args.size())
|
||||
throw "Bad arg count for array builtin";
|
||||
|
||||
return new ArrayBuiltinAny<FUNC,(int)NoCrement::OP>(inSrc, thisExpr, args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CppiaExpr *createArrayAnyBuiltin(CppiaExpr *src, CppiaExpr *inThisExpr, String field, Expressions &ioExpressions )
|
||||
{
|
||||
if (field==HX_CSTRING("concat"))
|
||||
return TCreateArrayAnyBuiltin<afConcat>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("copy"))
|
||||
return TCreateArrayAnyBuiltin<afCopy>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("insert"))
|
||||
return TCreateArrayAnyBuiltin<afInsert>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("iterator"))
|
||||
return TCreateArrayAnyBuiltin<afIterator>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("keyValueIterator"))
|
||||
return TCreateArrayAnyBuiltin<afKeyValueIterator>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("join"))
|
||||
return TCreateArrayAnyBuiltin<afJoin>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("pop"))
|
||||
return TCreateArrayAnyBuiltin<afPop>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("push"))
|
||||
return TCreateArrayAnyBuiltin<afPush>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("contains"))
|
||||
return TCreateArrayAnyBuiltin<afContains>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("remove"))
|
||||
return TCreateArrayAnyBuiltin<afRemove>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("reverse"))
|
||||
return TCreateArrayAnyBuiltin<afReverse>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("shift"))
|
||||
return TCreateArrayAnyBuiltin<afShift>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("splice"))
|
||||
return TCreateArrayAnyBuiltin<afSplice>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("slice"))
|
||||
return TCreateArrayAnyBuiltin<afSlice>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("sort"))
|
||||
return TCreateArrayAnyBuiltin<afSort>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("toString"))
|
||||
return TCreateArrayAnyBuiltin<afToString>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("unshift"))
|
||||
return TCreateArrayAnyBuiltin<afUnshift>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("map"))
|
||||
return TCreateArrayAnyBuiltin<afMap>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("filter"))
|
||||
return TCreateArrayAnyBuiltin<afFilter>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("indexOf"))
|
||||
return TCreateArrayAnyBuiltin<afIndexOf>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("lastIndexOf"))
|
||||
return TCreateArrayAnyBuiltin<afLastIndexOf>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("__get") || field==HX_CSTRING("__unsafe_get"))
|
||||
return TCreateArrayAnyBuiltin<af__get>(src, inThisExpr, ioExpressions, field==HX_CSTRING("__unsafe_get"));
|
||||
if (field==HX_CSTRING("__set") || field==HX_CSTRING("__unsafe_set"))
|
||||
return TCreateArrayAnyBuiltin<af__set>(src, inThisExpr, ioExpressions, field==HX_CSTRING("__unsafe_set"));
|
||||
if (field==HX_CSTRING("__SetSizeExact"))
|
||||
return TCreateArrayAnyBuiltin<af__SetSizeExact>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("blit"))
|
||||
return TCreateArrayAnyBuiltin<afBlit>(src, inThisExpr, ioExpressions);
|
||||
if (field==HX_CSTRING("resize"))
|
||||
return TCreateArrayAnyBuiltin<afResize>(src, inThisExpr, ioExpressions);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
8318
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/Cppia.cpp
Normal file
8318
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/Cppia.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1227
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/Cppia.h
Normal file
1227
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/Cppia.h
Normal file
File diff suppressed because it is too large
Load Diff
1963
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaClasses.cpp
Normal file
1963
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaClasses.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1540
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCompiler.cpp
Normal file
1540
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCompiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
497
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCompiler.h
Normal file
497
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCompiler.h
Normal file
@ -0,0 +1,497 @@
|
||||
#ifndef HX_CPPIA_COMPILER_H_INCLUDED
|
||||
#define HX_CPPIA_COMPILER_H_INCLUDED
|
||||
|
||||
#if HXCPP_ARMV5
|
||||
#define SLJIT_CONFIG_ARM_V5 1
|
||||
#elif HXCPP_ARMV7
|
||||
#define SLJIT_CONFIG_ARM_V7 1
|
||||
#elif HXCPP_ARM64
|
||||
#define SLJIT_CONFIG_ARM_64 1
|
||||
#else
|
||||
#ifdef HXCPP_M64
|
||||
#define SLJIT_CONFIG_X86_64 1
|
||||
#else
|
||||
#define SLJIT_CONFIG_X86_32 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SLJIT_UTIL_STACK 0
|
||||
|
||||
#include "sljit_src/sljitLir.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define TRY_NATIVE try {
|
||||
#define CATCH_NATIVE } catch(Dynamic e) { CppiaCtx::getCurrent()->exception = e.mPtr ? e.mPtr : Dynamic(String("",0)).mPtr; }
|
||||
|
||||
|
||||
extern "C" struct sljit_jump;
|
||||
extern "C" struct sljit_label;
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
enum JitPosition
|
||||
{
|
||||
jposDontCare,
|
||||
jposCtx,
|
||||
jposFrame,
|
||||
jposLocal,
|
||||
jposThis,
|
||||
jposArray,
|
||||
jposRegister,
|
||||
jposStar,
|
||||
jposStarReg,
|
||||
jposPointerVal,
|
||||
jposIntVal,
|
||||
//jposFloatVal,
|
||||
};
|
||||
|
||||
enum JitType
|
||||
{
|
||||
jtAny,
|
||||
jtPointer,
|
||||
jtString,
|
||||
jtFloat,
|
||||
jtFloat32,
|
||||
jtInt,
|
||||
jtByte,
|
||||
jtShort,
|
||||
jtVoid,
|
||||
jtUnknown,
|
||||
};
|
||||
|
||||
|
||||
JitType getJitType(ExprType inType);
|
||||
int getJitTypeSize(JitType inType);
|
||||
|
||||
|
||||
struct JitStringMultiArg
|
||||
{
|
||||
int length;
|
||||
const HX_CHAR *__s;
|
||||
};
|
||||
|
||||
// double-aligned
|
||||
union JitMultiArg
|
||||
{
|
||||
int ival;
|
||||
double dval;
|
||||
hx::Object *obj;
|
||||
JitStringMultiArg sval;
|
||||
};
|
||||
|
||||
struct JitVal
|
||||
{
|
||||
JitPosition position;
|
||||
JitType type;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int offset;
|
||||
unsigned short reg0;
|
||||
unsigned short reg1;
|
||||
};
|
||||
void *pVal;
|
||||
double dVal;
|
||||
int iVal;
|
||||
};
|
||||
|
||||
JitVal(JitType inType=jtVoid, size_t inOffset=0, JitPosition inPosition=jposDontCare,int inReg0=0, int inReg1=0)
|
||||
{
|
||||
position = inPosition;
|
||||
type = inType;
|
||||
offset = (int)inOffset;
|
||||
reg0 = inReg0;
|
||||
reg1 = inReg1;
|
||||
}
|
||||
JitVal(int inValue)
|
||||
{
|
||||
offset = 0;
|
||||
reg0 = 0;
|
||||
reg1 = 0;
|
||||
position = jposIntVal;
|
||||
type = jtInt;
|
||||
iVal = inValue;
|
||||
}
|
||||
/*
|
||||
JitVal(double inValue)
|
||||
{
|
||||
offset = 0;
|
||||
reg0 = 0;
|
||||
reg1 = 0;
|
||||
position = jposFloatVal;
|
||||
type = jtFloat;
|
||||
dVal = inValue;
|
||||
}
|
||||
*/
|
||||
JitVal(void *inValue)
|
||||
{
|
||||
offset = 0;
|
||||
reg0 = 0;
|
||||
reg1 = 0;
|
||||
position = jposPointerVal;
|
||||
type = jtPointer;
|
||||
pVal = inValue;
|
||||
}
|
||||
|
||||
bool uses(int reg) const
|
||||
{
|
||||
return ( (position==jposRegister || position==jposStar || position==jposStar || position==jposStarReg) && reg==reg0 ) ||
|
||||
( position==jposStarReg && reg==reg1 );
|
||||
}
|
||||
|
||||
JitVal operator +(size_t inDiff) const { return JitVal(type, offset+inDiff, position, reg0, reg1); }
|
||||
JitVal as(JitType type) const { return JitVal(type, offset, position, reg0, reg1); }
|
||||
bool valid() const { return type!=jtVoid; }
|
||||
|
||||
bool operator==(const JitVal &inOther) const
|
||||
{
|
||||
return position==inOther.position && type==inOther.type && offset==inOther.offset && reg0==inOther.reg0 && reg1==inOther.reg1;
|
||||
}
|
||||
bool operator!=(const JitVal &inOther) const { return !(*this == inOther); }
|
||||
|
||||
JitVal getReg() const { return JitVal(jtPointer, 0, jposRegister, reg0, reg1); }
|
||||
|
||||
|
||||
private:
|
||||
JitVal(const JitType &);
|
||||
JitVal(const ExprType &);
|
||||
};
|
||||
|
||||
struct JitReg : public JitVal
|
||||
{
|
||||
JitReg(int inReg, JitType inType=jtAny) : JitVal(inType, 0, jposRegister, inReg, 0) { }
|
||||
|
||||
JitVal star(JitType inType=jtPointer, int inOffset=0) { return JitVal(inType, inOffset, jposStar, reg0, reg1); }
|
||||
JitVal star(ExprType inType, int inOffset=0) { return JitVal(getJitType(inType), inOffset, jposStar, reg0, reg1); }
|
||||
JitVal atReg(JitReg inReg, int inShift=0, JitType inType=jtAny) {
|
||||
return JitVal(inType, inShift, jposStarReg, reg0, inReg.reg0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern int sFrameReg;
|
||||
struct JitFramePos : public JitVal
|
||||
{
|
||||
JitFramePos(int inOffset, JitType inType=jtPointer) : JitVal(inType, inOffset, jposFrame, sFrameReg) { }
|
||||
JitFramePos(int inOffset, ExprType inType) : JitVal(getJitType(inType), inOffset, jposFrame, sFrameReg) { }
|
||||
};
|
||||
|
||||
extern int sLocalReg;
|
||||
struct JitLocalPos : public JitVal
|
||||
{
|
||||
JitLocalPos(int inOffset, JitType inType=jtPointer) : JitVal(inType, inOffset, jposLocal, sLocalReg) { }
|
||||
};
|
||||
|
||||
extern int sThisReg;
|
||||
struct JitThisPos : public JitVal
|
||||
{
|
||||
JitThisPos(int inOffset, JitType inType=jtPointer) : JitVal(inType, inOffset, jposThis, sThisReg) { }
|
||||
};
|
||||
|
||||
|
||||
enum JitCompare
|
||||
{
|
||||
// Pointer compare / String compare
|
||||
cmpP_EQUAL = 0,
|
||||
cmpP_ZERO = 0,
|
||||
cmpP_NOT_EQUAL = 1,
|
||||
cmpP_NOT_ZERO = 1,
|
||||
|
||||
cmpP_LESS = 2,
|
||||
cmpP_GREATER_EQUAL = 3,
|
||||
cmpP_GREATER = 4,
|
||||
cmpP_LESS_EQUAL = 5,
|
||||
cmpP_SIG_LESS = 6,
|
||||
cmpP_SIG_GREATER_EQUAL = 7,
|
||||
cmpP_SIG_GREATER = 8,
|
||||
cmpP_SIG_LESS_EQUAL = 9,
|
||||
|
||||
cmpP_OVERFLOW = 10,
|
||||
cmpP_NOT_OVERFLOW = 11,
|
||||
|
||||
cmpP_MUL_OVERFLOW = 12,
|
||||
cmpP_MUL_NOT_OVERFLOW = 13,
|
||||
|
||||
|
||||
// Integer compares
|
||||
cmpI_EQUAL = 0 | 0x100,
|
||||
cmpI_ZERO = 0 | 0x100,
|
||||
cmpI_NOT_EQUAL = 1 | 0x100,
|
||||
cmpI_NOT_ZERO = 1 | 0x100,
|
||||
|
||||
cmpI_LESS = 2 | 0x100,
|
||||
cmpI_GREATER_EQUAL = 3 | 0x100,
|
||||
cmpI_GREATER = 4 | 0x100,
|
||||
cmpI_LESS_EQUAL = 5 | 0x100,
|
||||
cmpI_SIG_LESS = 6 | 0x100,
|
||||
cmpI_SIG_GREATER_EQUAL = 7 | 0x100,
|
||||
cmpI_SIG_GREATER = 8 | 0x100,
|
||||
cmpI_SIG_LESS_EQUAL = 9 | 0x100,
|
||||
|
||||
cmpI_OVERFLOW = 10 | 0x100,
|
||||
cmpI_NOT_OVERFLOW = 11 | 0x100,
|
||||
|
||||
cmpI_MUL_OVERFLOW = 12 | 0x100,
|
||||
cmpI_MUL_NOT_OVERFLOW = 13 | 0x100,
|
||||
|
||||
/* Floating point comparison types - double. */
|
||||
cmpD_EQUAL = 16,
|
||||
cmpD_NOT_EQUAL = 17,
|
||||
cmpD_LESS = 18,
|
||||
cmpD_GREATER_EQUAL = 19,
|
||||
cmpD_GREATER = 20,
|
||||
cmpD_LESS_EQUAL = 21,
|
||||
cmpD_UNORDERED = 22,
|
||||
cmpD_ORDERED = 23,
|
||||
|
||||
/* Floating point comparison types - single. */
|
||||
cmpS_EQUAL = 16 | 0x100,
|
||||
cmpS_NOT_EQUAL = 17 | 0x100,
|
||||
cmpS_LESS = 18 | 0x100,
|
||||
cmpS_GREATER_EQUAL = 19 | 0x100,
|
||||
cmpS_GREATER = 20 | 0x100,
|
||||
cmpS_LESS_EQUAL = 21 | 0x100,
|
||||
cmpS_UNORDERED = 22 | 0x100,
|
||||
cmpS_ORDERED = 23 | 0x100,
|
||||
|
||||
};
|
||||
|
||||
enum BitOp
|
||||
{
|
||||
bitOpAnd,
|
||||
bitOpOr,
|
||||
bitOpXOr,
|
||||
bitOpUSR,
|
||||
bitOpShiftL,
|
||||
bitOpShiftR,
|
||||
};
|
||||
|
||||
bool isMemoryVal(const JitVal &inVal);
|
||||
|
||||
extern JitReg sJitFrame;
|
||||
extern JitReg sJitThis;
|
||||
|
||||
extern JitReg sJitTemp0;
|
||||
extern JitReg sJitTemp1;
|
||||
extern JitReg sJitTemp2;
|
||||
|
||||
extern JitReg sJitTempF0;
|
||||
extern JitReg sJitTempF1;
|
||||
extern JitReg sJitTempF2;
|
||||
|
||||
extern JitReg sJitReturnReg;
|
||||
extern JitReg sJitArg0;
|
||||
extern JitReg sJitArg1;
|
||||
extern JitReg sJitArg2;
|
||||
extern JitReg sJitCtx;
|
||||
extern JitVal sJitCtxPointer;
|
||||
extern JitVal sJitCtxFrame;
|
||||
|
||||
typedef sljit_label *LabelId;
|
||||
typedef sljit_jump *JumpId;
|
||||
|
||||
typedef void (SLJIT_CALL *CppiaFunc)(CppiaCtx *inCtx);
|
||||
typedef void (*OnReturnFunc)(class CppiaCompiler *inCompiler, int stackSize);
|
||||
|
||||
typedef std::vector<JumpId> ThrowList;
|
||||
|
||||
|
||||
class CppiaCompiler
|
||||
{
|
||||
public:
|
||||
static CppiaCompiler *create(int inFrameSize);
|
||||
virtual ~CppiaCompiler() { }
|
||||
|
||||
static void freeCompiled(CppiaFunc inFunc);
|
||||
|
||||
virtual void setError(const char *inError) = 0;
|
||||
virtual void crash() = 0;
|
||||
|
||||
virtual int getCurrentFrameSize() = 0;
|
||||
virtual void restoreFrameSize(int inSize) = 0;
|
||||
virtual void addFrame(ExprType inType) = 0;
|
||||
virtual void freeTempSize(int inSize) = 0;
|
||||
virtual int allocTempSize(int size) = 0;
|
||||
virtual int allocTemp(JitType inType) = 0;
|
||||
virtual void freeTemp(JitType inType) = 0;
|
||||
|
||||
virtual JitVal addLocal(const char *inName, JitType inType) = 0;
|
||||
virtual JitVal functionArg(int inIndex) = 0;
|
||||
|
||||
|
||||
virtual void convert(const JitVal &inSrc, ExprType inSrcType, const JitVal &inTarget, ExprType inToType, bool asBool=false) = 0;
|
||||
virtual void convertResult(ExprType inSrcType, const JitVal &inTarget, ExprType inToType) = 0;
|
||||
virtual void convertReturnReg(ExprType inSrcType, const JitVal &inTarget, ExprType inToType, bool asBool=false) = 0;
|
||||
virtual void genVariantValueTemp0(int inOffset, const JitVal &inDest, ExprType destType) = 0;
|
||||
virtual void returnNull(const JitVal &inTarget, ExprType inToType) = 0;
|
||||
|
||||
virtual void beginGeneration(int inArgs=1) = 0;
|
||||
virtual CppiaFunc finishGeneration() = 0;
|
||||
|
||||
virtual void setFunctionDebug() = 0;
|
||||
virtual void setLineDebug() = 0;
|
||||
|
||||
virtual LabelId setContinuePos(LabelId inNewPos) = 0;
|
||||
virtual void addContinue() = 0;
|
||||
virtual void swapBreakList(QuickVec<JumpId> &ioBreakList) = 0;
|
||||
virtual void addBreak() = 0;
|
||||
virtual void setBreakTarget() = 0;
|
||||
|
||||
virtual ThrowList *pushCatching(ThrowList *inCatching) = 0;
|
||||
virtual void popCatching(ThrowList *) = 0;
|
||||
virtual void addThrow() = 0;
|
||||
virtual void checkException() = 0;
|
||||
|
||||
// Unconditional
|
||||
virtual JumpId jump(LabelId inTo=0) = 0;
|
||||
virtual void jump(const JitVal &inWhere) = 0;
|
||||
// Conditional - int/pointer
|
||||
virtual JumpId compare(JitCompare condition, const JitVal &v0, const JitVal &v1, LabelId andJump=0) = 0;
|
||||
// Conditional - Float
|
||||
virtual JumpId fcompare(JitCompare condition, const JitVal &v0, const JitVal &v1, LabelId andJump, bool inReverse) = 0;
|
||||
// Conditional - String
|
||||
virtual JumpId scompare(JitCompare condition, const JitVal &v0, const JitVal &v1, LabelId andJump=0) = 0;
|
||||
// Link
|
||||
virtual void comeFrom(JumpId inWhere) = 0;
|
||||
virtual LabelId addLabel() = 0;
|
||||
|
||||
inline JumpId notNull(const JitVal &v0) { return compare(cmpP_NOT_ZERO, v0, (void *)0); }
|
||||
|
||||
virtual void setMaxPointer() = 0;
|
||||
|
||||
virtual int getBaseSize() = 0;
|
||||
virtual void setLineOffset( int inOffset ) = 0;
|
||||
virtual int getLineOffset( ) = 0;
|
||||
virtual void setOnReturn( OnReturnFunc inFunc, int inStackSize ) = 0;
|
||||
virtual void addReturn() = 0;
|
||||
|
||||
virtual void trace(const char *inValue) = 0;
|
||||
virtual void traceObject(const char *inLabel, const JitVal &inValue) = 0;
|
||||
virtual void tracePointer(const char *inLabel, const JitVal &inValue) = 0;
|
||||
virtual void traceFloat(const char *inLabel, const JitVal &inValue) = 0;
|
||||
virtual void traceStrings(const char *inS0, const char *inS1) = 0;
|
||||
virtual void traceInt(const char *inLabel, const JitVal &inValue) = 0;
|
||||
virtual void traceString(const char *inLabel, const JitVal &inValue) = 0;
|
||||
|
||||
virtual void negate(const JitVal &inDest, const JitVal &inSrc) = 0;
|
||||
virtual void add(const JitVal &inDest, const JitVal &v0, const JitVal &v1 ) = 0;
|
||||
virtual void bitOp(BitOp inOp, const JitVal &inDest, const JitVal &v0, const JitVal &v1 ) = 0;
|
||||
virtual void bitNot(const JitVal &inDest, const JitVal &v0 ) = 0;
|
||||
virtual void mult(const JitVal &inDest, const JitVal &v0, const JitVal &v1, bool asFloat ) = 0;
|
||||
virtual void sub(const JitVal &inDest, const JitVal &v0, const JitVal &v1, bool asFloat ) = 0;
|
||||
virtual void fdiv(const JitVal &inDest, const JitVal &v0, const JitVal &v1 ) = 0;
|
||||
virtual void divmod() = 0;
|
||||
virtual void move(const JitVal &inDest, const JitVal &src) = 0;
|
||||
//virtual void compare(Condition condition,const JitVal &v0, const JitVal &v1) = 0;
|
||||
|
||||
|
||||
//virtual void call(CppiaFunc func, JitType inReturnType=jtVoid)=0;
|
||||
//virtual void call(const JitVal &inFunc, JitType inReturnType=jtVoid)=0;
|
||||
virtual void call(const JitVal &inFunc, const JitVal &inArg0)=0;
|
||||
|
||||
virtual void callNative(void *func)=0;
|
||||
virtual void callNative(void *func, const JitVal &inArg0)=0;
|
||||
virtual void callNative(void *func, const JitVal &inArg0, const JitVal &inArg1)=0;
|
||||
virtual void callNative(void *func, const JitVal &inArg0, const JitVal &inArg1, const JitVal &inArg2)=0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct JitTemp : public JitVal
|
||||
{
|
||||
CppiaCompiler *compiler;
|
||||
int size;
|
||||
|
||||
JitTemp(CppiaCompiler *inCompiler, JitType inType)
|
||||
: JitVal(inType, inCompiler->allocTemp(inType), jposLocal, sLocalReg)
|
||||
{
|
||||
compiler = inCompiler;
|
||||
size = getJitTypeSize( inType );
|
||||
}
|
||||
|
||||
|
||||
JitTemp(CppiaCompiler *inCompiler, ExprType inType)
|
||||
: JitVal(getJitType(inType), inCompiler->allocTemp( getJitType(inType)), jposLocal, sLocalReg)
|
||||
{
|
||||
compiler = inCompiler;
|
||||
size = getJitTypeSize( getJitType(inType) );
|
||||
}
|
||||
|
||||
|
||||
JitTemp(CppiaCompiler *inCompiler, ExprType inType, int inSize)
|
||||
: JitVal(getJitType(inType), inCompiler->allocTempSize(inSize), jposLocal, sLocalReg)
|
||||
{
|
||||
compiler = inCompiler;
|
||||
size = inSize;
|
||||
}
|
||||
|
||||
|
||||
~JitTemp()
|
||||
{
|
||||
compiler->freeTempSize(size);
|
||||
}
|
||||
|
||||
JitVal star(JitType inType=jtPointer, size_t inOffset=0) { return JitVal(inType, offset+(int)inOffset, jposStar, sLocalReg, 0); }
|
||||
JitVal star(ExprType inType, size_t inOffset=0) { return JitVal(getJitType(inType), offset+(int)inOffset, jposStar, sLocalReg, 0); }
|
||||
|
||||
};
|
||||
|
||||
struct JitMultiArgs : public JitTemp
|
||||
{
|
||||
// Float, so address is passed to native function
|
||||
JitMultiArgs(CppiaCompiler *inCompiler, int inN) : JitTemp(inCompiler, etFloat, inN*sizeof(JitMultiArg) )
|
||||
{
|
||||
}
|
||||
|
||||
JitVal arg(int inIndex,JitType inType=jtPointer) { return (*this + inIndex*sizeof(JitMultiArg)).as(inType); }
|
||||
JitVal arg(int inIndex,ExprType inType) { return arg(inIndex,getJitType(inType)); }
|
||||
|
||||
};
|
||||
|
||||
struct JitSave
|
||||
{
|
||||
JitTemp temp;
|
||||
JitVal value;
|
||||
|
||||
JitSave(CppiaCompiler *compiler, const JitVal &val)
|
||||
: temp(compiler, val.type), value(val)
|
||||
{
|
||||
compiler->move(temp, value);
|
||||
}
|
||||
~JitSave()
|
||||
{
|
||||
temp.compiler->move(value,temp);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct AutoFramePos
|
||||
{
|
||||
CppiaCompiler *compiler;
|
||||
int framePos;
|
||||
|
||||
AutoFramePos(CppiaCompiler *inCompiler)
|
||||
{
|
||||
compiler = inCompiler;
|
||||
framePos=compiler->getCurrentFrameSize();
|
||||
}
|
||||
|
||||
~AutoFramePos()
|
||||
{
|
||||
compiler->restoreFrameSize(framePos);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// objVal - should not be sJitTemp1
|
||||
void genWriteBarrier(CppiaCompiler *compiler, JitReg objVal, JitVal valuePtr);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
137
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCtx.cpp
Normal file
137
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaCtx.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/Scriptable.h>
|
||||
#include <hx/GC.h>
|
||||
#include <hx/Thread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Cppia.h"
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
#ifdef DEBUG_RETURN_TYPE
|
||||
#define DEBUG_RETURN_TYPE_CHECK \
|
||||
if (gLastRet!=CHECK && CHECK!=etVoid) { printf("BAD RETURN TYPE, got %d, expected %d!\n",gLastRet,CHECK); CPPIA_CHECK(0); }
|
||||
#else
|
||||
#define DEBUG_RETURN_TYPE_CHECK
|
||||
#endif
|
||||
|
||||
|
||||
#define GET_RETURN_VAL(RET,CHECK) \
|
||||
((ScriptCallable *)vtable)->runFunction(this); \
|
||||
breakContReturn = 0; \
|
||||
DEBUG_RETURN_TYPE_CHECK \
|
||||
RET;
|
||||
|
||||
|
||||
void StackContext::runVoid(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return;
|
||||
GET_RETURN_VAL(return,etVoid);
|
||||
/* Reached end of routine without return */
|
||||
}
|
||||
|
||||
int StackContext::runInt(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return 0;
|
||||
GET_RETURN_VAL(return getInt(), etInt );
|
||||
//printf("No Int return?\n");
|
||||
// Should not really get here...
|
||||
return 0;
|
||||
}
|
||||
Float StackContext::runFloat(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return 0;
|
||||
GET_RETURN_VAL(return getFloat(),etFloat );
|
||||
// Should not really get here...
|
||||
//printf("No Float return?\n");
|
||||
return 0;
|
||||
}
|
||||
String StackContext::runString(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return String();
|
||||
GET_RETURN_VAL(return getString(),etString );
|
||||
// Should not really get here...
|
||||
//printf("No String return?\n");
|
||||
return null();
|
||||
}
|
||||
Dynamic StackContext::runObject(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return null();
|
||||
GET_RETURN_VAL(return getObject(),etObject );
|
||||
//printf("No Object return?\n");
|
||||
return null();
|
||||
}
|
||||
hx::Object *StackContext::runObjectPtr(void *vtable)
|
||||
{
|
||||
if (breakContReturn) return 0;
|
||||
GET_RETURN_VAL(return getObjectPtr(),etObject );
|
||||
//printf("No Object return?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int runContextConvertInt(StackContext *ctx, ExprType inType, void *inFunc)
|
||||
{
|
||||
switch(inType)
|
||||
{
|
||||
case etInt: return ctx->runInt(inFunc);
|
||||
case etFloat: return ctx->runFloat(inFunc);
|
||||
case etObject: return ctx->runObject(inFunc);
|
||||
default:
|
||||
ctx->runVoid(inFunc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Float runContextConvertFloat(StackContext *ctx, ExprType inType, void *inFunc)
|
||||
{
|
||||
switch(inType)
|
||||
{
|
||||
case etInt: return ctx->runInt(inFunc);
|
||||
case etFloat: return ctx->runFloat(inFunc);
|
||||
case etObject: return ctx->runObject(inFunc);
|
||||
default:
|
||||
ctx->runVoid(inFunc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
String runContextConvertString(StackContext *ctx, ExprType inType, void *inFunc)
|
||||
{
|
||||
switch(inType)
|
||||
{
|
||||
case etInt: return String(ctx->runInt(inFunc));
|
||||
case etFloat: return String(ctx->runFloat(inFunc));
|
||||
case etObject: return ctx->runObject(inFunc);
|
||||
case etString: return ctx->runString(inFunc);
|
||||
default:
|
||||
ctx->runVoid(inFunc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
hx::Object *runContextConvertObject(StackContext *ctx, ExprType inType, void *inFunc)
|
||||
{
|
||||
switch(inType)
|
||||
{
|
||||
case etInt: return Dynamic(ctx->runInt(inFunc)).mPtr;
|
||||
case etFloat: return Dynamic(ctx->runFloat(inFunc)).mPtr;
|
||||
case etObject: return ctx->runObject(inFunc).mPtr;
|
||||
case etString: return Dynamic(ctx->runString(inFunc)).mPtr;
|
||||
default:
|
||||
ctx->runVoid(inFunc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
1007
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaFunction.cpp
Normal file
1007
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaFunction.cpp
Normal file
File diff suppressed because it is too large
Load Diff
660
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaModule.cpp
Normal file
660
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaModule.cpp
Normal file
@ -0,0 +1,660 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
#include "CppiaStream.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
static int sScriptId = 0;
|
||||
|
||||
|
||||
const char **sgNativeNameSlots = 0;
|
||||
int sgNativeNameSlotCount = 0;
|
||||
|
||||
Array<Dynamic> gAllCppiaModules;
|
||||
|
||||
std::vector<hx::Resource> scriptResources;
|
||||
|
||||
|
||||
|
||||
// --- CppiaModule ----
|
||||
|
||||
CppiaModule::CppiaModule()
|
||||
{
|
||||
main = 0;
|
||||
layout = 0;
|
||||
creatingClass = 0;
|
||||
creatingFunction = 0;
|
||||
scriptId = ++sScriptId;
|
||||
strings = Array_obj<String>::__new(0,0);
|
||||
if (sgNativeNameSlotCount>0)
|
||||
for(int i=2;i<sgNativeNameSlotCount;i++)
|
||||
interfaceSlots[sgNativeNameSlots[i]] = i;
|
||||
|
||||
}
|
||||
|
||||
void CppiaModule::setDebug(CppiaExpr *outExpr, int inFileId, int inLine)
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (inFileId)
|
||||
allFileIds.insert(inFileId);
|
||||
#endif
|
||||
outExpr->className = creatingClass;
|
||||
outExpr->functionName = creatingFunction;
|
||||
//outExpr->filename = cStrings[inFileId].c_str();
|
||||
outExpr->filename = strings[inFileId].utf8_str();
|
||||
outExpr->line = inLine;
|
||||
}
|
||||
|
||||
|
||||
// --- CppiaModule -------------------------
|
||||
|
||||
CppiaModule::~CppiaModule()
|
||||
{
|
||||
delete main;
|
||||
for(int i=0;i<classes.size();i++)
|
||||
delete classes[i];
|
||||
}
|
||||
|
||||
void CppiaModule::link()
|
||||
{
|
||||
DBGLOG("Resolve registered - super\n");
|
||||
HaxeNativeClass::link();
|
||||
|
||||
DBGLOG("Resolve typeIds\n");
|
||||
for(int t=0;t<types.size();t++)
|
||||
types[t]->link(*this);
|
||||
|
||||
DBGLOG("Resolve inherited atributes\n");
|
||||
for(int i=0;i<classes.size();i++)
|
||||
{
|
||||
classes[i]->linkTypes();
|
||||
}
|
||||
|
||||
for(int i=0;i<classes.size();i++)
|
||||
{
|
||||
linkingClass = classes[i];
|
||||
classes[i]->link();
|
||||
}
|
||||
linkingClass = 0;
|
||||
|
||||
if (main)
|
||||
main = (ScriptCallable *)main->link(*this);
|
||||
}
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
void CppiaModule::compile()
|
||||
{
|
||||
for(int i=0;i<classes.size();i++)
|
||||
classes[i]->compile();
|
||||
|
||||
if (main)
|
||||
main->compile();
|
||||
}
|
||||
#endif
|
||||
|
||||
void addScriptableClass(String inName);
|
||||
void addScriptableFile(String inName);
|
||||
|
||||
void CppiaModule::registerDebugger()
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
for(int i=0;i<classes.size();i++)
|
||||
{
|
||||
String scriptable(classes[i]->name.c_str());
|
||||
addScriptableClass( scriptable.makePermanent().utf8_str() );
|
||||
}
|
||||
|
||||
for(hx::UnorderedSet<int>::const_iterator i = allFileIds.begin(); i!=allFileIds.end(); ++i)
|
||||
addScriptableFile(strings[*i]);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
CppiaClassInfo *CppiaModule::findClass( ::String inName)
|
||||
{
|
||||
|
||||
std::string stdName(inName.utf8_str());
|
||||
for(int i=0;i<classes.size();i++)
|
||||
if (classes[i]->name == stdName)
|
||||
return classes[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CppiaModule::mark(hx::MarkContext *__inCtx)
|
||||
{
|
||||
DBGLOG(" --- MARK --- \n");
|
||||
HX_MARK_MEMBER(strings);
|
||||
for(int i=0;i<types.size();i++)
|
||||
{
|
||||
if (types[i]) /* May be partially constructed */
|
||||
types[i]->mark(__inCtx);
|
||||
}
|
||||
for(int i=0;i<markable.size();i++)
|
||||
{
|
||||
markable[i]->mark(__inCtx);
|
||||
}
|
||||
for(int i=0;i<classes.size();i++)
|
||||
if (classes[i])
|
||||
{
|
||||
classes[i]->mark(__inCtx);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void CppiaModule::visit(hx::VisitContext *__inCtx)
|
||||
{
|
||||
HX_VISIT_MEMBER(strings);
|
||||
for(int i=0;i<types.size();i++)
|
||||
types[i]->visit(__inCtx);
|
||||
for(int i=0;i<markable.size();i++)
|
||||
markable[i]->visit(__inCtx);
|
||||
for(int i=0;i<classes.size();i++)
|
||||
if (classes[i])
|
||||
classes[i]->visit(__inCtx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void cppiaClassInit(CppiaClassInfo *inClass, CppiaCtx *ctx, int inPhase);
|
||||
|
||||
|
||||
|
||||
void CppiaModule::boot(CppiaCtx *ctx)
|
||||
{
|
||||
// boot (statics)
|
||||
for(int i=0;i<classes.size();i++)
|
||||
cppiaClassInit(classes[i],ctx,0);
|
||||
// run __init__
|
||||
for(int i=0;i<classes.size();i++)
|
||||
cppiaClassInit(classes[i],ctx,1);
|
||||
}
|
||||
|
||||
int CppiaModule::getInterfaceSlot(const std::string &inName)
|
||||
{
|
||||
InterfaceSlots::iterator it = interfaceSlots.find(inName);
|
||||
if (it==interfaceSlots.end())
|
||||
{
|
||||
#if (HXCPP_API_LEVEL >= 330)
|
||||
int result = interfaceSlots.size()+1;
|
||||
#else
|
||||
int result = interfaceSlots.size()+2;
|
||||
#endif
|
||||
interfaceSlots[inName] = result;
|
||||
return result;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
int CppiaModule::findInterfaceSlot(const std::string &inName)
|
||||
{
|
||||
InterfaceSlots::iterator it = interfaceSlots.find(inName);
|
||||
if (it==interfaceSlots.end())
|
||||
return -1;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CppiaModule::where(CppiaExpr *e)
|
||||
{
|
||||
if (linkingClass && layout)
|
||||
CPPIALOG(" in %s::%p\n", linkingClass->name.c_str(), layout);
|
||||
CPPIALOG(" %s at %s:%d %s\n", e->getName(), e->filename, e->line, e->functionName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ScriptableRegisterNameSlots(const char *inNames[], int inLength)
|
||||
{
|
||||
sgNativeNameSlots = inNames;
|
||||
sgNativeNameSlotCount = inLength;
|
||||
}
|
||||
|
||||
|
||||
// --- CppiaConst -------------------------------------------
|
||||
|
||||
CppiaConst::CppiaConst() : type(cNull), ival(0), dval(0) { }
|
||||
|
||||
void CppiaConst::fromStream(CppiaStream &stream)
|
||||
{
|
||||
std::string tok = stream.getToken();
|
||||
if (tok[0]=='i')
|
||||
{
|
||||
type = cInt;
|
||||
|
||||
dval = ival = stream.getInt();
|
||||
}
|
||||
else if (tok=="true")
|
||||
{
|
||||
type = cInt;
|
||||
dval = ival = 1;
|
||||
}
|
||||
else if (tok=="false")
|
||||
{
|
||||
type = cInt;
|
||||
dval = ival = 0;
|
||||
}
|
||||
else if (tok[0]=='f')
|
||||
{
|
||||
type = cFloat;
|
||||
int strIndex = stream.getInt();
|
||||
String val = stream.module->strings[strIndex];
|
||||
dval = atof(val.out_str());
|
||||
ival = dval;
|
||||
}
|
||||
else if (tok[0]=='s')
|
||||
{
|
||||
type = cString;
|
||||
ival = stream.getInt();
|
||||
}
|
||||
else if (tok=="NULL")
|
||||
type = cNull;
|
||||
else if (tok=="THIS")
|
||||
type = cThis;
|
||||
else if (tok=="SUPER")
|
||||
type = cSuper;
|
||||
else
|
||||
throw "unknown const value";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// --- CppiaLoadedModule -------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Cppia Object - manage
|
||||
class CppiaObject : public hx::CppiaLoadedModule_obj
|
||||
{
|
||||
public:
|
||||
CppiaModule *cppia;
|
||||
bool booted;
|
||||
|
||||
CppiaObject(CppiaModule *inModule)
|
||||
{
|
||||
cppia = inModule;
|
||||
GCSetFinalizer( this, onRelease );
|
||||
}
|
||||
static void onRelease(hx::Object *inObj)
|
||||
{
|
||||
delete ((CppiaObject *)inObj)->cppia;
|
||||
}
|
||||
void __Mark(hx::MarkContext *ctx) { cppia->mark(ctx); }
|
||||
#ifdef HXCPP_VISIT_ALLOCS
|
||||
void __Visit(hx::VisitContext *ctx) { cppia->visit(ctx); }
|
||||
#endif
|
||||
|
||||
|
||||
void boot()
|
||||
{
|
||||
if (booted)
|
||||
return;
|
||||
|
||||
booted = true;
|
||||
try
|
||||
{
|
||||
DBGLOG("--- Boot --------------------------------------------\n");
|
||||
CppiaCtx *ctx = CppiaCtx::getCurrent();
|
||||
cppia->boot(ctx);
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
String error(errorString);
|
||||
hx::Throw(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
if (!booted)
|
||||
boot();
|
||||
if (cppia->main)
|
||||
{
|
||||
try
|
||||
{
|
||||
//__hxcpp_enable(false);
|
||||
DBGLOG("--- Run --------------------------------------------\n");
|
||||
CppiaCtx *ctx = CppiaCtx::getCurrent();
|
||||
ctx->runVoid(cppia->main);
|
||||
if (ctx->exception)
|
||||
{
|
||||
hx::Object *e = ctx->exception;
|
||||
ctx->exception = 0;
|
||||
hx::Throw( Dynamic(e) );
|
||||
}
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
String error(errorString);
|
||||
hx::Throw(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::hx::Class resolveClass( ::String inName)
|
||||
{
|
||||
CppiaClassInfo *info = cppia->findClass(inName);
|
||||
if (info)
|
||||
return info->getClass();
|
||||
return null();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
CppiaLoadedModule LoadCppia(const unsigned char *inData, int inDataLength)
|
||||
{
|
||||
if (!gAllCppiaModules.mPtr)
|
||||
{
|
||||
gAllCppiaModules = Array_obj<Dynamic>::__new();
|
||||
GCAddRoot( (hx::Object **)&gAllCppiaModules.mPtr );
|
||||
}
|
||||
|
||||
CppiaModule *cppiaPtr = new CppiaModule();
|
||||
CppiaLoadedModule loadedModule = new CppiaObject(cppiaPtr);
|
||||
gAllCppiaModules->push(loadedModule);
|
||||
|
||||
|
||||
CppiaModule &cppia = *cppiaPtr;
|
||||
CppiaStream stream(cppiaPtr,inData, inDataLength);
|
||||
|
||||
String error;
|
||||
try
|
||||
{
|
||||
std::string tok = stream.getAsciiToken();
|
||||
if (tok!="CPPIA" && tok!="CPPIB")
|
||||
throw "Bad magic";
|
||||
|
||||
stream.setBinary(tok=="CPPIB");
|
||||
|
||||
int stringCount = stream.getAsciiInt();
|
||||
for(int s=0;s<stringCount;s++)
|
||||
cppia.strings[s] = stream.readString();
|
||||
|
||||
int typeCount = stream.getAsciiInt();
|
||||
cppia.types.resize(typeCount);
|
||||
DBGLOG("Type count : %d\n", typeCount);
|
||||
for(int t=0;t<typeCount;t++)
|
||||
cppia.types[t] = new TypeData(stream.readString());
|
||||
|
||||
int classCount = stream.getAsciiInt();
|
||||
DBGLOG("Class count : %d\n", classCount);
|
||||
|
||||
if (stream.binary)
|
||||
{
|
||||
int newLine = stream.getByte();
|
||||
if (newLine!='\n')
|
||||
throw "Missing new-line after class count";
|
||||
}
|
||||
|
||||
cppia.classes.reserve(classCount);
|
||||
for(int c=0;c<classCount;c++)
|
||||
{
|
||||
CppiaClassInfo *info = new CppiaClassInfo(cppia);
|
||||
if (info->load(stream))
|
||||
cppia.classes.push_back(info);
|
||||
}
|
||||
|
||||
tok = stream.getToken();
|
||||
if (tok=="MAIN")
|
||||
{
|
||||
DBGLOG("Main...\n");
|
||||
cppia.main = new ScriptCallable(createCppiaExpr(stream));
|
||||
cppia.main->className = "cppia";
|
||||
cppia.main->functionName = "__cppia_main";
|
||||
}
|
||||
else if (tok!="NOMAIN")
|
||||
throw "no main specified";
|
||||
|
||||
tok = stream.getToken();
|
||||
if (tok=="RESOURCES")
|
||||
{
|
||||
int count = stream.getInt( );
|
||||
scriptResources.resize(count+1);
|
||||
for(int r=0;r<count;r++)
|
||||
{
|
||||
tok = stream.getToken();
|
||||
if (tok!="RESO")
|
||||
throw "no reso tag";
|
||||
|
||||
scriptResources[r].mName = cppia.strings[stream.getInt()];
|
||||
scriptResources[r].mDataLength = stream.getInt();
|
||||
}
|
||||
if (!stream.binary)
|
||||
stream.skipChar();
|
||||
|
||||
for(int r=0;r<count;r++)
|
||||
{
|
||||
int len = scriptResources[r].mDataLength;
|
||||
unsigned char *buffer = (unsigned char *)malloc(len+5);
|
||||
*(unsigned int *)buffer = HX_GC_CONST_ALLOC_BIT;
|
||||
buffer[len+5-1] = '\0';
|
||||
stream.readBytes(buffer+4, len);
|
||||
#ifdef HX_SMART_STRINGS_1
|
||||
unsigned char *p = (unsigned char *)buffer+4;
|
||||
unsigned char *end = p + len;
|
||||
while(!hasBig && p<end)
|
||||
if (*p++>127)
|
||||
{
|
||||
*(unsigned int *)buffer |= HX_GC_STRING_CHAR16_T;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
scriptResources[r].mData = buffer + 4;
|
||||
}
|
||||
scriptResources[count].mDataLength = 0;
|
||||
scriptResources[count].mData = 0;
|
||||
scriptResources[count].mName = String();
|
||||
|
||||
RegisterResources(&scriptResources[0]);
|
||||
}
|
||||
else
|
||||
throw "no resources tag";
|
||||
|
||||
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
error = HX_CSTRING("Error reading file ") + String(errorString) +
|
||||
HX_CSTRING(", line ") + String(stream.line) + HX_CSTRING(", char ") +
|
||||
String(stream.pos);
|
||||
}
|
||||
|
||||
if (!error.raw_ptr())
|
||||
try
|
||||
{
|
||||
DBGLOG("Link...\n");
|
||||
cppia.link();
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
error = String(errorString);
|
||||
}
|
||||
|
||||
if (gEnableJit)
|
||||
{
|
||||
#ifdef CPPIA_JIT
|
||||
if (!error.raw_ptr())
|
||||
try
|
||||
{
|
||||
DBGLOG("Compile...\n");
|
||||
cppia.compile();
|
||||
}
|
||||
catch(const char *errorString)
|
||||
{
|
||||
error = String(errorString);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (error.raw_ptr())
|
||||
hx::Throw(error);
|
||||
|
||||
cppia.registerDebugger();
|
||||
|
||||
return loadedModule;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Array<String > gAllClasses;
|
||||
Array<String > gAllFiles;
|
||||
|
||||
void addScriptableClass(String inName)
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (!gAllClasses.mPtr)
|
||||
{
|
||||
gAllClasses = Array_obj<Dynamic>::__new();
|
||||
GCAddRoot( (hx::Object **)&gAllClasses.mPtr );
|
||||
}
|
||||
if (gAllClasses->indexOf(inName)<0)
|
||||
gAllClasses->push(inName);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void addScriptableFile(String inName)
|
||||
{
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
if (!gAllFiles.mPtr)
|
||||
{
|
||||
gAllFiles = Array_obj<Dynamic>::__new();
|
||||
GCAddRoot( (hx::Object **)&gAllFiles.mPtr );
|
||||
}
|
||||
if (gAllFiles->indexOf(inName)<0)
|
||||
gAllFiles->push(inName);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef HXCPP_STACK_SCRIPTABLE
|
||||
|
||||
void __hxcpp_dbg_getScriptableVariables(hx::StackFrame *inFrame, ::Array<Dynamic> outNames)
|
||||
{
|
||||
hx::ScriptCallable *callable = inFrame->position->scriptCallable;
|
||||
if (callable)
|
||||
callable->getScriptableVariables((unsigned char *)inFrame, outNames);
|
||||
}
|
||||
|
||||
bool __hxcpp_dbg_getScriptableValue(hx::StackFrame *inFrame, String inName, ::Dynamic &outValue)
|
||||
{
|
||||
hx::ScriptCallable *callable = inFrame->position->scriptCallable;
|
||||
if (callable)
|
||||
return callable->getScriptableValue((unsigned char *)inFrame, inName, outValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool __hxcpp_dbg_setScriptableValue(hx::StackFrame *inFrame, String inName, ::Dynamic inValue)
|
||||
{
|
||||
hx::ScriptCallable *callable = inFrame->position->scriptCallable;
|
||||
if (callable)
|
||||
return callable->setScriptableValue((unsigned char *)inFrame, inName, inValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef HXCPP_DEBUGGER
|
||||
void __hxcpp_dbg_getScriptableFiles( Array< ::String> ioPaths )
|
||||
{
|
||||
Array<String> merge = hx::gAllFiles;
|
||||
if (merge.mPtr)
|
||||
for(int i=0;i< merge->length; i++)
|
||||
{
|
||||
if (ioPaths->indexOf( merge[i] ) < 0)
|
||||
ioPaths->push( merge[i] );
|
||||
}
|
||||
}
|
||||
|
||||
void __hxcpp_dbg_getScriptableFilesFullPath( Array< ::String> ioPaths )
|
||||
{
|
||||
__hxcpp_dbg_getScriptableFiles( ioPaths );
|
||||
}
|
||||
|
||||
void __hxcpp_dbg_getScriptableClasses( Array< ::String> ioClasses )
|
||||
{
|
||||
Array<String> merge = hx::gAllClasses;
|
||||
if (merge.mPtr)
|
||||
for(int i=0;i< merge->length; i++)
|
||||
{
|
||||
if (ioClasses->indexOf( merge[i] ) < 0)
|
||||
ioClasses->push( merge[i] );
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
::hx::CppiaLoadedModule __scriptable_cppia_from_string(String inCode)
|
||||
{
|
||||
const unsigned char *code = (const unsigned char *)inCode.raw_ptr();
|
||||
int length = inCode.length;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (inCode.isUTF16Encoded())
|
||||
{
|
||||
code = (const unsigned char *)inCode.utf8_str();
|
||||
length = strlen( (const char *)code );
|
||||
}
|
||||
#endif
|
||||
|
||||
return hx::LoadCppia(code,length);
|
||||
}
|
||||
|
||||
|
||||
::hx::CppiaLoadedModule __scriptable_cppia_from_data(Array<unsigned char> inCode)
|
||||
{
|
||||
return hx::LoadCppia( (unsigned char *)inCode->GetBase() ,inCode->length);
|
||||
}
|
||||
|
||||
|
||||
void __scriptable_load_cppia(String inCode)
|
||||
{
|
||||
const unsigned char *code = (const unsigned char *)inCode.raw_ptr();
|
||||
int length = inCode.length;
|
||||
#ifdef HX_SMART_STRINGS
|
||||
if (inCode.isUTF16Encoded())
|
||||
{
|
||||
code = (const unsigned char *)inCode.utf8_str();
|
||||
length = strlen( (const char *)code );
|
||||
}
|
||||
#endif
|
||||
|
||||
::hx::CppiaLoadedModule module = hx::LoadCppia(code,length);
|
||||
|
||||
module->boot();
|
||||
module->run();
|
||||
}
|
||||
|
||||
118
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaOps.inc
Normal file
118
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaOps.inc
Normal file
@ -0,0 +1,118 @@
|
||||
|
||||
CPPIA_OP( IaFunction , "FUNCTION", 1)
|
||||
CPPIA_OP( IaVar , "VAR", 2)
|
||||
CPPIA_OP( IaToInterface , "TOINTERFACE", 3)
|
||||
CPPIA_OP( IaToDynArray , "TODYNARRAY", 4)
|
||||
CPPIA_OP( IaToDataArray , "TODATAARRAY", 5)
|
||||
CPPIA_OP( IaToInterfaceArray , "TOINTERFACEARRAY", 6)
|
||||
CPPIA_OP( IaFun , "FUN", 7)
|
||||
CPPIA_OP( IaCast , "CAST", 8)
|
||||
CPPIA_OP( IaBlock , "BLOCK", 9)
|
||||
CPPIA_OP( IaBreak , "BREAK", 10)
|
||||
CPPIA_OP( IaContinue , "CONTINUE", 11)
|
||||
CPPIA_OP( IaIsNull , "ISNULL", 12)
|
||||
CPPIA_OP( IaNotNull , "NOTNULL", 13)
|
||||
CPPIA_OP( IaSet , "SET", 14)
|
||||
CPPIA_OP( IaCall , "CALL", 15)
|
||||
CPPIA_OP( IaCallGlobal , "CALLGLOBAL", 16)
|
||||
CPPIA_OP( IaCallStatic , "CALLSTATIC", 17)
|
||||
CPPIA_OP( IaCallMember , "CALLMEMBER", 18)
|
||||
CPPIA_OP( IaCallSuper , "CALLSUPER", 19)
|
||||
CPPIA_OP( IaCallThis , "CALLTHIS", 20)
|
||||
CPPIA_OP( IaCallSuperNew , "CALLSUPERNEW", 21)
|
||||
CPPIA_OP( IaCreateEnum , "CREATEENUM", 22)
|
||||
CPPIA_OP( IaADef , "ADEF", 23)
|
||||
CPPIA_OP( IaIf , "IF", 24)
|
||||
CPPIA_OP( IaIfElse , "IFELSE", 25)
|
||||
CPPIA_OP( IaFName , "FNAME", 27)
|
||||
CPPIA_OP( IaFStatic , "FSTATIC", 28)
|
||||
CPPIA_OP( IaFThisInst , "FTHISINST", 29)
|
||||
CPPIA_OP( IaFLink , "FLINK", 30)
|
||||
CPPIA_OP( IaFThisName , "FTHISNAME", 31)
|
||||
CPPIA_OP( IaFEnum , "FENUM", 32)
|
||||
CPPIA_OP( IaThrow , "THROW", 33)
|
||||
CPPIA_OP( IaArrayI , "ARRAYI", 34)
|
||||
CPPIA_OP( IaPlusPlus , "++", 35)
|
||||
CPPIA_OP( IaPlusPlusPost , "+++", 36)
|
||||
CPPIA_OP( IaMinusMinus , "--", 37)
|
||||
CPPIA_OP( IaMinusMinusPost , "---", 38)
|
||||
CPPIA_OP( IaNeg , "NEG", 39)
|
||||
CPPIA_OP( IaBitNot , "~", 40)
|
||||
CPPIA_OP( IaLogicNot , "!", 41)
|
||||
CPPIA_OP( IaTVars , "TVARS", 42)
|
||||
CPPIA_OP( IaVarDecl , "VARDECL", 43)
|
||||
CPPIA_OP( IaVarDeclI , "VARDECLI", 44)
|
||||
CPPIA_OP( IaNew , "NEW", 45)
|
||||
CPPIA_OP( IaReturn , "RETURN", 46)
|
||||
CPPIA_OP( IaRetVal , "RETVAL", 47)
|
||||
CPPIA_OP( IaPosInfo , "POSINFO", 48)
|
||||
CPPIA_OP( IaObjDef , "OBJDEF", 49)
|
||||
CPPIA_OP( IaClassOf , "CLASSOF", 50)
|
||||
CPPIA_OP( IaWhile , "WHILE", 51)
|
||||
CPPIA_OP( IaFor , "FOR", 52)
|
||||
CPPIA_OP( IaEnumI , "ENUMI", 53)
|
||||
CPPIA_OP( IaSwitch , "SWITCH", 54)
|
||||
CPPIA_OP( IaTry , "TRY", 55)
|
||||
CPPIA_OP( IaImplDynamic , "IMPLDYNAMIC", 56)
|
||||
CPPIA_OP( IaConstInt , "i", 57)
|
||||
CPPIA_OP( IaConstFloat , "f", 58)
|
||||
CPPIA_OP( IaConstString , "s", 59)
|
||||
CPPIA_OP( IaConstFalse , "false", 60)
|
||||
CPPIA_OP( IaConstTrue , "true", 61)
|
||||
CPPIA_OP( IaConstNull , "NULL", 62)
|
||||
CPPIA_OP( IaConsThis , "THIS", 63)
|
||||
CPPIA_OP( IaConstSuper , "SUPER", 64)
|
||||
CPPIA_OP( IaCastInt , "CASTINT", 65)
|
||||
CPPIA_OP( IaCastBool , "CASTBOOL", 66)
|
||||
CPPIA_OP( IaInterface , "INTERFACE", 67)
|
||||
CPPIA_OP( IaClass , "CLASS", 68)
|
||||
CPPIA_OP( IaAccessNormal , "N", 69)
|
||||
CPPIA_OP( IaAccessNot , "n", 70)
|
||||
CPPIA_OP( IaAccessResolve , "R", 71)
|
||||
CPPIA_OP( IaAccessCall , "C", 72)
|
||||
CPPIA_OP( IaEnum , "ENUM", 73)
|
||||
CPPIA_OP( IaInline , "INLINE", 74)
|
||||
CPPIA_OP( IaMain , "MAIN", 75)
|
||||
CPPIA_OP( IaNoMain , "NOMAIN", 76)
|
||||
CPPIA_OP( IaResources , "RESOURCES", 77)
|
||||
CPPIA_OP( IaReso , "RESO", 78)
|
||||
CPPIA_OP( IaNoCast , "NOCAST", 79)
|
||||
CPPIA_OP( IaAccessCallNative , "V", 80)
|
||||
CPPIA_OP( IaBinOpAdd , "+", 101)
|
||||
CPPIA_OP( IaBinOpMult , "*", 102)
|
||||
CPPIA_OP( IaBinOpDiv , "/", 103)
|
||||
CPPIA_OP( IaBinOpSub , "-", 104)
|
||||
CPPIA_OP( IaBinOpAssign , "=", 105)
|
||||
CPPIA_OP( IaBinOpEq , "==", 106)
|
||||
CPPIA_OP( IaBinOpNotEq , "!=", 107)
|
||||
CPPIA_OP( IaBinOpGte , ">=", 108)
|
||||
CPPIA_OP( IaBinOpLte , "<=", 109)
|
||||
CPPIA_OP( IaBinOpGt , ">", 110)
|
||||
CPPIA_OP( IaBinOpLt , "<", 111)
|
||||
CPPIA_OP( IaBinOpAnd , "&", 112)
|
||||
CPPIA_OP( IaBinOpOr , "|", 113)
|
||||
CPPIA_OP( IaBinOpXor , "^", 114)
|
||||
CPPIA_OP( IaBinOpBoolAnd , "&&", 115)
|
||||
CPPIA_OP( IaBinOpBoolOr , "||", 116)
|
||||
CPPIA_OP( IaBinOpShr , ">>", 117)
|
||||
CPPIA_OP( IaBinOpUShr , ">>>", 118)
|
||||
CPPIA_OP( IaBinOpShl , "<<", 119)
|
||||
CPPIA_OP( IaBinOpMod , "%", 120)
|
||||
CPPIA_OP( IaBinOpInterval , "...", 121)
|
||||
CPPIA_OP( IaBinOpArrow , "=>", 122)
|
||||
CPPIA_OP( IaBinOpAssignAdd , "+=", 201)
|
||||
CPPIA_OP( IaBinOpAssignMult , "*=", 202)
|
||||
CPPIA_OP( IaBinOpAssignDiv , "/=", 203)
|
||||
CPPIA_OP( IaBinOpAssignSub , "-=", 204)
|
||||
CPPIA_OP( IaBinOpAssignAnd , "&=", 212)
|
||||
CPPIA_OP( IaBinOpAssignOr , "|=", 213)
|
||||
CPPIA_OP( IaBinOpAssignXor , "^=", 214)
|
||||
CPPIA_OP( IaBinOpAssignBoolAnd , "&&=", 215)
|
||||
CPPIA_OP( IaBinOpAssignBoolOr , "||=", 216)
|
||||
CPPIA_OP( IaBinOpAssignShr , ">>=", 217)
|
||||
CPPIA_OP( IaBinOpAssignUShr , ">>>=", 218)
|
||||
CPPIA_OP( IaBinOpAssignShl , "<<=", 219)
|
||||
CPPIA_OP( IaBinOpAssignMod , "%=", 220)
|
||||
CPPIA_OP( IaTCast , "TCAST", 221)
|
||||
|
||||
|
||||
214
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaStream.h
Normal file
214
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaStream.h
Normal file
@ -0,0 +1,214 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
struct CppiaStream
|
||||
{
|
||||
std::map<int,std::string> tokenMap;
|
||||
std::map<std::string,int> opMap;
|
||||
bool binary;
|
||||
class CppiaModule *module;
|
||||
const char *data;
|
||||
const char *max;
|
||||
int line;
|
||||
int pos;
|
||||
|
||||
CppiaStream(class CppiaModule *inModule,const unsigned char *inData, int inLen)
|
||||
{
|
||||
binary = false;
|
||||
module = inModule;
|
||||
data = (const char *)inData;
|
||||
max = data + inLen;
|
||||
line = 1;
|
||||
pos = 1;
|
||||
}
|
||||
|
||||
struct OpName { int id; const char *name; };
|
||||
void setBinary(bool inBinary)
|
||||
{
|
||||
binary = inBinary;
|
||||
OpName names[] = {
|
||||
#define CPPIA_OP(ident,name,id) { id, name },
|
||||
#include "CppiaOps.inc"
|
||||
#undef CPPIA_OP
|
||||
};
|
||||
if (binary)
|
||||
{
|
||||
for(int i=0;i<sizeof(names)/sizeof(names[0]);i++)
|
||||
{
|
||||
OpName &name = names[i];
|
||||
if (!tokenMap[name.id].empty())
|
||||
throw "Double identifier";
|
||||
tokenMap[ name.id ] = name.name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i=0;i<sizeof(names)/sizeof(names[0]);i++)
|
||||
{
|
||||
OpName &name = names[i];
|
||||
opMap[ name.name ] = name.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
void skipWhitespace()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
while(data<max && *data<=32)
|
||||
skipChar();
|
||||
if (data<max && *data=='#')
|
||||
{
|
||||
while(data<max && *data!='\n')
|
||||
skipChar();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
int getLineId()
|
||||
{
|
||||
return binary ? 0 : getInt();
|
||||
}
|
||||
int getFileId()
|
||||
{
|
||||
return binary ? 0 : getInt();
|
||||
}
|
||||
void skipChar()
|
||||
{
|
||||
if (data>=max)
|
||||
throw "EOF";
|
||||
if (*data=='\n')
|
||||
{
|
||||
line++;
|
||||
pos = 1;
|
||||
}
|
||||
else
|
||||
pos++;
|
||||
data++;
|
||||
}
|
||||
std::string getAsciiToken()
|
||||
{
|
||||
skipWhitespace();
|
||||
const char *data0 = data;
|
||||
while(data<max && *data>32)
|
||||
{
|
||||
data++;
|
||||
pos++;
|
||||
}
|
||||
return std::string(data0,data);
|
||||
}
|
||||
|
||||
|
||||
CppiaOp getOp()
|
||||
{
|
||||
if (binary)
|
||||
return (CppiaOp) getInt();
|
||||
std::string tok = getAsciiToken();
|
||||
CppiaOp result = (CppiaOp)opMap[tok];
|
||||
if (result==0)
|
||||
throw "Unknown token";
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::string getToken()
|
||||
{
|
||||
if (!binary)
|
||||
return getAsciiToken();
|
||||
int id = getInt();
|
||||
//printf("Token %s\n", tokenMap[id].c_str());
|
||||
return tokenMap[id];
|
||||
}
|
||||
|
||||
int getAsciiInt()
|
||||
{
|
||||
int result = 0;
|
||||
int sign = 1;
|
||||
skipWhitespace();
|
||||
while(data<max && *data>32)
|
||||
{
|
||||
if (*data=='-')
|
||||
sign = -1;
|
||||
else
|
||||
{
|
||||
int digit = *data - '0';
|
||||
if (digit<0 || digit>9)
|
||||
throw "expected digit";
|
||||
result = result * 10 + digit;
|
||||
}
|
||||
pos++;
|
||||
data++;
|
||||
}
|
||||
return result*sign;
|
||||
}
|
||||
|
||||
int getByte()
|
||||
{
|
||||
int result = *(unsigned char *)data;
|
||||
data++;
|
||||
pos++;
|
||||
return result;
|
||||
}
|
||||
int getInt()
|
||||
{
|
||||
if (!binary)
|
||||
return getAsciiInt();
|
||||
|
||||
int code = getByte();
|
||||
if (code<254)
|
||||
return code;
|
||||
if (code==254)
|
||||
{
|
||||
int result = getByte();
|
||||
result |= (getByte()<<8);
|
||||
return result;
|
||||
}
|
||||
|
||||
int result = getByte();
|
||||
result |= (getByte()<<8);
|
||||
result |= (getByte()<<16);
|
||||
result |= (getByte()<<24);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool getBool()
|
||||
{
|
||||
int ival = getInt();
|
||||
if (ival>1)
|
||||
throw "invalid bool";
|
||||
return ival;
|
||||
}
|
||||
bool getStatic()
|
||||
{
|
||||
return getBool();
|
||||
}
|
||||
|
||||
String readString(std::string *outStdStdString=0)
|
||||
{
|
||||
int len = getAsciiInt();
|
||||
skipChar();
|
||||
const char *data0 = data;
|
||||
int hasBig = false;
|
||||
for(int i=0;i<len;i++)
|
||||
skipChar();
|
||||
if (outStdStdString)
|
||||
*outStdStdString = std::string(data0, data);
|
||||
return String::createPermanent(data0,data-data0);
|
||||
}
|
||||
|
||||
void readBytes(unsigned char *outBytes, int inLen)
|
||||
{
|
||||
if (data+inLen>max)
|
||||
throw "EOF";
|
||||
memcpy(outBytes, data, inLen);
|
||||
data+=inLen;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
|
||||
680
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaVars.cpp
Normal file
680
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/CppiaVars.cpp
Normal file
@ -0,0 +1,680 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
#include "CppiaStream.h"
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
static int sTypeSize[] = { 0, 0, sizeof(hx::Object *), sizeof(String), sizeof(Float), sizeof(int) };
|
||||
|
||||
inline void AlignOffset(ExprType type, int &ioOffset)
|
||||
{
|
||||
#ifdef HXCPP_ALIGN_FLOAT
|
||||
if (type==etFloat && (ioOffset & 0x7) )
|
||||
ioOffset = (ioOffset + 7) & ~7;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
FieldStorage fieldStorageFromType(TypeData *inType)
|
||||
{
|
||||
if (!inType)
|
||||
return fsObject;
|
||||
|
||||
switch(inType->expressionType)
|
||||
{
|
||||
case etInt:
|
||||
if (inType->name==HX_CSTRING("Bool"))
|
||||
return fsBool;
|
||||
return fsInt;
|
||||
case etFloat: return fsFloat;
|
||||
case etString: return fsString;
|
||||
case etObject: return fsObject;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return fsUnknown;
|
||||
}
|
||||
|
||||
|
||||
// --- CppiaVar ----
|
||||
|
||||
CppiaVar::CppiaVar(bool inIsStatic) : isStatic(inIsStatic)
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
CppiaVar::CppiaVar(CppiaFunction *inDynamicFunction)
|
||||
{
|
||||
clear();
|
||||
isStatic = inDynamicFunction->isStatic;
|
||||
dynamicFunction = inDynamicFunction;
|
||||
nameId = dynamicFunction->nameId;
|
||||
exprType = etObject;
|
||||
storeType = fsObject;
|
||||
}
|
||||
|
||||
void CppiaVar::clear()
|
||||
{
|
||||
type = 0;
|
||||
nameId = 0;
|
||||
typeId = 0;
|
||||
offset = 0;
|
||||
type = 0;
|
||||
objVal.mPtr = 0;
|
||||
intVal = 0;
|
||||
stringVal = String();
|
||||
valPointer = 0;
|
||||
storeType = fsUnknown;
|
||||
dynamicFunction = 0;
|
||||
isVirtual = false;
|
||||
init = 0;
|
||||
}
|
||||
|
||||
void CppiaVar::load(CppiaStream &stream)
|
||||
{
|
||||
readAccess = getAccess(stream);
|
||||
writeAccess = getAccess(stream);
|
||||
isVirtual = stream.getBool();
|
||||
nameId = stream.getInt();
|
||||
typeId = stream.getInt();
|
||||
if (stream.getInt())
|
||||
init = createCppiaExpr(stream);
|
||||
}
|
||||
|
||||
|
||||
// Static...
|
||||
void CppiaVar::linkVarTypes(CppiaModule &cppia)
|
||||
{
|
||||
if (dynamicFunction)
|
||||
{
|
||||
nameId = dynamicFunction->nameId;
|
||||
}
|
||||
type = cppia.types[typeId];
|
||||
name = cppia.strings[nameId];
|
||||
exprType = typeId==0 ? etObject : type->expressionType;
|
||||
|
||||
if (!isVirtual)
|
||||
{
|
||||
storeType = typeId==0 ? fsObject : fieldStorageFromType(type);
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsBool: valPointer = &boolVal; break;
|
||||
case fsByte: valPointer = &byteVal; break;
|
||||
case fsInt: valPointer = &intVal; break;
|
||||
case fsFloat: valPointer = &floatVal; break;
|
||||
case fsString: valPointer = &stringVal; break;
|
||||
case fsObject: valPointer = &objVal; break;
|
||||
default:
|
||||
valPointer = 0;
|
||||
throw "Unkown store type";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CppiaVar::hasPointer()
|
||||
{
|
||||
return storeType==fsString || storeType==fsObject;
|
||||
}
|
||||
|
||||
|
||||
Dynamic CppiaVar::getStaticValue()
|
||||
{
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: return *(unsigned char *)(valPointer);
|
||||
case fsBool: return *(bool *)(valPointer);
|
||||
case fsInt: return *(int *)(valPointer);
|
||||
case fsFloat: return *(Float *)(valPointer);
|
||||
case fsString: return *(String *)(valPointer);
|
||||
case fsObject: return *(hx::Object **)(valPointer);
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
Dynamic CppiaVar::setStaticValue(Dynamic inValue)
|
||||
{
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: *(unsigned char *)(valPointer) = inValue; return inValue;
|
||||
case fsBool: *(bool *)(valPointer) = inValue; return inValue;
|
||||
case fsInt: *(int *)(valPointer) = inValue; return inValue;
|
||||
case fsFloat: *(Float *)(valPointer) = inValue; return inValue;
|
||||
case fsString: *(String *)(valPointer) = inValue; return inValue;
|
||||
case fsObject: *(hx::Object **)(valPointer) = inValue.mPtr; return inValue;
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
CppiaExpr *CppiaVar::createAccess(CppiaExpr *inSrc)
|
||||
{
|
||||
if (valPointer)
|
||||
return createStaticAccess(inSrc, storeType, valPointer);
|
||||
if (isVirtual)
|
||||
throw "Direct access to extern field";
|
||||
//throw "Unlinked static variable";
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CppiaVar::linkVarTypes(CppiaModule &cppia, int &ioOffset)
|
||||
{
|
||||
DBGLOG("linkVarTypes %p\n",dynamicFunction);
|
||||
if (dynamicFunction)
|
||||
{
|
||||
//dynamicFunction->linkTypes(cppia);
|
||||
nameId = dynamicFunction->nameId;
|
||||
}
|
||||
type = cppia.types[typeId];
|
||||
if (!isVirtual)
|
||||
{
|
||||
exprType = typeId==0 ? etObject : type->expressionType;
|
||||
AlignOffset(exprType, ioOffset);
|
||||
offset = ioOffset;
|
||||
|
||||
switch(exprType)
|
||||
{
|
||||
case etInt: ioOffset += sizeof(int); storeType=fsInt; break;
|
||||
case etFloat: ioOffset += sizeof(Float);storeType=fsFloat; break;
|
||||
case etString: ioOffset += sizeof(String);storeType=fsString; break;
|
||||
case etObject: ioOffset += sizeof(hx::Object *);storeType=fsObject; break;
|
||||
case etVoid:
|
||||
case etNull:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaVar::createDynamic(hx::Object *inBase)
|
||||
{
|
||||
*(hx::Object **)((char *)inBase+offset) = createMemberClosure(inBase,(ScriptCallable*)dynamicFunction->funExpr);
|
||||
}
|
||||
|
||||
|
||||
Dynamic CppiaVar::getValue(hx::Object *inThis)
|
||||
{
|
||||
char *base = ((char *)inThis) + offset;
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: return *(unsigned char *)(base);
|
||||
case fsInt: return *(int *)(base);
|
||||
case fsBool: return *(bool *)(base);
|
||||
case fsFloat: return *(Float *)(base);
|
||||
case fsString: return *(String *)(base);
|
||||
case fsObject: return *(hx::Object **)(base);
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
Dynamic CppiaVar::setValue(hx::Object *inThis, Dynamic inValue)
|
||||
{
|
||||
char *base = ((char *)inThis) + offset;
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: *(unsigned char *)(base) = inValue; return inValue;
|
||||
case fsInt: *(int *)(base) = inValue; return inValue;
|
||||
case fsBool: *(bool *)(base) = inValue; return inValue;
|
||||
case fsFloat: *(Float *)(base) = inValue; return inValue;
|
||||
case fsString: *(String *)(base) = inValue; return inValue;
|
||||
case fsObject:
|
||||
switch(type->arrayType)
|
||||
{
|
||||
case arrNotArray:
|
||||
*(hx::Object **)(base) = inValue.mPtr;
|
||||
break;
|
||||
case arrBool:
|
||||
*(Array<bool> *)(base) = inValue;
|
||||
break;
|
||||
case arrInt:
|
||||
*(Array<int> *)(base) = inValue;
|
||||
break;
|
||||
case arrFloat:
|
||||
*(Array<Float> *)(base) = inValue;
|
||||
break;
|
||||
case arrFloat32:
|
||||
*(Array<float> *)(base) = inValue;
|
||||
break;
|
||||
case arrUnsignedChar:
|
||||
*(Array<unsigned char> *)(base) = inValue;
|
||||
break;
|
||||
case arrString:
|
||||
*(Array<String> *)(base) = inValue;
|
||||
break;
|
||||
case arrAny:
|
||||
#if (HXCPP_API_LEVEL>=330)
|
||||
(*(cpp::VirtualArray *)base).setDynamic(inValue);
|
||||
break;
|
||||
#else
|
||||
// Fallthrough
|
||||
#endif
|
||||
case arrObject:
|
||||
*(Array<Dynamic> *)(base) = inValue;
|
||||
break;
|
||||
}
|
||||
return inValue;
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
void CppiaVar::link(CppiaModule &inModule)
|
||||
{
|
||||
if (dynamicFunction)
|
||||
dynamicFunction->link();
|
||||
type = inModule.types[typeId];
|
||||
exprType = typeId==0 ? etObject : type->expressionType;
|
||||
name = inModule.strings[nameId];
|
||||
|
||||
if (init)
|
||||
init = init->link(inModule);
|
||||
}
|
||||
|
||||
CppiaVar::Access CppiaVar::getAccess(CppiaStream &stream)
|
||||
{
|
||||
std::string tok = stream.getToken();
|
||||
if (tok.size()!=1)
|
||||
throw "bad var access length";
|
||||
switch(tok[0])
|
||||
{
|
||||
case 'N': return accNormal;
|
||||
case 'n': return accNo;
|
||||
case 'R': return accResolve;
|
||||
case 'C': return accCall;
|
||||
case 'V': return accCallNative;
|
||||
}
|
||||
throw "bad access code";
|
||||
return accNormal;
|
||||
}
|
||||
|
||||
void CppiaVar::runInit(CppiaCtx *ctx)
|
||||
{
|
||||
if (isStatic)
|
||||
{
|
||||
if (dynamicFunction)
|
||||
objVal = createMemberClosure(0,(ScriptCallable*)dynamicFunction->funExpr);
|
||||
else if (init)
|
||||
switch(storeType)
|
||||
{
|
||||
case fsBool: boolVal = init->runInt(ctx); break;
|
||||
case fsByte: byteVal = init->runInt(ctx); break;
|
||||
case fsInt: intVal = init->runInt(ctx); break;
|
||||
case fsFloat: floatVal = init->runFloat(ctx); break;
|
||||
case fsString: stringVal = init->runString(ctx); break;
|
||||
case fsObject: objVal = init->runObject(ctx); break;
|
||||
case fsUnknown: ; // ?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaVar::mark(hx::MarkContext *__inCtx)
|
||||
{
|
||||
HX_MARK_MEMBER(stringVal);
|
||||
HX_MARK_MEMBER(objVal);
|
||||
HX_MARK_MEMBER(name);
|
||||
}
|
||||
void CppiaVar::visit(hx::VisitContext *__inCtx)
|
||||
{
|
||||
HX_VISIT_MEMBER(stringVal);
|
||||
HX_VISIT_MEMBER(objVal);
|
||||
HX_VISIT_MEMBER(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --- CppiaStackVar ----
|
||||
|
||||
|
||||
std::map<int,int> sVarIdNameMap;
|
||||
|
||||
|
||||
int getStackVarNameId(int inVarId)
|
||||
{
|
||||
return sVarIdNameMap[inVarId];
|
||||
}
|
||||
|
||||
|
||||
|
||||
CppiaStackVar::CppiaStackVar()
|
||||
{
|
||||
nameId = 0;
|
||||
id = 0;
|
||||
capture = false;
|
||||
typeId = 0;
|
||||
defaultStackPos = -1;
|
||||
stackPos = 0;
|
||||
fromStackPos = 0;
|
||||
capturePos = 0;
|
||||
expressionType = etNull;
|
||||
argType = expressionType;
|
||||
storeType = fsUnknown;
|
||||
type = 0;
|
||||
module = 0;
|
||||
}
|
||||
|
||||
CppiaStackVar::CppiaStackVar(CppiaStackVar *inVar,int &ioSize, int &ioCaptureSize)
|
||||
{
|
||||
nameId = inVar->nameId;
|
||||
id = inVar->id;
|
||||
sVarIdNameMap[id] = nameId;
|
||||
capture = inVar->capture;
|
||||
typeId = inVar->typeId;
|
||||
type = inVar->type;
|
||||
expressionType = inVar->expressionType;
|
||||
argType = expressionType;
|
||||
defaultStackPos = -1;
|
||||
|
||||
fromStackPos = inVar->stackPos;
|
||||
storeType = inVar->storeType;
|
||||
stackPos = ioSize;
|
||||
capturePos = ioCaptureSize;
|
||||
ioSize += sTypeSize[expressionType];
|
||||
ioCaptureSize += sTypeSize[expressionType];
|
||||
module = inVar->module;
|
||||
}
|
||||
|
||||
|
||||
void CppiaStackVar::fromStream(CppiaStream &stream)
|
||||
{
|
||||
nameId = stream.getInt();
|
||||
id = stream.getInt();
|
||||
capture = stream.getBool();
|
||||
typeId = stream.getInt();
|
||||
}
|
||||
|
||||
void CppiaStackVar::setInFrame(unsigned char *inFrame,Dynamic inValue)
|
||||
{
|
||||
unsigned char *ptr = inFrame + stackPos;
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte:
|
||||
*(int *)(ptr) = (unsigned char)inValue;
|
||||
break;
|
||||
case fsBool:
|
||||
*(int *)(ptr) = (bool)inValue;
|
||||
break;
|
||||
case fsInt:
|
||||
*(int *)(ptr) = inValue;
|
||||
break;
|
||||
case fsFloat:
|
||||
SetFloatAligned(ptr,inValue);
|
||||
break;
|
||||
case fsString:
|
||||
*(String *)(ptr) = inValue;
|
||||
break;
|
||||
case fsObject:
|
||||
*(hx::Object **)(ptr) = inValue.mPtr;
|
||||
break;
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaStackVar::set(CppiaCtx *inCtx,Dynamic inValue)
|
||||
{
|
||||
setInFrame( inCtx->frame, inValue );
|
||||
}
|
||||
|
||||
|
||||
Dynamic CppiaStackVar::getInFrame(const unsigned char *inFrame)
|
||||
{
|
||||
const unsigned char *ptr = inFrame + stackPos;
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: return (unsigned char) *(int *)ptr;
|
||||
case fsBool: return (bool) *(int *)ptr;
|
||||
case fsInt: return *(int *)ptr;
|
||||
case fsFloat: return *(Float *)ptr;
|
||||
case fsString: return *(String *)ptr;
|
||||
case fsObject: return *(hx::Object **)ptr;
|
||||
case fsUnknown:
|
||||
break;
|
||||
}
|
||||
return null();
|
||||
}
|
||||
|
||||
|
||||
void CppiaStackVar::markClosure(char *inBase, hx::MarkContext *__inCtx)
|
||||
{
|
||||
switch(storeType)
|
||||
{
|
||||
case fsString:
|
||||
HX_MARK_MEMBER(*(String *)(inBase + capturePos));
|
||||
break;
|
||||
case fsObject:
|
||||
HX_MARK_MEMBER(*(hx::Object **)(inBase + capturePos));
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaStackVar::visitClosure(char *inBase, hx::VisitContext *__inCtx)
|
||||
{
|
||||
switch(storeType)
|
||||
{
|
||||
case fsString:
|
||||
HX_VISIT_MEMBER(*(String *)(inBase + capturePos));
|
||||
break;
|
||||
case fsObject:
|
||||
HX_VISIT_MEMBER(*(hx::Object **)(inBase + capturePos));
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaStackVar::link(CppiaModule &inModule, bool hasDefault)
|
||||
{
|
||||
expressionType = inModule.types[typeId]->expressionType;
|
||||
argType = hasDefault ? ( expressionType==etString ? etString : etObject) : expressionType;
|
||||
storeType = typeId==0 ? fsObject : fieldStorageFromType(inModule.types[typeId]);
|
||||
if (inModule.layout)
|
||||
{
|
||||
inModule.layout->varMap[id] = this;
|
||||
stackPos = inModule.layout->size;
|
||||
inModule.layout->size += sTypeSize[argType];
|
||||
}
|
||||
else
|
||||
{
|
||||
stackPos = -1;
|
||||
storeType = fsUnknown;
|
||||
}
|
||||
type = inModule.types[typeId];
|
||||
defaultStackPos =stackPos;
|
||||
module = &inModule;
|
||||
}
|
||||
|
||||
|
||||
void CppiaStackVar::linkDefault()
|
||||
{
|
||||
if (expressionType==etFloat && sizeof(double)>sizeof(hx::Object *) )
|
||||
{
|
||||
stackPos = module->layout->size;
|
||||
module->layout->size += sTypeSize[expressionType];
|
||||
}
|
||||
}
|
||||
|
||||
void CppiaStackVar::setDefault(CppiaCtx *inCxt, const CppiaConst &inDefault)
|
||||
{
|
||||
if (argType==etString)
|
||||
{
|
||||
if (inDefault.type == CppiaConst::cString)
|
||||
{
|
||||
String *s = (String *)(inCxt->frame + defaultStackPos);
|
||||
if (!s->raw_ptr())
|
||||
*s = module->strings[ inDefault.ival ];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hx::Object *src = *(hx::Object **)(inCxt->frame + defaultStackPos);
|
||||
|
||||
if (src)
|
||||
{
|
||||
setInFrame(inCxt->frame, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *ptr = inCxt->frame + stackPos;
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte: *(int *)ptr = (unsigned char)inDefault.ival; break;
|
||||
case fsBool: *(int *)ptr = (bool)inDefault.ival; break;
|
||||
case fsInt: *(int *)ptr =
|
||||
inDefault.type==CppiaConst::cInt ? inDefault.ival :
|
||||
inDefault.dval;
|
||||
break;
|
||||
case fsFloat: *(Float *)ptr =
|
||||
inDefault.type==CppiaConst::cInt ? inDefault.ival :
|
||||
inDefault.dval;
|
||||
break;
|
||||
case fsObject:
|
||||
{
|
||||
Dynamic &d = *(Dynamic *)ptr;
|
||||
if (inDefault.type==CppiaConst::cInt)
|
||||
d = inDefault.ival;
|
||||
else if (inDefault.type==CppiaConst::cFloat)
|
||||
d = inDefault.dval;
|
||||
else if (inDefault.type==CppiaConst::cString)
|
||||
d = module->strings[ inDefault.ival ];
|
||||
}
|
||||
break;
|
||||
case fsString:
|
||||
case fsUnknown:
|
||||
break; // handled above, or not needed
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
|
||||
static int SLJIT_CALL objToInt(hx::Object *inVal)
|
||||
{
|
||||
return inVal->__ToInt();
|
||||
}
|
||||
static void SLJIT_CALL objToFloat(hx::Object *inVal,double *outFloat)
|
||||
{
|
||||
*outFloat = inVal->__ToDouble();
|
||||
}
|
||||
static hx::Object *SLJIT_CALL intToObject(int inVal)
|
||||
{
|
||||
return Dynamic(inVal).mPtr;
|
||||
}
|
||||
static hx::Object *SLJIT_CALL floatToObject(double * inVal)
|
||||
{
|
||||
return Dynamic(*inVal).mPtr;
|
||||
}
|
||||
static hx::Object *SLJIT_CALL stringToObject(String * inVal)
|
||||
{
|
||||
return Dynamic(*inVal).mPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CppiaStackVar::genDefault(CppiaCompiler *compiler, const CppiaConst &inDefault)
|
||||
{
|
||||
if (argType==etString)
|
||||
{
|
||||
if (inDefault.type == CppiaConst::cString)
|
||||
{
|
||||
JumpId notNull = compiler->compare(cmpP_NOT_ZERO, JitFramePos(defaultStackPos+StringOffset::Ptr).as(jtPointer),(void *)0);
|
||||
String val = module->strings[ inDefault.ival ];
|
||||
compiler->move(JitFramePos(defaultStackPos).as(jtInt), (int)val.length);
|
||||
compiler->move(JitFramePos(defaultStackPos+StringOffset::Ptr).as(jtPointer), (void *)val.raw_ptr());
|
||||
compiler->comeFrom(notNull);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JitFramePos srcPos(defaultStackPos);
|
||||
JitFramePos destPos(stackPos);
|
||||
compiler->move( sJitTemp0, srcPos.as(jtPointer) );
|
||||
JumpId notNull = compiler->compare(cmpP_NOT_ZERO, sJitTemp0, (void *)0);
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte:
|
||||
compiler->move( destPos.as(jtByte), JitVal((int)(unsigned char)inDefault.ival));
|
||||
break;
|
||||
|
||||
case fsBool:
|
||||
compiler->move( destPos.as(jtByte), JitVal((int)(bool)inDefault.ival));
|
||||
break;
|
||||
|
||||
case fsInt:
|
||||
compiler->move( destPos.as(jtInt), inDefault.ival);
|
||||
break;
|
||||
case fsFloat:
|
||||
compiler->move( sJitTemp0, (void *)&inDefault.dval);
|
||||
compiler->move( destPos.as(jtFloat), sJitTemp0.star(jtFloat));
|
||||
break;
|
||||
case fsObject:
|
||||
if (inDefault.type==CppiaConst::cInt)
|
||||
compiler->callNative( (void *)intToObject, inDefault.ival );
|
||||
else if (inDefault.type==CppiaConst::cFloat)
|
||||
compiler->callNative( (void *)floatToObject, (void *)&inDefault.dval );
|
||||
else if (inDefault.type==CppiaConst::cString)
|
||||
compiler->callNative( (void *)stringToObject, (void *)&module->strings[ inDefault.ival ] );
|
||||
else
|
||||
break;
|
||||
compiler->move(destPos.as(jtPointer), sJitReturnReg.as(jtPointer));
|
||||
break;
|
||||
case fsString: // handled
|
||||
case fsUnknown: // ?
|
||||
break;
|
||||
}
|
||||
|
||||
JumpId defaultDone = compiler->jump();
|
||||
compiler->comeFrom(notNull);
|
||||
|
||||
switch(storeType)
|
||||
{
|
||||
case fsByte:
|
||||
case fsBool:
|
||||
//Fallthough...
|
||||
//compiler->callNative( (void *)objToInt, sJitTemp0.as(jtPointer) );
|
||||
//compiler->move( destPos.as(jtByte), sJitReturnReg.as(jtByte));
|
||||
//compiler->move( destPos.as(jtInt), sJitReturnReg.as(jtInt));
|
||||
//break;
|
||||
|
||||
case fsInt:
|
||||
compiler->callNative( (void *)objToInt, sJitTemp0.as(jtPointer) );
|
||||
compiler->move( destPos.as(jtInt), sJitReturnReg.as(jtInt));
|
||||
break;
|
||||
case fsFloat:
|
||||
compiler->callNative( (void *)objToFloat, sJitTemp0.as(jtPointer), destPos.as(jtFloat)) ;
|
||||
break;
|
||||
case fsObject:
|
||||
// Should be same pos
|
||||
//compiler->move(destPos.as(jtPointer), sJitTemp0.as(jtPointer));
|
||||
break;
|
||||
case fsString: // handled
|
||||
case fsUnknown: // ?
|
||||
break;
|
||||
}
|
||||
|
||||
compiler->comeFrom(defaultDone);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
400
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/GlobalBuiltin.cpp
Normal file
400
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/GlobalBuiltin.cpp
Normal file
@ -0,0 +1,400 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
template<> inline Array<unsigned char> &runValue(Array<unsigned char> &outValue, CppiaCtx *ctx, CppiaExpr *expr)
|
||||
{
|
||||
outValue.mPtr = (Array_obj<unsigned char>*) expr->runObject(ctx);
|
||||
return outValue;
|
||||
}
|
||||
|
||||
|
||||
template<typename ARG0, int (*FUNC)(ARG0 arg0)>
|
||||
class IntBuiltin1 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
IntBuiltin1(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "IntBuiltin1"; }
|
||||
ExprType getType() { return etInt; }
|
||||
|
||||
void runVoid(CppiaCtx *ctx) { runInt(ctx); }
|
||||
Float runFloat(CppiaCtx *ctx) { return runInt(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runInt(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runInt(ctx)); }
|
||||
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, int (*FUNC)(ARG0 arg0, ARG1 arg1)>
|
||||
class IntBuiltin2 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
IntBuiltin2(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "IntBuiltin2"; }
|
||||
ExprType getType() { return etInt; }
|
||||
|
||||
void runVoid(CppiaCtx *ctx) { runInt(ctx); }
|
||||
Float runFloat(CppiaCtx *ctx) { return runInt(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runInt(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runInt(ctx)); }
|
||||
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0,val1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename ARG0, void (*FUNC)(ARG0)>
|
||||
class VoidBuiltin1 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
VoidBuiltin1(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "VoidBuiltin1"; }
|
||||
ExprType getType() { return etVoid; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
Float runFloat(CppiaCtx *ctx) { runVoid(ctx); return 0;}
|
||||
hx::Object *runObject(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
String runString(CppiaCtx *ctx) { runVoid(ctx); return String(); }
|
||||
void runVoid(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_VCHECK;
|
||||
FUNC(val0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, void (*FUNC)(ARG0,ARG1)>
|
||||
class VoidBuiltin2 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
VoidBuiltin2(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "VoidBuiltin2"; }
|
||||
ExprType getType() { return etVoid; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
Float runFloat(CppiaCtx *ctx) { runVoid(ctx); return 0;}
|
||||
hx::Object *runObject(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
String runString(CppiaCtx *ctx) { runVoid(ctx); return String(); }
|
||||
void runVoid(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_VCHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_VCHECK;
|
||||
FUNC(val0,val1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, typename ARG2, void (*FUNC)(ARG0,ARG1,ARG2)>
|
||||
class VoidBuiltin3 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
VoidBuiltin3(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "VoidBuiltin3"; }
|
||||
ExprType getType() { return etVoid; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
Float runFloat(CppiaCtx *ctx) { runVoid(ctx); return 0;}
|
||||
hx::Object *runObject(CppiaCtx *ctx) { runVoid(ctx); return 0; }
|
||||
String runString(CppiaCtx *ctx) { runVoid(ctx); return String(); }
|
||||
void runVoid(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_VCHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_VCHECK;
|
||||
ARG2 val2;
|
||||
runValue(val2, ctx, args[2]);
|
||||
BCR_VCHECK;
|
||||
FUNC(val0,val1,val2);
|
||||
}
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static void SLJIT_CALL setFloat(Array_obj<unsigned char> *inBuffer, int inAddr, double *inValue)
|
||||
{
|
||||
if (sizeof(ARG2)==sizeof(float))
|
||||
__hxcpp_memory_set_float(inBuffer,inAddr,*inValue);
|
||||
else
|
||||
__hxcpp_memory_set_double(inBuffer,inAddr,*inValue);
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp obj(compiler,jtPointer);
|
||||
args[0]->genCode(compiler, obj, etObject);
|
||||
|
||||
JitTemp addr(compiler,jtInt);
|
||||
args[1]->genCode(compiler, addr, etInt);
|
||||
|
||||
JitTemp val(compiler,jtFloat);
|
||||
args[2]->genCode(compiler, val, etFloat);
|
||||
|
||||
compiler->callNative( (void *)setFloat, obj, addr, val );
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename RET, RET (*FUNC)()>
|
||||
class FloatBuiltin0 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
FloatBuiltin0(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "FloatBuiltin0"; }
|
||||
ExprType getType() { return etFloat; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { return runFloat(ctx); }
|
||||
void runVoid(CppiaCtx *ctx) { runFloat(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runFloat(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runFloat(ctx)); }
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
return FUNC();
|
||||
}
|
||||
#ifdef CPPIA_JIT
|
||||
static void SLJIT_CALL run(double *outResult)
|
||||
{
|
||||
*outResult = FUNC();
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
if (destType==etFloat && isMemoryVal(inDest) )
|
||||
{
|
||||
compiler->callNative( (void *)run, inDest.as(jtFloat));
|
||||
}
|
||||
else
|
||||
{
|
||||
JitTemp temp(compiler,jtFloat);
|
||||
compiler->callNative( (void *)run, temp);
|
||||
compiler->convert(temp, etFloat, inDest, destType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename ARG0, typename RET, RET (*FUNC)(ARG0)>
|
||||
class FloatBuiltin1 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
FloatBuiltin1(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "FloatBuiltin1"; }
|
||||
ExprType getType() { return etFloat; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { return runFloat(ctx); }
|
||||
void runVoid(CppiaCtx *ctx) { runFloat(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runFloat(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runFloat(ctx)); }
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, typename RET, RET (*FUNC)(ARG0,ARG1)>
|
||||
class FloatBuiltin2 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
FloatBuiltin2(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "FloatBuiltin2"; }
|
||||
ExprType getType() { return etFloat; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { return runFloat(ctx); }
|
||||
void runVoid(CppiaCtx *ctx) { runFloat(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runFloat(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runFloat(ctx)); }
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0,val1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ARG0, typename ARG1, typename ARG2, typename RET, RET (*FUNC)(ARG0,ARG1,ARG2)>
|
||||
class FloatBuiltin3 : public CppiaExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
FloatBuiltin3(CppiaExpr *inSrc, Expressions &inArgs) : CppiaExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "FloatBuiltin3"; }
|
||||
ExprType getType() { return etFloat; }
|
||||
|
||||
int runInt(CppiaCtx *ctx) { return runFloat(ctx); }
|
||||
void runVoid(CppiaCtx *ctx) { runFloat(ctx); }
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runFloat(ctx)).mPtr; }
|
||||
String runString(CppiaCtx *ctx) { return String(runFloat(ctx)); }
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
ARG1 val1;
|
||||
runValue(val1, ctx, args[1]);
|
||||
BCR_CHECK;
|
||||
ARG2 val2;
|
||||
runValue(val2, ctx, args[2]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0,val1,val2);
|
||||
}
|
||||
};
|
||||
|
||||
#define MEMORY_INT(GETTER,SETTER) \
|
||||
if (function==HX_CSTRING( #GETTER ) ) \
|
||||
{ \
|
||||
if (ioExpressions.size()==1) \
|
||||
return new IntBuiltin1<int, GETTER>(src,ioExpressions); \
|
||||
return new IntBuiltin2<Array<unsigned char>, int, GETTER>(src,ioExpressions); \
|
||||
} \
|
||||
if (function==HX_CSTRING( #SETTER ) ) \
|
||||
{ \
|
||||
if (ioExpressions.size()==2) \
|
||||
return new VoidBuiltin2<int,int, SETTER>(src,ioExpressions); \
|
||||
return new VoidBuiltin3<Array<unsigned char>,int,int,SETTER>(src,ioExpressions); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename ARG0, typename RET, RET (*FUNC)(ARG0)>
|
||||
class ObjectBuiltin1 : public CppiaDynamicExpr
|
||||
{
|
||||
public:
|
||||
Expressions args;
|
||||
|
||||
ObjectBuiltin1(CppiaExpr *inSrc, Expressions &inArgs) : CppiaDynamicExpr(inSrc), args(inArgs) { }
|
||||
|
||||
const char *getName() { return "ObjectBuiltin1"; }
|
||||
ExprType getType() { return etObject; }
|
||||
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
ARG0 val0;
|
||||
runValue(val0, ctx, args[0]);
|
||||
BCR_CHECK;
|
||||
return FUNC(val0).mPtr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
CppiaExpr *createGlobalBuiltin(CppiaExpr *src, String function, Expressions &ioExpressions )
|
||||
{
|
||||
MEMORY_INT(__hxcpp_memory_get_byte, __hxcpp_memory_set_byte);
|
||||
MEMORY_INT(__hxcpp_memory_get_i32, __hxcpp_memory_set_i32);
|
||||
MEMORY_INT(__hxcpp_memory_get_ui32, __hxcpp_memory_set_ui32);
|
||||
MEMORY_INT(__hxcpp_memory_get_i16, __hxcpp_memory_set_i16);
|
||||
MEMORY_INT(__hxcpp_memory_get_ui16, __hxcpp_memory_set_ui16);
|
||||
|
||||
if (function==HX_CSTRING("__hxcpp_memory_get_float") )
|
||||
{
|
||||
if (ioExpressions.size()==1)
|
||||
return new FloatBuiltin1<int,float,__hxcpp_memory_get_float>(src,ioExpressions);
|
||||
return new FloatBuiltin2<Array<unsigned char>,int,float,__hxcpp_memory_get_float>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__hxcpp_memory_set_float") )
|
||||
{
|
||||
if (ioExpressions.size()==2)
|
||||
return new VoidBuiltin2<int,float,__hxcpp_memory_set_float>(src,ioExpressions);
|
||||
return new VoidBuiltin3<Array<unsigned char>,int,float,__hxcpp_memory_set_float>(src,ioExpressions);
|
||||
}
|
||||
|
||||
if (function==HX_CSTRING("__hxcpp_memory_get_double") )
|
||||
{
|
||||
if (ioExpressions.size()==1)
|
||||
return new FloatBuiltin1<int,double,__hxcpp_memory_get_double>(src,ioExpressions);
|
||||
return new FloatBuiltin2<Array<unsigned char>,int,double,__hxcpp_memory_get_double>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__hxcpp_memory_set_double") )
|
||||
{
|
||||
if (ioExpressions.size()==2)
|
||||
return new VoidBuiltin2<int,double,__hxcpp_memory_set_double>(src,ioExpressions);
|
||||
return new VoidBuiltin3<Array<unsigned char>,int,double,__hxcpp_memory_set_double>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__time_stamp") )
|
||||
{
|
||||
if (ioExpressions.size()==0)
|
||||
return new FloatBuiltin0<double,__time_stamp>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__hxcpp_thread_create") )
|
||||
{
|
||||
if (ioExpressions.size()==1)
|
||||
return new ObjectBuiltin1<Dynamic,Dynamic,__hxcpp_thread_create>(src,ioExpressions);
|
||||
}
|
||||
if (function==HX_CSTRING("__hxcpp_thread_send") )
|
||||
{
|
||||
if (ioExpressions.size()==2)
|
||||
return new VoidBuiltin2<Dynamic,Dynamic,__hxcpp_thread_send>(src,ioExpressions);
|
||||
}
|
||||
|
||||
|
||||
printf("Unknown function : %s(%d)\n", function.out_str(), (int)ioExpressions.size() );
|
||||
throw (HX_CSTRING("Unknown global:") + function).utf8_str();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
223
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/HaxeNative.cpp
Normal file
223
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/HaxeNative.cpp
Normal file
@ -0,0 +1,223 @@
|
||||
#include <hxcpp.h>
|
||||
#include <hx/Scriptable.h>
|
||||
#include "Cppia.h"
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
typedef std::map<std::string, HaxeNativeClass *> ScriptRegisteredMap;
|
||||
static ScriptRegisteredMap *sScriptRegistered = 0;
|
||||
|
||||
typedef std::map<std::string, HaxeNativeInterface *> HaxeNativeIntefaceMap;
|
||||
static HaxeNativeIntefaceMap *sScriptRegisteredInterface = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// -- HaxeNativeClass ---
|
||||
|
||||
HaxeNativeClass::HaxeNativeClass(const std::string &inName, int inDataOffset, ScriptNamedFunction *inFunctions, hx::ScriptableClassFactory inFactory, ScriptNamedFunction inConstruct)
|
||||
{
|
||||
name = inName;
|
||||
mDataOffset = inDataOffset;
|
||||
functions = inFunctions;
|
||||
factory = inFactory;
|
||||
construct = inConstruct;
|
||||
haxeSuper = 0;
|
||||
}
|
||||
|
||||
void HaxeNativeClass::addVtableEntries( std::vector<std::string> &outVtable)
|
||||
{
|
||||
if (haxeSuper)
|
||||
haxeSuper->addVtableEntries(outVtable);
|
||||
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *func = functions; func->name; func++)
|
||||
if (!func->isStatic)
|
||||
outVtable.push_back( func->name );
|
||||
}
|
||||
|
||||
void HaxeNativeClass::dump()
|
||||
{
|
||||
printf("HaxeNativeClass %s\n", name.c_str());
|
||||
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *f=functions;f->name;f++)
|
||||
printf(" %s func %s\n", f->isStatic ? "static" : "virtual", f->name );
|
||||
if (haxeSuper)
|
||||
{
|
||||
printf("super:\n");
|
||||
haxeSuper->dump();
|
||||
}
|
||||
}
|
||||
|
||||
ScriptNamedFunction HaxeNativeClass::findFunction(const std::string &inName)
|
||||
{
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *f=functions;f->name;f++)
|
||||
if (inName == f->name && !f->isStatic)
|
||||
return *f;
|
||||
if (haxeSuper)
|
||||
return haxeSuper->findFunction(inName);
|
||||
|
||||
return ScriptNamedFunction(0,0,0,0,0);
|
||||
}
|
||||
|
||||
|
||||
ScriptNamedFunction HaxeNativeClass::findStaticFunction(String inName)
|
||||
{
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *f=functions;f->name;f++)
|
||||
if ( !strcmp(inName.utf8_str(),f->name) && f->isStatic)
|
||||
return *f;
|
||||
|
||||
return ScriptNamedFunction(0,0,0,0,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
HaxeNativeClass *HaxeNativeClass::findClass(const std::string &inName)
|
||||
{
|
||||
return sScriptRegistered ? (*sScriptRegistered)[inName] : 0;
|
||||
}
|
||||
|
||||
HaxeNativeClass *HaxeNativeClass::hxObject()
|
||||
{
|
||||
return sScriptRegistered ? (*sScriptRegistered)["hx.Object"] : 0;
|
||||
}
|
||||
|
||||
void HaxeNativeClass::link()
|
||||
{
|
||||
HaxeNativeClass *hxObj = hxObject();
|
||||
for(ScriptRegisteredMap::iterator i = sScriptRegistered->begin(); i!=sScriptRegistered->end();++i)
|
||||
{
|
||||
if (!i->second)
|
||||
continue;
|
||||
|
||||
DBGLOG("== %s ==\n", i->first.c_str());
|
||||
if (i->second == hxObj)
|
||||
{
|
||||
DBGLOG(" super =0\n");
|
||||
continue;
|
||||
}
|
||||
hx::Class cls = hx::Class_obj::Resolve( String(i->first.c_str() ) );
|
||||
if (cls.mPtr)
|
||||
{
|
||||
hx::Class superClass = cls->GetSuper();
|
||||
if (superClass.mPtr)
|
||||
{
|
||||
HaxeNativeClass *superRef = (*sScriptRegistered)[superClass.mPtr->mName.utf8_str()];
|
||||
if (superRef)
|
||||
{
|
||||
DBGLOG("registered %s\n",superClass.mPtr->mName.utf8_str());
|
||||
i->second->haxeSuper = superRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBGLOG("haxe super = %p\n", i->second->haxeSuper);
|
||||
if (!i->second->haxeSuper)
|
||||
{
|
||||
DBGLOG("using hx.Object\n");
|
||||
i->second->haxeSuper = hxObj;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -- HaxeNativeInterface ---
|
||||
|
||||
|
||||
ScriptFunction HaxeNativeInterface::findFunction(const std::string &inName)
|
||||
{
|
||||
if (functions)
|
||||
for(ScriptNamedFunction *f=functions;f->name;f++)
|
||||
if (inName == f->name)
|
||||
return *f;
|
||||
//if (haxeSuper)
|
||||
// return haxeSuper->findFunction(inName);
|
||||
|
||||
return ScriptFunction(0,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ScriptableRegisterClass( String inName, int inDataOffset, ScriptNamedFunction *inFunctions, hx::ScriptableClassFactory inFactory, hx::ScriptFunction inConstruct)
|
||||
{
|
||||
DBGLOG("ScriptableRegisterClass %s\n", inName.out_str());
|
||||
if (!sScriptRegistered)
|
||||
sScriptRegistered = new ScriptRegisteredMap();
|
||||
HaxeNativeClass *registered = new HaxeNativeClass(inName.utf8_str(),inDataOffset, inFunctions,inFactory, inConstruct);
|
||||
(*sScriptRegistered)[inName.utf8_str()] = registered;
|
||||
//printf("Registering %s -> %p\n",inName.out_str(),(*sScriptRegistered)[inName.utf8_str()]);
|
||||
}
|
||||
|
||||
|
||||
#if (HXCPP_API_LEVEL >= 330)
|
||||
|
||||
HaxeNativeInterface::HaxeNativeInterface(const std::string &inName,
|
||||
ScriptNamedFunction *inFunctions,
|
||||
void *inScriptTable )
|
||||
{
|
||||
name = inName;
|
||||
functions = inFunctions;
|
||||
scriptTable = inScriptTable;
|
||||
}
|
||||
|
||||
void ScriptableRegisterInterface( String inName,
|
||||
ScriptNamedFunction *inFunctions,
|
||||
void *inScriptTable)
|
||||
{
|
||||
DBGLOG("ScriptableInterfaceFactory %s\n",inName.out_str());
|
||||
if (!sScriptRegisteredInterface)
|
||||
sScriptRegisteredInterface = new HaxeNativeIntefaceMap();
|
||||
|
||||
HaxeNativeInterface *registered = new HaxeNativeInterface(inName.utf8_str(), inFunctions, inScriptTable);
|
||||
(*sScriptRegisteredInterface)[inName.utf8_str()] = registered;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
HaxeNativeInterface::HaxeNativeInterface(const std::string &inName,
|
||||
ScriptNamedFunction *inFunctions,
|
||||
hx::ScriptableInterfaceFactory inFactory,
|
||||
const hx::type_info *inType)
|
||||
{
|
||||
functions = inFunctions;
|
||||
factory = inFactory;
|
||||
name = inName;
|
||||
mType = inType;
|
||||
}
|
||||
|
||||
void ScriptableRegisterInterface( String inName,
|
||||
ScriptNamedFunction *inFunctions,
|
||||
const hx::type_info *inType,
|
||||
hx::ScriptableInterfaceFactory inFactory )
|
||||
{
|
||||
DBGLOG("ScriptableInterfaceFactory %s\n",inName.out_str());
|
||||
if (!sScriptRegisteredInterface)
|
||||
sScriptRegisteredInterface = new HaxeNativeIntefaceMap();
|
||||
|
||||
HaxeNativeInterface *registered = new HaxeNativeInterface(inName.utf8_str(), inFunctions, inFactory,inType);
|
||||
(*sScriptRegisteredInterface)[inName.utf8_str()] = registered;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
HaxeNativeInterface *HaxeNativeInterface::findInterface(const std::string &inName)
|
||||
{
|
||||
return sScriptRegisteredInterface ? (*sScriptRegisteredInterface)[inName] : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // end namespace hx
|
||||
472
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/StringBuiltin.cpp
Normal file
472
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/StringBuiltin.cpp
Normal file
@ -0,0 +1,472 @@
|
||||
#include <hxcpp.h>
|
||||
#include "Cppia.h"
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
struct StringExpr : public CppiaExpr
|
||||
{
|
||||
CppiaExpr *strVal;
|
||||
StringExpr(CppiaExpr *inSrc, CppiaExpr *inThis )
|
||||
: CppiaExpr(inSrc)
|
||||
{
|
||||
strVal = inThis;
|
||||
}
|
||||
ExprType getType() { return etString; }
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
strVal = strVal->link(inData);
|
||||
return this;
|
||||
}
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
return Dynamic(runString(ctx)).mPtr;
|
||||
}
|
||||
};
|
||||
|
||||
template<bool SUBSTR>
|
||||
struct SubStrExpr : public StringExpr
|
||||
{
|
||||
CppiaExpr *a0;
|
||||
CppiaExpr *a1;
|
||||
SubStrExpr(CppiaExpr *inSrc, CppiaExpr *inThis, CppiaExpr *inA0, CppiaExpr *inA1)
|
||||
: StringExpr(inSrc,inThis)
|
||||
{
|
||||
a0 = inA0;
|
||||
a1 = inA1;
|
||||
}
|
||||
const char *getName() { return "SubStrExpr"; }
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
a0 = a0->link(inData);
|
||||
a1 = a1->link(inData);
|
||||
return StringExpr::link(inData);
|
||||
}
|
||||
String runString(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
int start = a0->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
Dynamic end = a1->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
if (SUBSTR)
|
||||
return val.substr(start,end);
|
||||
else
|
||||
return val.substring(start,end);
|
||||
}
|
||||
#ifdef CPPIA_JIT
|
||||
static void SLJIT_CALL runSubstr(String *ioValue, int start, hx::Object *end)
|
||||
{
|
||||
*ioValue = ioValue->substr(start, Dynamic(end));
|
||||
}
|
||||
static void SLJIT_CALL runSubstring(String *ioValue, int start, hx::Object *end)
|
||||
{
|
||||
*ioValue = ioValue->substring(start, Dynamic(end));
|
||||
}
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp ioValue(compiler,jtString);
|
||||
JitTemp startVal(compiler,jtInt);
|
||||
|
||||
strVal->genCode(compiler, ioValue, etString);
|
||||
a0->genCode(compiler, startVal, etInt);
|
||||
a1->genCode(compiler, sJitArg2, etObject);
|
||||
compiler->callNative( SUBSTR ? (void *)runSubstr : (void *)runSubstring, ioValue, startVal, sJitArg2.as(jtPointer) );
|
||||
compiler->convert(ioValue, etString, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<bool KEYS>
|
||||
struct StringIteratorExpr : public StringExpr
|
||||
{
|
||||
StringIteratorExpr(CppiaExpr *inSrc, CppiaExpr *inThis) : StringExpr(inSrc,inThis)
|
||||
{
|
||||
}
|
||||
const char *getName() { return "StringIteratorExpr"; }
|
||||
|
||||
ExprType getType() { return etObject; }
|
||||
|
||||
String runString(CppiaCtx *ctx) { return Dynamic(runObject(ctx)); }
|
||||
int runInt(CppiaCtx *ctx) { return 0; }
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
return ( KEYS ? val.keyValueIterator() : val.iterator() ).mPtr;
|
||||
}
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static hx::Object *SLJIT_CALL run(String *inValue)
|
||||
{
|
||||
return ( KEYS ? inValue->keyValueIterator() : inValue->iterator() ).mPtr;
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
strVal->genCode(compiler, value, etString);
|
||||
compiler->callNative( (void *)run, value);
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<bool UPPER>
|
||||
struct ToCaseExpr : public StringExpr
|
||||
{
|
||||
const char *getName() { return "ToCaseExpr"; }
|
||||
ToCaseExpr(CppiaExpr *inSrc, CppiaExpr *inThis ) : StringExpr(inSrc,inThis) { }
|
||||
String runString(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
if (UPPER)
|
||||
return val.toUpperCase();
|
||||
else
|
||||
return val.toLowerCase();
|
||||
}
|
||||
#ifdef CPPIA_JIT
|
||||
static void SLJIT_CALL strToCase(String *ioVal)
|
||||
{
|
||||
if (UPPER)
|
||||
*ioVal = ioVal->toUpperCase();
|
||||
else
|
||||
*ioVal = ioVal->toLowerCase();
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
if (destType==etString)
|
||||
{
|
||||
strVal->genCode(compiler, inDest, destType);
|
||||
compiler->callNative( (void *)strToCase, inDest.as(jtString) );
|
||||
}
|
||||
else
|
||||
{
|
||||
JitTemp tmpVal(compiler,jtString);
|
||||
strVal->genCode(compiler, tmpVal, etString);
|
||||
compiler->callNative( (void *)strToCase, tmpVal);
|
||||
compiler->convert( tmpVal, etString, inDest, destType );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<bool CODE,bool AS_INT>
|
||||
struct CharAtExpr : public StringExpr
|
||||
{
|
||||
CppiaExpr *a0;
|
||||
|
||||
CharAtExpr(CppiaExpr *inSrc, CppiaExpr *inThis, CppiaExpr *inIndex ) : StringExpr(inSrc,inThis)
|
||||
{
|
||||
a0 = inIndex;
|
||||
}
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
a0 = a0->link(inData);
|
||||
return StringExpr::link(inData);
|
||||
}
|
||||
const char *getName() { return "CharAtExpr"; }
|
||||
ExprType getType() { return CODE ? (AS_INT ? etInt : etObject) : etString; }
|
||||
|
||||
String runString(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
int idx = a0->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
return val.charAt(idx);
|
||||
}
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
//printf("Char code at %d INT\n", CODE);
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
int idx = a0->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
|
||||
if (AS_INT)
|
||||
return (int)val.cca(idx);
|
||||
else
|
||||
return val.charCodeAt(idx);
|
||||
}
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
int idx = a0->runInt(ctx);
|
||||
BCR_CHECK;
|
||||
|
||||
if (CODE)
|
||||
{
|
||||
if (AS_INT)
|
||||
return Dynamic( val.cca(idx) ).mPtr;
|
||||
else
|
||||
return val.charCodeAt(idx).mPtr;
|
||||
}
|
||||
else
|
||||
return Dynamic(val.charAt(idx)).mPtr;
|
||||
}
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static hx::Object *SLJIT_CALL runCharCodeAt(String *inValue, int inIndex)
|
||||
{
|
||||
return (inValue->charCodeAt(inIndex)).mPtr;
|
||||
}
|
||||
static int SLJIT_CALL runCca(String *inValue, int inIndex)
|
||||
{
|
||||
return (inValue->cca(inIndex));
|
||||
}
|
||||
static void SLJIT_CALL runCharAt(String *ioValue, int inIndex)
|
||||
{
|
||||
*ioValue = ioValue->charAt(inIndex);
|
||||
}
|
||||
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
strVal->genCode(compiler, value, etString);
|
||||
a0->genCode(compiler, sJitTemp1, etInt);
|
||||
|
||||
if (CODE)
|
||||
{
|
||||
if (AS_INT)
|
||||
{
|
||||
#ifdef HX_SMART_STRINGS
|
||||
compiler->callNative( (void *)runCca, value, sJitTemp1.as(jtInt));
|
||||
compiler->convertReturnReg( etInt, inDest, destType);
|
||||
#else
|
||||
// sJitTemp1 = __s
|
||||
compiler->move( sJitTemp0.as(jtPointer), value.star(jtPointer,offsetof(String,__s)) );
|
||||
if (destType==etInt)
|
||||
{
|
||||
compiler->move(inDest.as(jtInt), sJitTemp0.atReg(sJitTemp1,0,jtByte) );
|
||||
}
|
||||
else
|
||||
{
|
||||
compiler->move(sJitTemp0.as(jtInt), sJitTemp0.atReg(sJitTemp1,0,jtByte) );
|
||||
compiler->convertReturnReg(etInt, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
compiler->callNative( (void *)runCharCodeAt, value, sJitTemp1.as(jtInt));
|
||||
compiler->convertReturnReg( etObject, inDest, destType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
compiler->callNative( (void *)runCharAt, value, sJitTemp1.as(jtInt));
|
||||
compiler->convert(value, etString, inDest, destType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct SplitExpr : public CppiaExpr
|
||||
{
|
||||
CppiaExpr *strVal;
|
||||
CppiaExpr *a0;
|
||||
|
||||
SplitExpr(CppiaExpr *inSrc, CppiaExpr *inThis, CppiaExpr *inDelim ) :
|
||||
CppiaExpr(inSrc)
|
||||
{
|
||||
strVal = inThis;
|
||||
a0 = inDelim;
|
||||
}
|
||||
const char *getName() { return "SplitExpr"; }
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
strVal = strVal->link(inData);
|
||||
a0 = a0->link(inData);
|
||||
return this;
|
||||
}
|
||||
ExprType getType() { return etObject; }
|
||||
|
||||
hx::Object *runObject(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
String separator = a0->runString(ctx);
|
||||
BCR_CHECK;
|
||||
return val.split(separator).mPtr;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static hx::Object *SLJIT_CALL runSplit(String *inValue, String *sep)
|
||||
{
|
||||
return (inValue->split(*sep)).mPtr;
|
||||
}
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
JitTemp sep(compiler,jtString);
|
||||
|
||||
strVal->genCode(compiler, value, etString);
|
||||
a0->genCode(compiler, sep, etString);
|
||||
compiler->callNative( (void *)runSplit, value, sep );
|
||||
compiler->convertReturnReg(etObject, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<bool LAST>
|
||||
struct IndexOfExpr : public CppiaExpr
|
||||
{
|
||||
CppiaExpr *strVal;
|
||||
CppiaExpr *sought;
|
||||
CppiaExpr *start;
|
||||
|
||||
IndexOfExpr(CppiaExpr *inSrc, CppiaExpr *inThis, CppiaExpr *inSought, CppiaExpr *inStart ) :
|
||||
CppiaExpr(inSrc)
|
||||
{
|
||||
strVal = inThis;
|
||||
sought = inSought;
|
||||
start = inStart;
|
||||
}
|
||||
const char *getName() { return "IndexOfExpr"; }
|
||||
ExprType getType() { return etInt; }
|
||||
CppiaExpr *link(CppiaModule &inData)
|
||||
{
|
||||
strVal = strVal->link(inData);
|
||||
sought = sought->link(inData);
|
||||
start = start->link(inData);
|
||||
return this;
|
||||
}
|
||||
Float runFloat(CppiaCtx *ctx)
|
||||
{
|
||||
return runInt(ctx);
|
||||
}
|
||||
int runInt(CppiaCtx *ctx)
|
||||
{
|
||||
String val = strVal->runString(ctx);
|
||||
BCR_CHECK;
|
||||
String s = sought->runString(ctx);
|
||||
BCR_CHECK;
|
||||
hx::Object *first = start->runObject(ctx);
|
||||
BCR_CHECK;
|
||||
if (LAST)
|
||||
return val.lastIndexOf(s,first);
|
||||
else
|
||||
return val.indexOf(s,first);
|
||||
}
|
||||
hx::Object *runObject(CppiaCtx *ctx) { return Dynamic(runInt(ctx)).mPtr; }
|
||||
|
||||
|
||||
#ifdef CPPIA_JIT
|
||||
static int SLJIT_CALL runIndexOf(String *ioValue, String *sought, hx::Object *first)
|
||||
{
|
||||
return ioValue->indexOf(*sought, Dynamic(first));
|
||||
}
|
||||
static int SLJIT_CALL runLastIndexOf(String *ioValue, String *sought, hx::Object *first)
|
||||
{
|
||||
return ioValue->lastIndexOf(*sought, Dynamic(first));
|
||||
}
|
||||
void genCode(CppiaCompiler *compiler, const JitVal &inDest,ExprType destType)
|
||||
{
|
||||
JitTemp value(compiler,jtString);
|
||||
JitTemp soughtTemp(compiler,jtString);
|
||||
|
||||
strVal->genCode(compiler, value, etString);
|
||||
sought->genCode(compiler, soughtTemp, etString);
|
||||
start->genCode(compiler, sJitArg2, etObject);
|
||||
compiler->callNative( LAST ? (void *)runLastIndexOf : (void *)runIndexOf, value, soughtTemp, sJitArg2.as(jtPointer) );
|
||||
compiler->convertReturnReg(etInt, inDest, destType);
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// TODO
|
||||
// static function fromCharCode( code : Int ) : String;
|
||||
|
||||
|
||||
CppiaExpr *createStringBuiltin(CppiaExpr *inSrc, CppiaExpr *inThisExpr, String field, Expressions &ioExpressions )
|
||||
{
|
||||
if (field==HX_CSTRING("toString"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return inThisExpr;
|
||||
}
|
||||
else if (field==HX_CSTRING("toUpperCase"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return new ToCaseExpr<true>(inSrc,inThisExpr);
|
||||
}
|
||||
else if (field==HX_CSTRING("toLowerCase"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return new ToCaseExpr<false>(inSrc,inThisExpr);
|
||||
}
|
||||
else if (field==HX_CSTRING("charAt"))
|
||||
{
|
||||
if (ioExpressions.size()!=1) throw "Bad arg count";
|
||||
return new CharAtExpr<false,false>(inSrc,inThisExpr,ioExpressions[0]);
|
||||
}
|
||||
else if (field==HX_CSTRING("cca"))
|
||||
{
|
||||
if (ioExpressions.size()!=1) throw "Bad arg count";
|
||||
return new CharAtExpr<true,true>(inSrc,inThisExpr,ioExpressions[0]);
|
||||
}
|
||||
else if (field==HX_CSTRING("iterator"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return new StringIteratorExpr<false>(inSrc,inThisExpr);
|
||||
}
|
||||
else if (field==HX_CSTRING("keyValueIterator"))
|
||||
{
|
||||
if (ioExpressions.size()!=0) throw "Bad arg count";
|
||||
return new StringIteratorExpr<true>(inSrc,inThisExpr);
|
||||
}
|
||||
else if (field==HX_CSTRING("charCodeAt"))
|
||||
{
|
||||
if (ioExpressions.size()!=1) throw "Bad arg count";
|
||||
return new CharAtExpr<true,false>(inSrc,inThisExpr,ioExpressions[0]);
|
||||
}
|
||||
else if (field==HX_CSTRING("split"))
|
||||
{
|
||||
if (ioExpressions.size()!=1) throw "Bad arg count";
|
||||
return new SplitExpr(inSrc,inThisExpr,ioExpressions[0]);
|
||||
}
|
||||
else if (field==HX_CSTRING("indexOf"))
|
||||
{
|
||||
if (ioExpressions.size()!=2) throw "Bad arg count";
|
||||
return new IndexOfExpr<false>(inSrc,inThisExpr,ioExpressions[0], ioExpressions[1]);
|
||||
}
|
||||
else if (field==HX_CSTRING("lastIndexOf"))
|
||||
{
|
||||
if (ioExpressions.size()!=2) throw "Bad arg count";
|
||||
return new IndexOfExpr<true>(inSrc,inThisExpr,ioExpressions[0], ioExpressions[1]);
|
||||
}
|
||||
|
||||
else if (field==HX_CSTRING("substr"))
|
||||
{
|
||||
if (ioExpressions.size()!=2) throw "Bad arg count";
|
||||
return new SubStrExpr<true>(inSrc,inThisExpr, ioExpressions[0], ioExpressions[1]);
|
||||
}
|
||||
else if (field==HX_CSTRING("substring"))
|
||||
{
|
||||
if (ioExpressions.size()!=2) throw "Bad arg count";
|
||||
return new SubStrExpr<false>(inSrc,inThisExpr, ioExpressions[0], ioExpressions[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end namespace hx
|
||||
29
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/README
Normal file
29
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/README
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
SLJIT - Stack Less JIT Compiler
|
||||
|
||||
Purpose:
|
||||
A simple, machine independent JIT compiler, which suitable for
|
||||
translating interpreted byte code to machine code. The sljitLir.h
|
||||
describes the LIR (low-level intermediate representation) of SLJIT.
|
||||
|
||||
Compatible:
|
||||
Any C (C++) compiler. At least I hope so.
|
||||
|
||||
Using sljit:
|
||||
Copy the content of sljit_src directory into your project source directory.
|
||||
Add sljitLir.c source file to your build environment. All other files are
|
||||
included by sljitLir.c (if required). Define the machine by SLJIT_CONFIG_*
|
||||
selector. See sljitConfig.h for all possible values. For C++ compilers,
|
||||
rename sljitLir.c to sljitLir.cpp.
|
||||
|
||||
More info:
|
||||
http://sljit.sourceforge.net/
|
||||
|
||||
Contact:
|
||||
hzmester@freemail.hu
|
||||
|
||||
Special thanks:
|
||||
Alexander Nasonov
|
||||
Daniel Richard G.
|
||||
Giuseppe D'Angelo
|
||||
Jiong Wang (TileGX support)
|
||||
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SLJIT_CONFIG_H_
|
||||
#define _SLJIT_CONFIG_H_
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Custom defines */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Put your custom defines here. This empty section will never change
|
||||
which helps maintaining patches (with diff / patch utilities). */
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Architecture */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Architecture selection. */
|
||||
/* #define SLJIT_CONFIG_X86_32 1 */
|
||||
/* #define SLJIT_CONFIG_X86_64 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_V5 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_V7 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_THUMB2 1 */
|
||||
/* #define SLJIT_CONFIG_ARM_64 1 */
|
||||
/* #define SLJIT_CONFIG_PPC_32 1 */
|
||||
/* #define SLJIT_CONFIG_PPC_64 1 */
|
||||
/* #define SLJIT_CONFIG_MIPS_32 1 */
|
||||
/* #define SLJIT_CONFIG_MIPS_64 1 */
|
||||
/* #define SLJIT_CONFIG_SPARC_32 1 */
|
||||
/* #define SLJIT_CONFIG_TILEGX 1 */
|
||||
|
||||
/* #define SLJIT_CONFIG_AUTO 1 */
|
||||
/* #define SLJIT_CONFIG_UNSUPPORTED 1 */
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Utilities */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Useful for thread-safe compiling of global functions. */
|
||||
#ifndef SLJIT_UTIL_GLOBAL_LOCK
|
||||
/* Enabled by default */
|
||||
#define SLJIT_UTIL_GLOBAL_LOCK 1
|
||||
#endif
|
||||
|
||||
/* Implements a stack like data structure (by using mmap / VirtualAlloc). */
|
||||
#ifndef SLJIT_UTIL_STACK
|
||||
/* Enabled by default */
|
||||
#define SLJIT_UTIL_STACK 1
|
||||
#endif
|
||||
|
||||
/* Single threaded application. Does not require any locks. */
|
||||
#ifndef SLJIT_SINGLE_THREADED
|
||||
/* Disabled by default. */
|
||||
#define SLJIT_SINGLE_THREADED 0
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Configuration */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* If SLJIT_STD_MACROS_DEFINED is not defined, the application should
|
||||
define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMCPY, and NULL. */
|
||||
#ifndef SLJIT_STD_MACROS_DEFINED
|
||||
/* Disabled by default. */
|
||||
#define SLJIT_STD_MACROS_DEFINED 0
|
||||
#endif
|
||||
|
||||
/* Executable code allocation:
|
||||
If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should
|
||||
define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_EXEC_OFFSET. */
|
||||
#ifndef SLJIT_EXECUTABLE_ALLOCATOR
|
||||
/* Enabled by default. */
|
||||
#define SLJIT_EXECUTABLE_ALLOCATOR 1
|
||||
|
||||
/* When SLJIT_PROT_EXECUTABLE_ALLOCATOR is enabled SLJIT uses
|
||||
an allocator which does not set writable and executable
|
||||
permission flags at the same time. The trade-of is increased
|
||||
memory consumption and disabled dynamic code modifications. */
|
||||
#ifndef SLJIT_PROT_EXECUTABLE_ALLOCATOR
|
||||
/* Disabled by default. */
|
||||
#define SLJIT_PROT_EXECUTABLE_ALLOCATOR 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Force cdecl calling convention even if a better calling
|
||||
convention (e.g. fastcall) is supported by the C compiler.
|
||||
If this option is enabled, C functions without
|
||||
SLJIT_CALL can also be called from JIT code. */
|
||||
#ifndef SLJIT_USE_CDECL_CALLING_CONVENTION
|
||||
/* Disabled by default */
|
||||
#define SLJIT_USE_CDECL_CALLING_CONVENTION 0
|
||||
#endif
|
||||
|
||||
/* Return with error when an invalid argument is passed. */
|
||||
#ifndef SLJIT_ARGUMENT_CHECKS
|
||||
/* Disabled by default */
|
||||
#define SLJIT_ARGUMENT_CHECKS 0
|
||||
#endif
|
||||
|
||||
/* Debug checks (assertions, etc.). */
|
||||
#ifndef SLJIT_DEBUG
|
||||
/* Enabled by default */
|
||||
#define SLJIT_DEBUG 1
|
||||
#endif
|
||||
|
||||
/* Verbose operations. */
|
||||
#ifndef SLJIT_VERBOSE
|
||||
/* Enabled by default */
|
||||
#define SLJIT_VERBOSE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
SLJIT_IS_FPU_AVAILABLE
|
||||
The availability of the FPU can be controlled by SLJIT_IS_FPU_AVAILABLE.
|
||||
zero value - FPU is NOT present.
|
||||
nonzero value - FPU is present.
|
||||
*/
|
||||
|
||||
/* For further configurations, see the beginning of sljitConfigInternal.h */
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,728 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SLJIT_CONFIG_INTERNAL_H_
|
||||
#define _SLJIT_CONFIG_INTERNAL_H_
|
||||
|
||||
/*
|
||||
SLJIT defines the following architecture dependent types and macros:
|
||||
|
||||
Types:
|
||||
sljit_s8, sljit_u8 : signed and unsigned 8 bit integer type
|
||||
sljit_s16, sljit_u16 : signed and unsigned 16 bit integer type
|
||||
sljit_s32, sljit_u32 : signed and unsigned 32 bit integer type
|
||||
sljit_sw, sljit_uw : signed and unsigned machine word, enough to store a pointer
|
||||
sljit_p : unsgined pointer value (usually the same as sljit_uw, but
|
||||
some 64 bit ABIs may use 32 bit pointers)
|
||||
sljit_f32 : 32 bit single precision floating point value
|
||||
sljit_f64 : 64 bit double precision floating point value
|
||||
|
||||
Macros for feature detection (boolean):
|
||||
SLJIT_32BIT_ARCHITECTURE : 32 bit architecture
|
||||
SLJIT_64BIT_ARCHITECTURE : 64 bit architecture
|
||||
SLJIT_LITTLE_ENDIAN : little endian architecture
|
||||
SLJIT_BIG_ENDIAN : big endian architecture
|
||||
SLJIT_UNALIGNED : allows unaligned memory accesses for non-fpu operations (only!)
|
||||
SLJIT_INDIRECT_CALL : see SLJIT_FUNC_OFFSET() for more information
|
||||
|
||||
Constants:
|
||||
SLJIT_NUMBER_OF_REGISTERS : number of available registers
|
||||
SLJIT_NUMBER_OF_SCRATCH_REGISTERS : number of available scratch registers
|
||||
SLJIT_NUMBER_OF_SAVED_REGISTERS : number of available saved registers
|
||||
SLJIT_NUMBER_OF_FLOAT_REGISTERS : number of available floating point registers
|
||||
SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS : number of available floating point scratch registers
|
||||
SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS : number of available floating point saved registers
|
||||
SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index
|
||||
SLJIT_F32_SHIFT : the shift required to apply when accessing
|
||||
a single precision floating point array by index
|
||||
SLJIT_F64_SHIFT : the shift required to apply when accessing
|
||||
a double precision floating point array by index
|
||||
SLJIT_LOCALS_OFFSET : local space starting offset (SLJIT_SP + SLJIT_LOCALS_OFFSET)
|
||||
SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address
|
||||
|
||||
Other macros:
|
||||
SLJIT_CALL : C calling convention define for both calling JIT form C and C callbacks for JIT
|
||||
SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (compiler independent helper)
|
||||
*/
|
||||
|
||||
/*****************/
|
||||
/* Sanity check. */
|
||||
/*****************/
|
||||
|
||||
#if !((defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|
||||
|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
|| (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
|
||||
|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|
||||
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|
||||
|| (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|
||||
|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|
||||
|| (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
|
||||
|| (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
|
||||
|| (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
|
||||
|| (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED))
|
||||
#error "An architecture must be selected"
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|
||||
+ (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
+ (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
|
||||
+ (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
+ (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|
||||
+ (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
+ (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
+ (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|
||||
+ (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
|
||||
+ (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|
||||
+ (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|
||||
+ (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
|
||||
+ (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
|
||||
+ (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2
|
||||
#error "Multiple architectures are selected"
|
||||
#endif
|
||||
|
||||
/********************************************************/
|
||||
/* Automatic CPU detection (requires compiler support). */
|
||||
/********************************************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#if defined(__i386__) || defined(__i386)
|
||||
#define SLJIT_CONFIG_X86_32 1
|
||||
#elif defined(__x86_64__)
|
||||
#define SLJIT_CONFIG_X86_64 1
|
||||
#elif defined(__arm__) || defined(__ARM__)
|
||||
#ifdef __thumb2__
|
||||
#define SLJIT_CONFIG_ARM_THUMB2 1
|
||||
#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)
|
||||
#define SLJIT_CONFIG_ARM_V7 1
|
||||
#else
|
||||
#define SLJIT_CONFIG_ARM_V5 1
|
||||
#endif
|
||||
#elif defined (__aarch64__)
|
||||
#define SLJIT_CONFIG_ARM_64 1
|
||||
#elif defined(__ppc64__) || defined(__powerpc64__) || defined(_ARCH_PPC64) || (defined(_POWER) && defined(__64BIT__))
|
||||
#define SLJIT_CONFIG_PPC_64 1
|
||||
#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER)
|
||||
#define SLJIT_CONFIG_PPC_32 1
|
||||
#elif defined(__mips__) && !defined(_LP64)
|
||||
#define SLJIT_CONFIG_MIPS_32 1
|
||||
#elif defined(__mips64)
|
||||
#define SLJIT_CONFIG_MIPS_64 1
|
||||
#elif defined(__sparc__) || defined(__sparc)
|
||||
#define SLJIT_CONFIG_SPARC_32 1
|
||||
#elif defined(__tilegx__)
|
||||
#define SLJIT_CONFIG_TILEGX 1
|
||||
#else
|
||||
/* Unsupported architecture */
|
||||
#define SLJIT_CONFIG_UNSUPPORTED 1
|
||||
#endif
|
||||
|
||||
#else /* !_WIN32 */
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define SLJIT_CONFIG_X86_64 1
|
||||
#elif defined(_ARM_)
|
||||
#define SLJIT_CONFIG_ARM_V5 1
|
||||
#else
|
||||
#define SLJIT_CONFIG_X86_32 1
|
||||
#endif
|
||||
|
||||
#endif /* !WIN32 */
|
||||
#endif /* SLJIT_CONFIG_AUTO */
|
||||
|
||||
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
#undef SLJIT_EXECUTABLE_ALLOCATOR
|
||||
#endif
|
||||
|
||||
/******************************/
|
||||
/* CPU family type detection. */
|
||||
/******************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
#define SLJIT_CONFIG_ARM_32 1
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
#define SLJIT_CONFIG_X86 1
|
||||
#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
|
||||
#define SLJIT_CONFIG_ARM 1
|
||||
#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
#define SLJIT_CONFIG_PPC 1
|
||||
#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
#define SLJIT_CONFIG_MIPS 1
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) || (defined SLJIT_CONFIG_SPARC_64 && SLJIT_CONFIG_SPARC_64)
|
||||
#define SLJIT_CONFIG_SPARC 1
|
||||
#endif
|
||||
|
||||
/**********************************/
|
||||
/* External function definitions. */
|
||||
/**********************************/
|
||||
|
||||
/* General macros:
|
||||
Note: SLJIT is designed to be independent from them as possible.
|
||||
|
||||
In release mode (SLJIT_DEBUG is not defined) only the following
|
||||
external functions are needed:
|
||||
*/
|
||||
|
||||
#ifndef SLJIT_MALLOC
|
||||
#define SLJIT_MALLOC(size, allocator_data) malloc(size)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_FREE
|
||||
#define SLJIT_FREE(ptr, allocator_data) free(ptr)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_MEMCPY
|
||||
#define SLJIT_MEMCPY(dest, src, len) memcpy(dest, src, len)
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_ZEROMEM
|
||||
#define SLJIT_ZEROMEM(dest, len) memset(dest, 0, len)
|
||||
#endif
|
||||
|
||||
/***************************/
|
||||
/* Compiler helper macros. */
|
||||
/***************************/
|
||||
|
||||
#if !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY)
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
#define SLJIT_LIKELY(x) __builtin_expect((x), 1)
|
||||
#define SLJIT_UNLIKELY(x) __builtin_expect((x), 0)
|
||||
#else
|
||||
#define SLJIT_LIKELY(x) (x)
|
||||
#define SLJIT_UNLIKELY(x) (x)
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY) */
|
||||
|
||||
#ifndef SLJIT_INLINE
|
||||
/* Inline functions. Some old compilers do not support them. */
|
||||
#if defined(__SUNPRO_C) && __SUNPRO_C <= 0x510
|
||||
#define SLJIT_INLINE
|
||||
#else
|
||||
#define SLJIT_INLINE __inline
|
||||
#endif
|
||||
#endif /* !SLJIT_INLINE */
|
||||
|
||||
#ifndef SLJIT_NOINLINE
|
||||
/* Not inline functions. */
|
||||
#if defined(__GNUC__)
|
||||
#define SLJIT_NOINLINE __attribute__ ((noinline))
|
||||
#else
|
||||
#define SLJIT_NOINLINE
|
||||
#endif
|
||||
#endif /* !SLJIT_INLINE */
|
||||
|
||||
#ifndef SLJIT_UNUSED_ARG
|
||||
/* Unused arguments. */
|
||||
#define SLJIT_UNUSED_ARG(arg) (void)arg
|
||||
#endif
|
||||
|
||||
/*********************************/
|
||||
/* Type of public API functions. */
|
||||
/*********************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC)
|
||||
/* Static ABI functions. For all-in-one programs. */
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/* Disable unused warnings in gcc. */
|
||||
#define SLJIT_API_FUNC_ATTRIBUTE static __attribute__((unused))
|
||||
#else
|
||||
#define SLJIT_API_FUNC_ATTRIBUTE static
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define SLJIT_API_FUNC_ATTRIBUTE
|
||||
#endif /* (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC) */
|
||||
|
||||
/****************************/
|
||||
/* Instruction cache flush. */
|
||||
/****************************/
|
||||
|
||||
#if (!defined SLJIT_CACHE_FLUSH && defined __has_builtin)
|
||||
#if __has_builtin(__builtin___clear_cache)
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
__builtin___clear_cache((char*)from, (char*)to)
|
||||
|
||||
#endif /* __has_builtin(__builtin___clear_cache) */
|
||||
#endif /* (!defined SLJIT_CACHE_FLUSH && defined __has_builtin) */
|
||||
|
||||
#ifndef SLJIT_CACHE_FLUSH
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
|
||||
|
||||
/* Not required to implement on archs with unified caches. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to)
|
||||
|
||||
#elif defined __APPLE__
|
||||
|
||||
/* Supported by all macs since Mac OS 10.5.
|
||||
However, it does not work on non-jailbroken iOS devices,
|
||||
although the compilation is successful. */
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
sys_icache_invalidate((char*)(from), (char*)(to) - (char*)(from))
|
||||
|
||||
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
|
||||
/* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
ppc_cache_flush((from), (to))
|
||||
#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
|
||||
|
||||
#elif (defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
__builtin___clear_cache((char*)from, (char*)to)
|
||||
|
||||
#elif defined __ANDROID__
|
||||
|
||||
/* Android lacks __clear_cache; instead, cacheflush should be used. */
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
cacheflush((long)(from), (long)(to), 0)
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
|
||||
/* The __clear_cache() implementation of GCC is a dummy function on Sparc. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
sparc_cache_flush((from), (to))
|
||||
#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_64 && defined _MSC_VER )
|
||||
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
FlushInstructionCache(GetCurrentProcess(),(char*)from, ((char*)to) - ((char *)from) );
|
||||
|
||||
#else
|
||||
|
||||
/* Calls __ARM_NR_cacheflush on ARM-Linux. */
|
||||
#define SLJIT_CACHE_FLUSH(from, to) \
|
||||
__clear_cache((char*)(from), (char*)(to))
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_CACHE_FLUSH */
|
||||
|
||||
/******************************************************/
|
||||
/* Integer and floating point type definitions. */
|
||||
/******************************************************/
|
||||
|
||||
/* 8 bit byte type. */
|
||||
typedef unsigned char sljit_u8;
|
||||
typedef signed char sljit_s8;
|
||||
|
||||
/* 16 bit half-word type. */
|
||||
typedef unsigned short int sljit_u16;
|
||||
typedef signed short int sljit_s16;
|
||||
|
||||
/* 32 bit integer type. */
|
||||
typedef unsigned int sljit_u32;
|
||||
typedef signed int sljit_s32;
|
||||
|
||||
/* Machine word type. Enough for storing a pointer.
|
||||
32 bit for 32 bit machines.
|
||||
64 bit for 64 bit machines. */
|
||||
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
/* Just to have something. */
|
||||
#define SLJIT_WORD_SHIFT 0
|
||||
typedef unsigned long int sljit_uw;
|
||||
typedef long int sljit_sw;
|
||||
#elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
&& !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|
||||
&& !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|
||||
&& !(defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
|
||||
#define SLJIT_32BIT_ARCHITECTURE 1
|
||||
#define SLJIT_WORD_SHIFT 2
|
||||
typedef unsigned int sljit_uw;
|
||||
typedef int sljit_sw;
|
||||
#else
|
||||
#define SLJIT_64BIT_ARCHITECTURE 1
|
||||
#define SLJIT_WORD_SHIFT 3
|
||||
#ifdef _WIN32
|
||||
typedef unsigned __int64 sljit_uw;
|
||||
typedef __int64 sljit_sw;
|
||||
#else
|
||||
typedef unsigned long int sljit_uw;
|
||||
typedef long int sljit_sw;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef sljit_uw sljit_p;
|
||||
|
||||
/* Floating point types. */
|
||||
typedef float sljit_f32;
|
||||
typedef double sljit_f64;
|
||||
|
||||
/* Shift for pointer sized data. */
|
||||
#define SLJIT_POINTER_SHIFT SLJIT_WORD_SHIFT
|
||||
|
||||
/* Shift for double precision sized data. */
|
||||
#define SLJIT_F32_SHIFT 2
|
||||
#define SLJIT_F64_SHIFT 3
|
||||
|
||||
#ifndef SLJIT_W
|
||||
|
||||
/* Defining long constants. */
|
||||
#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
|
||||
#define SLJIT_W(w) (w##ll)
|
||||
#else
|
||||
#define SLJIT_W(w) (w)
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_W */
|
||||
|
||||
/*************************/
|
||||
/* Endianness detection. */
|
||||
/*************************/
|
||||
|
||||
#if !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN)
|
||||
|
||||
/* These macros are mostly useful for the applications. */
|
||||
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#define SLJIT_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#define SLJIT_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|
||||
|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
|
||||
|
||||
#ifdef __MIPSEL__
|
||||
#define SLJIT_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#define SLJIT_BIG_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
|
||||
#define SLJIT_BIG_ENDIAN 1
|
||||
|
||||
#else
|
||||
#define SLJIT_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#endif /* !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN) */
|
||||
|
||||
/* Sanity check. */
|
||||
#if (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
|
||||
#error "Exactly one endianness must be selected"
|
||||
#endif
|
||||
|
||||
#if !(defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && !(defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
|
||||
#error "Exactly one endianness must be selected"
|
||||
#endif
|
||||
|
||||
#ifndef SLJIT_UNALIGNED
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|
||||
|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|
||||
|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|
||||
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|
||||
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|
||||
|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|
||||
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
|
||||
#define SLJIT_UNALIGNED 1
|
||||
#endif
|
||||
|
||||
#endif /* !SLJIT_UNALIGNED */
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
/* Auto detect SSE2 support using CPUID.
|
||||
On 64 bit x86 cpus, sse2 must be present. */
|
||||
#define SLJIT_DETECT_SSE2 1
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************/
|
||||
/* Calling convention of functions generated by SLJIT or called from the generated code. */
|
||||
/*****************************************************************************************/
|
||||
|
||||
#ifndef SLJIT_CALL
|
||||
|
||||
#if (defined SLJIT_USE_CDECL_CALLING_CONVENTION && SLJIT_USE_CDECL_CALLING_CONVENTION)
|
||||
|
||||
/* Force cdecl. */
|
||||
#define SLJIT_CALL
|
||||
|
||||
#elif (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
|
||||
#if defined(__GNUC__) && !defined(__APPLE__)
|
||||
|
||||
#define SLJIT_CALL __attribute__ ((fastcall))
|
||||
#define SLJIT_X86_32_FASTCALL 1
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#define SLJIT_CALL __fastcall
|
||||
#define SLJIT_X86_32_FASTCALL 1
|
||||
|
||||
#elif defined(__BORLANDC__)
|
||||
|
||||
#define SLJIT_CALL __msfastcall
|
||||
#define SLJIT_X86_32_FASTCALL 1
|
||||
|
||||
#else /* Unknown compiler. */
|
||||
|
||||
/* The cdecl attribute is the default. */
|
||||
#define SLJIT_CALL
|
||||
|
||||
#endif
|
||||
|
||||
#else /* Non x86-32 architectures. */
|
||||
|
||||
#define SLJIT_CALL
|
||||
|
||||
#endif /* SLJIT_CONFIG_X86_32 */
|
||||
|
||||
#endif /* !SLJIT_CALL */
|
||||
|
||||
#ifndef SLJIT_INDIRECT_CALL
|
||||
#if ((defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) && (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN)) \
|
||||
|| ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && defined _AIX)
|
||||
/* It seems certain ppc compilers use an indirect addressing for functions
|
||||
which makes things complicated. */
|
||||
#define SLJIT_INDIRECT_CALL 1
|
||||
#endif
|
||||
#endif /* SLJIT_INDIRECT_CALL */
|
||||
|
||||
/* The offset which needs to be substracted from the return address to
|
||||
determine the next executed instruction after return. */
|
||||
#ifndef SLJIT_RETURN_ADDRESS_OFFSET
|
||||
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
#define SLJIT_RETURN_ADDRESS_OFFSET 8
|
||||
#else
|
||||
#define SLJIT_RETURN_ADDRESS_OFFSET 0
|
||||
#endif
|
||||
#endif /* SLJIT_RETURN_ADDRESS_OFFSET */
|
||||
|
||||
/***************************************************/
|
||||
/* Functions of the built-in executable allocator. */
|
||||
/***************************************************/
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size);
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr);
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
|
||||
#define SLJIT_MALLOC_EXEC(size) sljit_malloc_exec(size)
|
||||
#define SLJIT_FREE_EXEC(ptr) sljit_free_exec(ptr)
|
||||
|
||||
#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
|
||||
#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
|
||||
#else
|
||||
#define SLJIT_EXEC_OFFSET(ptr) 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************/
|
||||
/* Registers and locals offset determination. */
|
||||
/**********************************************/
|
||||
|
||||
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 9
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#else
|
||||
/* Maximum 3 arguments are passed on the stack, +1 for double alignment. */
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#endif /* SLJIT_X86_32_FASTCALL */
|
||||
|
||||
#elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
|
||||
|
||||
#ifndef _WIN64
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 6
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
#else
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
|
||||
#endif /* _WIN64 */
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 12
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 25
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 10
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (2 * sizeof(sljit_sw))
|
||||
|
||||
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 22
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 17
|
||||
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined _AIX)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((6 + 8) * sizeof(sljit_sw))
|
||||
#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
|
||||
/* Add +1 for double alignment. */
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((3 + 1) * sizeof(sljit_sw))
|
||||
#else
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (3 * sizeof(sljit_sw))
|
||||
#endif /* SLJIT_CONFIG_PPC_64 || _AIX */
|
||||
|
||||
#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 21
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
|
||||
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
|
||||
#define SLJIT_LOCALS_OFFSET_BASE (4 * sizeof(sljit_sw))
|
||||
#else
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_SPARC && SLJIT_CONFIG_SPARC)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 18
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 14
|
||||
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
|
||||
/* Add +1 for double alignment. */
|
||||
#define SLJIT_LOCALS_OFFSET_BASE ((23 + 1) * sizeof(sljit_sw))
|
||||
#endif
|
||||
|
||||
#elif (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 10
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 5
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
|
||||
|
||||
#define SLJIT_NUMBER_OF_REGISTERS 0
|
||||
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 0
|
||||
#define SLJIT_LOCALS_OFFSET_BASE 0
|
||||
|
||||
#endif
|
||||
|
||||
#define SLJIT_LOCALS_OFFSET (SLJIT_LOCALS_OFFSET_BASE)
|
||||
|
||||
#define SLJIT_NUMBER_OF_SCRATCH_REGISTERS \
|
||||
(SLJIT_NUMBER_OF_REGISTERS - SLJIT_NUMBER_OF_SAVED_REGISTERS)
|
||||
|
||||
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 6
|
||||
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && (defined _WIN64)
|
||||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 1
|
||||
#else
|
||||
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
|
||||
#endif
|
||||
|
||||
#define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \
|
||||
(SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS)
|
||||
|
||||
/*************************************/
|
||||
/* Debug and verbose related macros. */
|
||||
/*************************************/
|
||||
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
|
||||
|
||||
#if !defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE)
|
||||
|
||||
/* SLJIT_HALT_PROCESS must halt the process. */
|
||||
#ifndef SLJIT_HALT_PROCESS
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SLJIT_HALT_PROCESS() \
|
||||
abort();
|
||||
#endif /* !SLJIT_HALT_PROCESS */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#endif /* !SLJIT_ASSERT || !SLJIT_UNREACHABLE */
|
||||
|
||||
/* Feel free to redefine these two macros. */
|
||||
#ifndef SLJIT_ASSERT
|
||||
|
||||
#define SLJIT_ASSERT(x) \
|
||||
do { \
|
||||
if (SLJIT_UNLIKELY(!(x))) { \
|
||||
printf("Assertion failed at " __FILE__ ":%d\n", __LINE__); \
|
||||
SLJIT_HALT_PROCESS(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* !SLJIT_ASSERT */
|
||||
|
||||
#ifndef SLJIT_UNREACHABLE
|
||||
|
||||
#define SLJIT_UNREACHABLE() \
|
||||
do { \
|
||||
printf("Should never been reached " __FILE__ ":%d\n", __LINE__); \
|
||||
SLJIT_HALT_PROCESS(); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !SLJIT_UNREACHABLE */
|
||||
|
||||
#else /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
|
||||
|
||||
/* Forcing empty, but valid statements. */
|
||||
#undef SLJIT_ASSERT
|
||||
#undef SLJIT_UNREACHABLE
|
||||
|
||||
#define SLJIT_ASSERT(x) \
|
||||
do { } while (0)
|
||||
#define SLJIT_UNREACHABLE() \
|
||||
do { } while (0)
|
||||
|
||||
#endif /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
|
||||
|
||||
#ifndef SLJIT_COMPILE_ASSERT
|
||||
|
||||
#define SLJIT_COMPILE_ASSERT(x, description) \
|
||||
switch(0) { case 0: case ((x) ? 1 : 0): break; }
|
||||
|
||||
#endif /* !SLJIT_COMPILE_ASSERT */
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file contains a simple executable memory allocator
|
||||
|
||||
It is assumed, that executable code blocks are usually medium (or sometimes
|
||||
large) memory blocks, and the allocator is not too frequently called (less
|
||||
optimized than other allocators). Thus, using it as a generic allocator is
|
||||
not suggested.
|
||||
|
||||
How does it work:
|
||||
Memory is allocated in continuous memory areas called chunks by alloc_chunk()
|
||||
Chunk format:
|
||||
[ block ][ block ] ... [ block ][ block terminator ]
|
||||
|
||||
All blocks and the block terminator is started with block_header. The block
|
||||
header contains the size of the previous and the next block. These sizes
|
||||
can also contain special values.
|
||||
Block size:
|
||||
0 - The block is a free_block, with a different size member.
|
||||
1 - The block is a block terminator.
|
||||
n - The block is used at the moment, and the value contains its size.
|
||||
Previous block size:
|
||||
0 - This is the first block of the memory chunk.
|
||||
n - The size of the previous block.
|
||||
|
||||
Using these size values we can go forward or backward on the block chain.
|
||||
The unused blocks are stored in a chain list pointed by free_blocks. This
|
||||
list is useful if we need to find a suitable memory area when the allocator
|
||||
is called.
|
||||
|
||||
When a block is freed, the new free block is connected to its adjacent free
|
||||
blocks if possible.
|
||||
|
||||
[ free block ][ used block ][ free block ]
|
||||
and "used block" is freed, the three blocks are connected together:
|
||||
[ one big free block ]
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* System (OS) functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* 64 KByte. */
|
||||
#define CHUNK_SIZE 0x10000
|
||||
|
||||
/*
|
||||
alloc_chunk / free_chunk :
|
||||
* allocate executable system memory chunks
|
||||
* the size is always divisible by CHUNK_SIZE
|
||||
allocator_grab_lock / allocator_release_lock :
|
||||
* make the allocator thread safe
|
||||
* can be empty if the OS (or the application) does not support threading
|
||||
* only the allocator requires this lock, sljit is fully thread safe
|
||||
as it only uses local variables
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
|
||||
{
|
||||
return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(size);
|
||||
VirtualFree(chunk, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
|
||||
{
|
||||
void *retval;
|
||||
|
||||
#ifdef MAP_ANON
|
||||
retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#else
|
||||
if (dev_zero < 0) {
|
||||
if (open_dev_zero())
|
||||
return NULL;
|
||||
}
|
||||
retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, dev_zero, 0);
|
||||
#endif
|
||||
|
||||
return (retval != MAP_FAILED) ? retval : NULL;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
|
||||
{
|
||||
munmap(chunk, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Common functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define CHUNK_MASK (~(CHUNK_SIZE - 1))
|
||||
|
||||
struct block_header {
|
||||
sljit_uw size;
|
||||
sljit_uw prev_size;
|
||||
};
|
||||
|
||||
struct free_block {
|
||||
struct block_header header;
|
||||
struct free_block *next;
|
||||
struct free_block *prev;
|
||||
sljit_uw size;
|
||||
};
|
||||
|
||||
#define AS_BLOCK_HEADER(base, offset) \
|
||||
((struct block_header*)(((sljit_u8*)base) + offset))
|
||||
#define AS_FREE_BLOCK(base, offset) \
|
||||
((struct free_block*)(((sljit_u8*)base) + offset))
|
||||
#define MEM_START(base) ((void*)(((sljit_u8*)base) + sizeof(struct block_header)))
|
||||
#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7) & ~7)
|
||||
|
||||
static struct free_block* free_blocks;
|
||||
static sljit_uw allocated_size;
|
||||
static sljit_uw total_size;
|
||||
|
||||
static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
|
||||
{
|
||||
free_block->header.size = 0;
|
||||
free_block->size = size;
|
||||
|
||||
free_block->next = free_blocks;
|
||||
free_block->prev = NULL;
|
||||
if (free_blocks)
|
||||
free_blocks->prev = free_block;
|
||||
free_blocks = free_block;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
|
||||
{
|
||||
if (free_block->next)
|
||||
free_block->next->prev = free_block->prev;
|
||||
|
||||
if (free_block->prev)
|
||||
free_block->prev->next = free_block->next;
|
||||
else {
|
||||
SLJIT_ASSERT(free_blocks == free_block);
|
||||
free_blocks = free_block->next;
|
||||
}
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
||||
{
|
||||
struct block_header *header;
|
||||
struct block_header *next_header;
|
||||
struct free_block *free_block;
|
||||
sljit_uw chunk_size;
|
||||
|
||||
allocator_grab_lock();
|
||||
if (size < (64 - sizeof(struct block_header)))
|
||||
size = (64 - sizeof(struct block_header));
|
||||
size = ALIGN_SIZE(size);
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
if (free_block->size >= size) {
|
||||
chunk_size = free_block->size;
|
||||
if (chunk_size > size + 64) {
|
||||
/* We just cut a block from the end of the free block. */
|
||||
chunk_size -= size;
|
||||
free_block->size = chunk_size;
|
||||
header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
header->prev_size = chunk_size;
|
||||
AS_BLOCK_HEADER(header, size)->prev_size = size;
|
||||
}
|
||||
else {
|
||||
sljit_remove_free_block(free_block);
|
||||
header = (struct block_header*)free_block;
|
||||
size = chunk_size;
|
||||
}
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
free_block = free_block->next;
|
||||
}
|
||||
|
||||
chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK;
|
||||
header = (struct block_header*)alloc_chunk(chunk_size);
|
||||
if (!header) {
|
||||
allocator_release_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chunk_size -= sizeof(struct block_header);
|
||||
total_size += chunk_size;
|
||||
|
||||
header->prev_size = 0;
|
||||
if (chunk_size > size + 64) {
|
||||
/* Cut the allocated space into a free and a used block. */
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
chunk_size -= size;
|
||||
|
||||
free_block = AS_FREE_BLOCK(header, size);
|
||||
free_block->header.prev_size = size;
|
||||
sljit_insert_free_block(free_block, chunk_size);
|
||||
next_header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
}
|
||||
else {
|
||||
/* All space belongs to this allocation. */
|
||||
allocated_size += chunk_size;
|
||||
header->size = chunk_size;
|
||||
next_header = AS_BLOCK_HEADER(header, chunk_size);
|
||||
}
|
||||
next_header->size = 1;
|
||||
next_header->prev_size = chunk_size;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
|
||||
{
|
||||
struct block_header *header;
|
||||
struct free_block* free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
|
||||
allocated_size -= header->size;
|
||||
|
||||
/* Connecting free blocks together if possible. */
|
||||
|
||||
/* If header->prev_size == 0, free_block will equal to header.
|
||||
In this case, free_block->header.size will be > 0. */
|
||||
free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
|
||||
if (SLJIT_UNLIKELY(!free_block->header.size)) {
|
||||
free_block->size += header->size;
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
else {
|
||||
free_block = (struct free_block*)header;
|
||||
sljit_insert_free_block(free_block, header->size);
|
||||
}
|
||||
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
if (SLJIT_UNLIKELY(!header->size)) {
|
||||
free_block->size += ((struct free_block*)header)->size;
|
||||
sljit_remove_free_block((struct free_block*)header);
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
|
||||
/* The whole chunk is free. */
|
||||
if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
|
||||
/* If this block is freed, we still have (allocated_size / 2) free space. */
|
||||
if (total_size - free_block->size > (allocated_size * 3 / 2)) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
}
|
||||
|
||||
allocator_release_lock();
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
|
||||
{
|
||||
struct free_block* free_block;
|
||||
struct free_block* next_free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
next_free_block = free_block->next;
|
||||
if (!free_block->header.prev_size &&
|
||||
AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
free_block = next_free_block;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
|
||||
allocator_release_lock();
|
||||
}
|
||||
2147
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/sljitLir.c
Normal file
2147
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/sljitLir.c
Normal file
File diff suppressed because it is too large
Load Diff
1385
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/sljitLir.h
Normal file
1385
Kha/Backends/Kore-hxcpp/khacpp/src/hx/cppia/sljit_src/sljitLir.h
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* mips 32-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
|
||||
{
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
if (imm < 0 && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define EMIT_LOGICAL(op_imm, op_norm) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
#define EMIT_SHIFT(op_imm, op_v) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
sljit_s32 is_overflow, is_carry, is_handled;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
|
||||
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(24), DR(dst));
|
||||
#endif
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst));
|
||||
#endif
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, CLZ | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, CLZ | S(src2) | T(dst) | D(dst), DR(dst)));
|
||||
#else
|
||||
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
|
||||
FAIL_IF(push_inst(compiler, SRL | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
|
||||
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
|
||||
}
|
||||
/* Nearly all instructions are unmovable in the following sequence. */
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
/* Check zero. */
|
||||
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(32), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(dst) | IMM(-1), DR(dst)));
|
||||
/* Loop for searching the highest bit. */
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(dst) | T(dst) | IMM(1), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
|
||||
if (op & SLJIT_SET_Z)
|
||||
return push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ADD:
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
/* a + b >= a | b (otherwise, the carry should be set to 1). */
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_ADDC:
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
} else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
if (!is_carry)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* Set carry flag. */
|
||||
return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUB:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_handled = 0;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
|
||||
is_handled = 1;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_handled) {
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SUBU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MUL:
|
||||
SLJIT_ASSERT(!(flags & SRC2_IMM));
|
||||
|
||||
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW && GET_FLAG_TYPE(op) != SLJIT_MUL_NOT_OVERFLOW) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
return push_inst(compiler, MFLO | D(dst), DR(dst));
|
||||
#endif
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, SRA | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
|
||||
return push_inst(compiler, SUBU | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_AND:
|
||||
EMIT_LOGICAL(ANDI, AND);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_OR:
|
||||
EMIT_LOGICAL(ORI, OR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_XOR:
|
||||
EMIT_LOGICAL(XORI, XOR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_SHL:
|
||||
EMIT_SHIFT(SLL, SLLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_LSHR:
|
||||
EMIT_SHIFT(SRL, SRLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ASHR:
|
||||
EMIT_SHIFT(SRA, SRAV);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
|
||||
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
@ -0,0 +1,541 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* mips 64-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
|
||||
{
|
||||
sljit_s32 shift = 32;
|
||||
sljit_s32 shift2;
|
||||
sljit_s32 inv = 0;
|
||||
sljit_ins ins;
|
||||
sljit_uw uimm;
|
||||
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
if (imm < 0 && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
|
||||
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
|
||||
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Zero extended number. */
|
||||
uimm = imm;
|
||||
if (imm < 0) {
|
||||
uimm = ~imm;
|
||||
inv = 1;
|
||||
}
|
||||
|
||||
while (!(uimm & 0xff00000000000000l)) {
|
||||
shift -= 8;
|
||||
uimm <<= 8;
|
||||
}
|
||||
|
||||
if (!(uimm & 0xf000000000000000l)) {
|
||||
shift -= 4;
|
||||
uimm <<= 4;
|
||||
}
|
||||
|
||||
if (!(uimm & 0xc000000000000000l)) {
|
||||
shift -= 2;
|
||||
uimm <<= 2;
|
||||
}
|
||||
|
||||
if ((sljit_sw)uimm < 0) {
|
||||
uimm >>= 1;
|
||||
shift += 1;
|
||||
}
|
||||
SLJIT_ASSERT(((uimm & 0xc000000000000000l) == 0x4000000000000000l) && (shift > 0) && (shift <= 32));
|
||||
|
||||
if (inv)
|
||||
uimm = ~uimm;
|
||||
|
||||
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
|
||||
if (uimm & 0x0000ffff00000000l)
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 32), dst_ar));
|
||||
|
||||
imm &= (1l << shift) - 1;
|
||||
if (!(imm & ~0xffff)) {
|
||||
ins = (shift == 32) ? DSLL32 : DSLL;
|
||||
if (shift < 32)
|
||||
ins |= SH_IMM(shift);
|
||||
FAIL_IF(push_inst(compiler, ins | TA(dst_ar) | DA(dst_ar), dst_ar));
|
||||
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
}
|
||||
|
||||
/* Double shifts needs to be performed. */
|
||||
uimm <<= 32;
|
||||
shift2 = shift - 16;
|
||||
|
||||
while (!(uimm & 0xf000000000000000l)) {
|
||||
shift2 -= 4;
|
||||
uimm <<= 4;
|
||||
}
|
||||
|
||||
if (!(uimm & 0xc000000000000000l)) {
|
||||
shift2 -= 2;
|
||||
uimm <<= 2;
|
||||
}
|
||||
|
||||
if (!(uimm & 0x8000000000000000l)) {
|
||||
shift2--;
|
||||
uimm <<= 1;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT((uimm & 0x8000000000000000l) && (shift2 > 0) && (shift2 <= 16));
|
||||
|
||||
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift - shift2), dst_ar));
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
|
||||
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift2), dst_ar));
|
||||
|
||||
imm &= (1l << shift2) - 1;
|
||||
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
|
||||
}
|
||||
|
||||
#define SELECT_OP(a, b) \
|
||||
(!(op & SLJIT_I32_OP) ? a : b)
|
||||
|
||||
#define EMIT_LOGICAL(op_imm, op_norm) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
#define EMIT_SHIFT(op_dimm, op_dimm32, op_imm, op_dv, op_v) \
|
||||
if (flags & SRC2_IMM) { \
|
||||
if (src2 >= 32) { \
|
||||
SLJIT_ASSERT(!(op & SLJIT_I32_OP)); \
|
||||
ins = op_dimm32; \
|
||||
src2 -= 32; \
|
||||
} \
|
||||
else \
|
||||
ins = (op & SLJIT_I32_OP) ? op_imm : op_dimm; \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, ins | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, ins | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
|
||||
} \
|
||||
else { \
|
||||
ins = (op & SLJIT_I32_OP) ? op_v : op_dv; \
|
||||
if (op & SLJIT_SET_Z) \
|
||||
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
|
||||
if (!(flags & UNUSED_DEST)) \
|
||||
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | D(dst), DR(dst))); \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
sljit_ins ins;
|
||||
sljit_s32 is_overflow, is_carry, is_handled;
|
||||
|
||||
switch (GET_OPCODE(op)) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(dst), DR(dst));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8) {
|
||||
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
|
||||
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(24), DR(dst));
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16) {
|
||||
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(16), DR(dst));
|
||||
}
|
||||
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U32:
|
||||
SLJIT_ASSERT(!(op & SLJIT_I32_OP));
|
||||
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(0), DR(dst)));
|
||||
return push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst));
|
||||
|
||||
case SLJIT_MOV_S32:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
return push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(0), DR(dst));
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | T(dst) | D(dst), DR(dst)));
|
||||
#else
|
||||
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
|
||||
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
|
||||
}
|
||||
/* Nearly all instructions are unmovable in the following sequence. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
/* Check zero. */
|
||||
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM((op & SLJIT_I32_OP) ? 32 : 64), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(dst) | IMM(-1), DR(dst)));
|
||||
/* Loop for searching the highest bit. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(dst) | T(dst) | IMM(1), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL, SLL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
|
||||
if (op & SLJIT_SET_Z)
|
||||
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ADD:
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
/* a + b >= a | b (otherwise, the carry should be set to 1). */
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_ADDC:
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
else {
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
|
||||
} else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
if (!is_carry)
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* Set carry flag. */
|
||||
return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUB:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_handled = 0;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
is_handled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
|
||||
is_handled = 1;
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_handled) {
|
||||
if (flags & SRC2_IMM) {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst));
|
||||
}
|
||||
else {
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
if (!(flags & UNUSED_DEST))
|
||||
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW || GET_FLAG_TYPE(op) == SLJIT_NOT_OVERFLOW;
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_overflow) {
|
||||
if (src2 >= 0)
|
||||
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else
|
||||
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
}
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_overflow)
|
||||
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
else if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
|
||||
if (is_overflow || is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (!is_overflow)
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
|
||||
if (op & SLJIT_SET_Z)
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
|
||||
|
||||
case SLJIT_SUBC:
|
||||
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
|
||||
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
|
||||
src2 = TMP_REG2;
|
||||
flags &= ~SRC2_IMM;
|
||||
}
|
||||
|
||||
is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
|
||||
|
||||
if (flags & SRC2_IMM) {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
|
||||
}
|
||||
else {
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
/* dst may be the same as src1 or src2. */
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
|
||||
}
|
||||
|
||||
if (is_carry)
|
||||
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
|
||||
return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MUL:
|
||||
SLJIT_ASSERT(!(flags & SRC2_IMM));
|
||||
|
||||
if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW && GET_FLAG_TYPE(op) != SLJIT_MUL_NOT_OVERFLOW) {
|
||||
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
|
||||
if (op & SLJIT_I32_OP)
|
||||
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
|
||||
FAIL_IF(push_inst(compiler, DMULT | S(src1) | T(src2), MOVABLE_INS));
|
||||
return push_inst(compiler, MFLO | D(dst), DR(dst));
|
||||
#else
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
|
||||
return push_inst(compiler, MFLO | D(dst), DR(dst));
|
||||
#endif
|
||||
}
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
|
||||
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, SELECT_OP(DSRA32, SRA) | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
|
||||
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
|
||||
|
||||
case SLJIT_AND:
|
||||
EMIT_LOGICAL(ANDI, AND);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_OR:
|
||||
EMIT_LOGICAL(ORI, OR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_XOR:
|
||||
EMIT_LOGICAL(XORI, XOR);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_SHL:
|
||||
EMIT_SHIFT(DSLL, DSLL32, SLL, DSLLV, SLLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_LSHR:
|
||||
EMIT_SHIFT(DSRL, DSRL32, SRL, DSRLV, SRLV);
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_ASHR:
|
||||
EMIT_SHIFT(DSRA, DSRA32, SRA, DSRAV, SRAV);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 48), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 32), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 16), DR(dst)));
|
||||
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
|
||||
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[5] = (inst[5] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 6);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[5] = (inst[5] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 6);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* ppc 32-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
|
||||
{
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
|
||||
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
|
||||
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define INS_CLEAR_LEFT(dst, src, from) \
|
||||
(RLWINM | S(src) | A(dst) | ((from) << 6) | (31 << 1))
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
|
||||
{
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
|
||||
}
|
||||
else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16)
|
||||
return push_inst(compiler, EXTSH | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_NEG:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst));
|
||||
|
||||
case SLJIT_ADD:
|
||||
if (flags & ALT_FORM1) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM4) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff)));
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(dst) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1)));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
|
||||
return push_inst(compiler, ADDC | OERC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_SUB:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM2 | ALT_FORM3)) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? CMPI : CMPLI) | CRD(0) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM4 | ALT_FORM5)) {
|
||||
return push_inst(compiler, ((flags & ALT_FORM4) ? CMP : CMPL) | CRD(0) | A(src1) | B(src2));
|
||||
}
|
||||
if (flags & ALT_FORM6) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, CMPLI | CRD(0) | A(src1) | compiler->imm));
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
|
||||
}
|
||||
if (flags & ALT_FORM7) {
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(0) | A(src1) | B(src2)));
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, SUBFC | OERC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_MUL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, MULLW | OERC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_AND:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_OR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_XOR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_SHL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
|
||||
}
|
||||
return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_LSHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
|
||||
}
|
||||
return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_ASHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
|
||||
}
|
||||
return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16)));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* ppc 64-bit arch dependent functions. */
|
||||
|
||||
#if defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)
|
||||
#define ASM_SLJIT_CLZ(src, dst) \
|
||||
__asm__ volatile ( "cntlzd %0, %1" : "=r"(dst) : "r"(src) )
|
||||
#elif defined(__xlc__)
|
||||
#error "Please enable GCC syntax for inline assembly statements"
|
||||
#else
|
||||
#error "Must implement count leading zeroes"
|
||||
#endif
|
||||
|
||||
#define RLDI(dst, src, sh, mb, type) \
|
||||
(HI(30) | S(src) | A(dst) | ((type) << 2) | (((sh) & 0x1f) << 11) | (((sh) & 0x20) >> 4) | (((mb) & 0x1f) << 6) | ((mb) & 0x20))
|
||||
|
||||
#define PUSH_RLDICR(reg, shift) \
|
||||
push_inst(compiler, RLDI(reg, reg, 63 - shift, shift, 1))
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
|
||||
{
|
||||
sljit_uw tmp;
|
||||
sljit_uw shift;
|
||||
sljit_uw tmp2;
|
||||
sljit_uw shift2;
|
||||
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
|
||||
|
||||
if (!(imm & ~0xffff))
|
||||
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
|
||||
|
||||
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Count leading zeroes. */
|
||||
tmp = (imm >= 0) ? imm : ~imm;
|
||||
ASM_SLJIT_CLZ(tmp, shift);
|
||||
SLJIT_ASSERT(shift > 0);
|
||||
shift--;
|
||||
tmp = (imm << shift);
|
||||
|
||||
if ((tmp & ~0xffff000000000000ul) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
shift += 15;
|
||||
return PUSH_RLDICR(reg, shift);
|
||||
}
|
||||
|
||||
if ((tmp & ~0xffffffff00000000ul) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp >> 32)));
|
||||
shift += 31;
|
||||
return PUSH_RLDICR(reg, shift);
|
||||
}
|
||||
|
||||
/* Cut out the 16 bit from immediate. */
|
||||
shift += 15;
|
||||
tmp2 = imm & ((1ul << (63 - shift)) - 1);
|
||||
|
||||
if (tmp2 <= 0xffff) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, shift));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | tmp2);
|
||||
}
|
||||
|
||||
if (tmp2 <= 0xffffffff) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, shift));
|
||||
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | (tmp2 >> 16)));
|
||||
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp2)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
ASM_SLJIT_CLZ(tmp2, shift2);
|
||||
tmp2 <<= shift2;
|
||||
|
||||
if ((tmp2 & ~0xffff000000000000ul) == 0) {
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
|
||||
shift2 += 15;
|
||||
shift += (63 - shift2);
|
||||
FAIL_IF(PUSH_RLDICR(reg, shift));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | (tmp2 >> 48)));
|
||||
return PUSH_RLDICR(reg, shift2);
|
||||
}
|
||||
|
||||
/* The general version. */
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 48)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm >> 32)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, 31));
|
||||
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(imm >> 16)));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm));
|
||||
}
|
||||
|
||||
/* Simplified mnemonics: clrldi. */
|
||||
#define INS_CLEAR_LEFT(dst, src, from) \
|
||||
(RLDICL | S(src) | A(dst) | ((from) << 6) | (1 << 5))
|
||||
|
||||
/* Sign extension for integer operations. */
|
||||
#define UN_EXTS() \
|
||||
if ((flags & (ALT_SIGN_EXT | REG2_SOURCE)) == (ALT_SIGN_EXT | REG2_SOURCE)) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
|
||||
src2 = TMP_REG2; \
|
||||
}
|
||||
|
||||
#define BIN_EXTS() \
|
||||
if (flags & ALT_SIGN_EXT) { \
|
||||
if (flags & REG1_SOURCE) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
|
||||
src1 = TMP_REG1; \
|
||||
} \
|
||||
if (flags & REG2_SOURCE) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
|
||||
src2 = TMP_REG2; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define BIN_IMM_EXTS() \
|
||||
if ((flags & (ALT_SIGN_EXT | REG1_SOURCE)) == (ALT_SIGN_EXT | REG1_SOURCE)) { \
|
||||
FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
|
||||
src1 = TMP_REG1; \
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
|
||||
{
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S32)
|
||||
return push_inst(compiler, EXTSW | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 0));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
|
||||
}
|
||||
else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
|
||||
return push_inst(compiler, EXTSB | S(src2) | A(dst));
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_S16)
|
||||
return push_inst(compiler, EXTSH | S(src2) | A(dst));
|
||||
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(dst == src2);
|
||||
}
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
UN_EXTS();
|
||||
return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_NEG:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
UN_EXTS();
|
||||
return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1);
|
||||
if (flags & ALT_FORM1)
|
||||
return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst));
|
||||
return push_inst(compiler, CNTLZD | RC(flags) | S(src2) | A(dst));
|
||||
|
||||
case SLJIT_ADD:
|
||||
if (flags & ALT_FORM1) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
BIN_IMM_EXTS();
|
||||
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM4) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff)));
|
||||
return push_inst(compiler, ADDIS | D(dst) | A(dst) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1)));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, ADDC | OERC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
|
||||
|
||||
case SLJIT_SUB:
|
||||
if (flags & ALT_FORM1) {
|
||||
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM2 | ALT_FORM3)) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? CMPI : CMPLI) | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm);
|
||||
}
|
||||
if (flags & (ALT_FORM4 | ALT_FORM5)) {
|
||||
return push_inst(compiler, ((flags & ALT_FORM4) ? CMP : CMPL) | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2));
|
||||
}
|
||||
if (flags & ALT_FORM6) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, CMPLI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm));
|
||||
return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
|
||||
}
|
||||
if (flags & ALT_FORM7) {
|
||||
FAIL_IF(push_inst(compiler, CMPL | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
}
|
||||
if (!(flags & ALT_SET_FLAGS))
|
||||
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, SUBFC | OERC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
BIN_EXTS();
|
||||
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_MUL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
|
||||
}
|
||||
BIN_EXTS();
|
||||
if (flags & ALT_FORM2)
|
||||
return push_inst(compiler, MULLW | OERC(flags) | D(dst) | A(src2) | B(src1));
|
||||
return push_inst(compiler, MULLD | OERC(flags) | D(dst) | A(src2) | B(src1));
|
||||
|
||||
case SLJIT_AND:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_OR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_XOR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM2) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
|
||||
}
|
||||
if (flags & ALT_FORM3) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
|
||||
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
|
||||
}
|
||||
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_SHL:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
|
||||
}
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, RLDI(dst, src1, compiler->imm, 63 - compiler->imm, 1) | RC(flags));
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SLW : SLD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_LSHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
|
||||
}
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, RLDI(dst, src1, 64 - compiler->imm, compiler->imm, 0) | RC(flags));
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SRW : SRD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
|
||||
case SLJIT_ASHR:
|
||||
if (flags & ALT_FORM1) {
|
||||
SLJIT_ASSERT(src2 == TMP_REG2);
|
||||
if (flags & ALT_FORM2) {
|
||||
compiler->imm &= 0x1f;
|
||||
return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
|
||||
}
|
||||
compiler->imm &= 0x3f;
|
||||
return push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4));
|
||||
}
|
||||
return push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2));
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 48)));
|
||||
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value >> 32)));
|
||||
FAIL_IF(PUSH_RLDICR(reg, 31));
|
||||
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(init_value >> 16)));
|
||||
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins*)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
|
||||
inst[4] = (inst[4] & 0xffff0000) | (new_target & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins*)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
|
||||
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
|
||||
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
|
||||
inst[4] = (inst[4] & 0xffff0000) | (new_constant & 0xffff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 5);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw imm)
|
||||
{
|
||||
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
|
||||
return push_inst(compiler, OR | D(dst) | S1(0) | IMM(imm), DR(dst));
|
||||
|
||||
FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((imm >> 10) & 0x3fffff), DR(dst)));
|
||||
return (imm & 0x3ff) ? push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (imm & 0x3ff), DR(dst)) : SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
#define ARG2(flags, src2) ((flags & SRC2_IMM) ? IMM(src2) : S2(src2))
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
|
||||
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
|
||||
{
|
||||
SLJIT_COMPILE_ASSERT(ICC_IS_SET == SET_FLAGS, icc_is_set_and_set_flags_must_be_the_same);
|
||||
|
||||
switch (op) {
|
||||
case SLJIT_MOV:
|
||||
case SLJIT_MOV_U32:
|
||||
case SLJIT_MOV_S32:
|
||||
case SLJIT_MOV_P:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if (dst != src2)
|
||||
return push_inst(compiler, OR | D(dst) | S1(0) | S2(src2), DR(dst));
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U8:
|
||||
case SLJIT_MOV_S8:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
if (op == SLJIT_MOV_U8)
|
||||
return push_inst(compiler, AND | D(dst) | S1(src2) | IMM(0xff), DR(dst));
|
||||
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(24), DR(dst)));
|
||||
return push_inst(compiler, SRA | D(dst) | S1(dst) | IMM(24), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_MOV_U16:
|
||||
case SLJIT_MOV_S16:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
|
||||
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(16), DR(dst)));
|
||||
return push_inst(compiler, (op == SLJIT_MOV_S16 ? SRA : SRL) | D(dst) | S1(dst) | IMM(16), DR(dst));
|
||||
}
|
||||
else if (dst != src2)
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
|
||||
case SLJIT_NOT:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
return push_inst(compiler, XNOR | (flags & SET_FLAGS) | D(dst) | S1(0) | S2(src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_CLZ:
|
||||
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
|
||||
/* sparc 32 does not support SLJIT_KEEP_FLAGS. Not sure I can fix this. */
|
||||
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(src2) | S2(0), SET_FLAGS));
|
||||
FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2(src2), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, BICC | DA(0x1) | (7 & DISP_MASK), UNMOVABLE_INS));
|
||||
FAIL_IF(push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(0) | IMM(32), UNMOVABLE_INS | (flags & SET_FLAGS)));
|
||||
FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(-1), DR(dst)));
|
||||
|
||||
/* Loop. */
|
||||
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(0), SET_FLAGS));
|
||||
FAIL_IF(push_inst(compiler, SLL | D(TMP_REG1) | S1(TMP_REG1) | IMM(1), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, BICC | DA(0xe) | (-2 & DISP_MASK), UNMOVABLE_INS));
|
||||
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_ADD:
|
||||
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_ADDC:
|
||||
return push_inst(compiler, ADDC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_SUB:
|
||||
return push_inst(compiler, SUB | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_SUBC:
|
||||
return push_inst(compiler, SUBC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_MUL:
|
||||
FAIL_IF(push_inst(compiler, SMUL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
if (!(flags & SET_FLAGS))
|
||||
return SLJIT_SUCCESS;
|
||||
FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(dst) | IMM(31), DR(TMP_REG1)));
|
||||
FAIL_IF(push_inst(compiler, RDY | D(TMP_LINK), DR(TMP_LINK)));
|
||||
return push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(TMP_LINK), MOVABLE_INS | SET_FLAGS);
|
||||
|
||||
case SLJIT_AND:
|
||||
return push_inst(compiler, AND | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_OR:
|
||||
return push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_XOR:
|
||||
return push_inst(compiler, XOR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
|
||||
|
||||
case SLJIT_SHL:
|
||||
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
|
||||
case SLJIT_LSHR:
|
||||
FAIL_IF(push_inst(compiler, SRL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
|
||||
case SLJIT_ASHR:
|
||||
FAIL_IF(push_inst(compiler, SRA | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
|
||||
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
|
||||
}
|
||||
|
||||
SLJIT_UNREACHABLE();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
|
||||
{
|
||||
FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((init_value >> 10) & 0x3fffff), DR(dst)));
|
||||
return push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (init_value & 0x3ff), DR(dst));
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffc00000) | ((new_target >> 10) & 0x3fffff);
|
||||
inst[1] = (inst[1] & 0xfffffc00) | (new_target & 0x3ff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
|
||||
{
|
||||
sljit_ins *inst = (sljit_ins *)addr;
|
||||
|
||||
inst[0] = (inst[0] & 0xffc00000) | ((new_constant >> 10) & 0x3fffff);
|
||||
inst[1] = (inst[1] & 0xfffffc00) | (new_constant & 0x3ff);
|
||||
inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
|
||||
SLJIT_CACHE_FLUSH(inst, inst + 2);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* x86 32-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 emit_do_imm(struct sljit_compiler *compiler, sljit_u8 opcode, sljit_sw imm)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_sw));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1 + sizeof(sljit_sw));
|
||||
*inst++ = opcode;
|
||||
sljit_unaligned_store_sw(inst, imm);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_s32 type, sljit_sw executable_offset)
|
||||
{
|
||||
if (type == SLJIT_JUMP) {
|
||||
*code_ptr++ = JMP_i32;
|
||||
jump->addr++;
|
||||
}
|
||||
else if (type >= SLJIT_FAST_CALL) {
|
||||
*code_ptr++ = CALL_i32;
|
||||
jump->addr++;
|
||||
}
|
||||
else {
|
||||
*code_ptr++ = GROUP_0F;
|
||||
*code_ptr++ = get_jump_code(type);
|
||||
jump->addr += 2;
|
||||
}
|
||||
|
||||
if (jump->flags & JUMP_LABEL)
|
||||
jump->flags |= PATCH_MW;
|
||||
else
|
||||
sljit_unaligned_store_sw(code_ptr, jump->u.target - (jump->addr + 4) - (sljit_uw)executable_offset);
|
||||
code_ptr += 4;
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
sljit_s32 size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
compiler->args = args;
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
/* [esp+0] for saving temporaries and third argument for calls. */
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
#else
|
||||
/* [esp+0] for saving temporaries and space for maximum three arguments. */
|
||||
if (scratches <= 1)
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->saveds_offset = ((scratches == 2) ? 2 : 3) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
if (scratches > 3)
|
||||
compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
|
||||
|
||||
compiler->locals_offset = compiler->saveds_offset;
|
||||
|
||||
if (saveds > 3)
|
||||
compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
|
||||
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
|
||||
|
||||
size = 1 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
size += (args > 0 ? (args * 2) : 0) + (args > 2 ? 2 : 0);
|
||||
#else
|
||||
size += (args > 0 ? (2 + args * 3) : 0);
|
||||
#endif
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(size);
|
||||
PUSH_REG(reg_map[TMP_REG1]);
|
||||
#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (args > 0) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[TMP_REG1] << 3) | 0x4 /* esp */;
|
||||
}
|
||||
#endif
|
||||
if (saveds > 2 || scratches > 9)
|
||||
PUSH_REG(reg_map[SLJIT_S2]);
|
||||
if (saveds > 1 || scratches > 10)
|
||||
PUSH_REG(reg_map[SLJIT_S1]);
|
||||
if (saveds > 0 || scratches > 11)
|
||||
PUSH_REG(reg_map[SLJIT_S0]);
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (args > 0) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S0] << 3) | reg_map[SLJIT_R2];
|
||||
}
|
||||
if (args > 1) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S1] << 3) | reg_map[SLJIT_R1];
|
||||
}
|
||||
if (args > 2) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | 0x4 /* esp */;
|
||||
*inst++ = 0x24;
|
||||
*inst++ = sizeof(sljit_sw) * (3 + 2); /* saveds >= 3 as well. */
|
||||
}
|
||||
#else
|
||||
if (args > 0) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S0] << 3) | reg_map[TMP_REG1];
|
||||
*inst++ = sizeof(sljit_sw) * 2;
|
||||
}
|
||||
if (args > 1) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S1] << 3) | reg_map[TMP_REG1];
|
||||
*inst++ = sizeof(sljit_sw) * 3;
|
||||
}
|
||||
if (args > 2) {
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | reg_map[TMP_REG1];
|
||||
*inst++ = sizeof(sljit_sw) * 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_ASSERT(SLJIT_LOCALS_OFFSET > 0);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Ignore pushed registers and SLJIT_LOCALS_OFFSET when computing the aligned local size. */
|
||||
saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
|
||||
#else
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
|
||||
else
|
||||
local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
|
||||
#endif
|
||||
|
||||
compiler->local_size = local_size;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (local_size > 1024) {
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_R0], local_size));
|
||||
#else
|
||||
/* Space for a single argument. This amount is excluded when the stack is allocated below. */
|
||||
local_size -= sizeof(sljit_sw);
|
||||
FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_R0], local_size));
|
||||
FAIL_IF(emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, sizeof(sljit_sw)));
|
||||
#endif
|
||||
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack)));
|
||||
}
|
||||
#endif
|
||||
|
||||
SLJIT_ASSERT(local_size > 0);
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
if (options & SLJIT_F64_ALIGNMENT) {
|
||||
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_SP, 0);
|
||||
|
||||
/* Some space might allocated during sljit_grow_stack() above on WIN32. */
|
||||
FAIL_IF(emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size + sizeof(sljit_sw)));
|
||||
|
||||
#if defined _WIN32 && !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->local_size > 1024)
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
TMP_REG1, 0, TMP_REG1, 0, SLJIT_IMM, sizeof(sljit_sw)));
|
||||
#endif
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 6);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(6);
|
||||
inst[0] = GROUP_BINARY_81;
|
||||
inst[1] = MOD_REG | AND | reg_map[SLJIT_SP];
|
||||
sljit_unaligned_store_sw(inst + 2, ~(sizeof(sljit_f64) - 1));
|
||||
|
||||
/* The real local size must be used. */
|
||||
return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), compiler->local_size, TMP_REG1, 0);
|
||||
}
|
||||
#endif
|
||||
return emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
compiler->args = args;
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
/* [esp+0] for saving temporaries and third argument for calls. */
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
#else
|
||||
/* [esp+0] for saving temporaries and space for maximum three arguments. */
|
||||
if (scratches <= 1)
|
||||
compiler->saveds_offset = 1 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->saveds_offset = ((scratches == 2) ? 2 : 3) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
if (scratches > 3)
|
||||
compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
|
||||
|
||||
compiler->locals_offset = compiler->saveds_offset;
|
||||
|
||||
if (saveds > 3)
|
||||
compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
|
||||
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
|
||||
compiler->local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
|
||||
#else
|
||||
if (options & SLJIT_F64_ALIGNMENT)
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
|
||||
else
|
||||
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
|
||||
SLJIT_ASSERT(compiler->args >= 0);
|
||||
|
||||
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
|
||||
|
||||
SLJIT_ASSERT(compiler->local_size > 0);
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
if (compiler->options & SLJIT_F64_ALIGNMENT)
|
||||
EMIT_MOV(compiler, SLJIT_SP, 0, SLJIT_MEM1(SLJIT_SP), compiler->local_size)
|
||||
else
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
|
||||
#else
|
||||
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
|
||||
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
|
||||
#endif
|
||||
|
||||
size = 2 + (compiler->scratches > 7 ? (compiler->scratches - 7) : 0) +
|
||||
(compiler->saveds <= 3 ? compiler->saveds : 3);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->args > 2)
|
||||
size += 2;
|
||||
#else
|
||||
if (compiler->args > 0)
|
||||
size += 2;
|
||||
#endif
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(size);
|
||||
|
||||
if (compiler->saveds > 0 || compiler->scratches > 11)
|
||||
POP_REG(reg_map[SLJIT_S0]);
|
||||
if (compiler->saveds > 1 || compiler->scratches > 10)
|
||||
POP_REG(reg_map[SLJIT_S1]);
|
||||
if (compiler->saveds > 2 || compiler->scratches > 9)
|
||||
POP_REG(reg_map[SLJIT_S2]);
|
||||
POP_REG(reg_map[TMP_REG1]);
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
if (compiler->args > 2)
|
||||
RET_I16(sizeof(sljit_sw));
|
||||
else
|
||||
RET();
|
||||
#else
|
||||
RET();
|
||||
#endif
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* Size contains the flags as well. */
|
||||
static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
|
||||
/* The register or immediate operand. */
|
||||
sljit_s32 a, sljit_sw imma,
|
||||
/* The general operand (not immediate). */
|
||||
sljit_s32 b, sljit_sw immb)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_u8 *buf_ptr;
|
||||
sljit_s32 flags = size & ~0xf;
|
||||
sljit_s32 inst_size;
|
||||
|
||||
/* Both cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
|
||||
/* Size flags not allowed for typed instructions. */
|
||||
SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
|
||||
/* Both size flags cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
|
||||
/* SSE2 and immediate is not possible. */
|
||||
SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
|
||||
SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
|
||||
&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
|
||||
&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
|
||||
|
||||
size &= 0xf;
|
||||
inst_size = size;
|
||||
|
||||
if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
|
||||
inst_size++;
|
||||
if (flags & EX86_PREF_66)
|
||||
inst_size++;
|
||||
|
||||
/* Calculate size of b. */
|
||||
inst_size += 1; /* mod r/m byte. */
|
||||
if (b & SLJIT_MEM) {
|
||||
if ((b & REG_MASK) == SLJIT_UNUSED)
|
||||
inst_size += sizeof(sljit_sw);
|
||||
else if (immb != 0 && !(b & OFFS_REG_MASK)) {
|
||||
/* Immediate operand. */
|
||||
if (immb <= 127 && immb >= -128)
|
||||
inst_size += sizeof(sljit_s8);
|
||||
else
|
||||
inst_size += sizeof(sljit_sw);
|
||||
}
|
||||
|
||||
if ((b & REG_MASK) == SLJIT_SP && !(b & OFFS_REG_MASK))
|
||||
b |= TO_OFFS_REG(SLJIT_SP);
|
||||
|
||||
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED)
|
||||
inst_size += 1; /* SIB byte. */
|
||||
}
|
||||
|
||||
/* Calculate size of a. */
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BIN_INS) {
|
||||
if (imma <= 127 && imma >= -128) {
|
||||
inst_size += 1;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
} else
|
||||
inst_size += 4;
|
||||
}
|
||||
else if (flags & EX86_SHIFT_INS) {
|
||||
imma &= 0x1f;
|
||||
if (imma != 1) {
|
||||
inst_size ++;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
}
|
||||
} else if (flags & EX86_BYTE_ARG)
|
||||
inst_size++;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
inst_size += sizeof(short);
|
||||
else
|
||||
inst_size += sizeof(sljit_sw);
|
||||
}
|
||||
else
|
||||
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
|
||||
PTR_FAIL_IF(!inst);
|
||||
|
||||
/* Encoding the byte. */
|
||||
INC_SIZE(inst_size);
|
||||
if (flags & EX86_PREF_F2)
|
||||
*inst++ = 0xf2;
|
||||
if (flags & EX86_PREF_F3)
|
||||
*inst++ = 0xf3;
|
||||
if (flags & EX86_PREF_66)
|
||||
*inst++ = 0x66;
|
||||
|
||||
buf_ptr = inst + size;
|
||||
|
||||
/* Encode mod/rm byte. */
|
||||
if (!(flags & EX86_SHIFT_INS)) {
|
||||
if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
|
||||
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
|
||||
|
||||
if ((a & SLJIT_IMM) || (a == 0))
|
||||
*buf_ptr = 0;
|
||||
else if (!(flags & EX86_SSE2_OP1))
|
||||
*buf_ptr = reg_map[a] << 3;
|
||||
else
|
||||
*buf_ptr = a << 3;
|
||||
}
|
||||
else {
|
||||
if (a & SLJIT_IMM) {
|
||||
if (imma == 1)
|
||||
*inst = GROUP_SHIFT_1;
|
||||
else
|
||||
*inst = GROUP_SHIFT_N;
|
||||
} else
|
||||
*inst = GROUP_SHIFT_CL;
|
||||
*buf_ptr = 0;
|
||||
}
|
||||
|
||||
if (!(b & SLJIT_MEM))
|
||||
*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_map[b] : b);
|
||||
else if ((b & REG_MASK) != SLJIT_UNUSED) {
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
|
||||
if (immb != 0) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr |= 0x40;
|
||||
else
|
||||
*buf_ptr |= 0x80;
|
||||
}
|
||||
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
|
||||
*buf_ptr++ |= reg_map[b & REG_MASK];
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3);
|
||||
}
|
||||
|
||||
if (immb != 0) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr++ = immb; /* 8 bit displacement. */
|
||||
else {
|
||||
sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_sw);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3) | (immb << 6);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*buf_ptr++ |= 0x05;
|
||||
sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_sw);
|
||||
}
|
||||
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BYTE_ARG)
|
||||
*buf_ptr = imma;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
sljit_unaligned_store_s16(buf_ptr, imma);
|
||||
else if (!(flags & EX86_SHIFT_INS))
|
||||
sljit_unaligned_store_sw(buf_ptr, imma);
|
||||
}
|
||||
|
||||
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Call / return instructions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static SLJIT_INLINE sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
|
||||
inst = (sljit_u8*)ensure_buf(compiler, type >= SLJIT_CALL3 ? 1 + 2 + 1 : 1 + 2);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(type >= SLJIT_CALL3 ? 2 + 1 : 2);
|
||||
|
||||
if (type >= SLJIT_CALL3)
|
||||
PUSH_REG(reg_map[SLJIT_R2]);
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_R2] << 3) | reg_map[SLJIT_R0];
|
||||
#else
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 * (type - SLJIT_CALL0));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4 * (type - SLJIT_CALL0));
|
||||
|
||||
*inst++ = MOV_rm_r;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_R0] << 3) | 0x4 /* SIB */;
|
||||
*inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_SP];
|
||||
*inst++ = 0;
|
||||
if (type >= SLJIT_CALL2) {
|
||||
*inst++ = MOV_rm_r;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_R1] << 3) | 0x4 /* SIB */;
|
||||
*inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_SP];
|
||||
*inst++ = sizeof(sljit_sw);
|
||||
}
|
||||
if (type >= SLJIT_CALL3) {
|
||||
*inst++ = MOV_rm_r;
|
||||
*inst++ = MOD_DISP8 | (reg_map[SLJIT_R2] << 3) | 0x4 /* SIB */;
|
||||
*inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_SP];
|
||||
*inst++ = 2 * sizeof(sljit_sw);
|
||||
}
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
CHECK_EXTRA_REGS(dst, dstw, (void)0);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
dst = TMP_REG1;
|
||||
|
||||
if (FAST_IS_REG(dst)) {
|
||||
/* Unused dest is possible here. */
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(1);
|
||||
POP_REG(reg_map[dst]);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Memory. */
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = POP_rm;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
CHECK_EXTRA_REGS(src, srcw, (void)0);
|
||||
|
||||
if (FAST_IS_REG(src)) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(1 + 1);
|
||||
PUSH_REG(reg_map[src]);
|
||||
}
|
||||
else if (src & SLJIT_MEM) {
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = GROUP_FF;
|
||||
*inst |= PUSH_rm;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
}
|
||||
else {
|
||||
/* SLJIT_IMM. */
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(5 + 1);
|
||||
*inst++ = PUSH_i32;
|
||||
sljit_unaligned_store_sw(inst, srcw);
|
||||
inst += sizeof(sljit_sw);
|
||||
}
|
||||
|
||||
RET();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
@ -0,0 +1,739 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* x86 64-bit arch dependent functions. */
|
||||
|
||||
static sljit_s32 emit_load_imm64(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(2 + sizeof(sljit_sw));
|
||||
*inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
|
||||
*inst++ = MOV_r_i32 + (reg_map[reg] & 0x7);
|
||||
sljit_unaligned_store_sw(inst, imm);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_s32 type)
|
||||
{
|
||||
if (type < SLJIT_JUMP) {
|
||||
/* Invert type. */
|
||||
*code_ptr++ = get_jump_code(type ^ 0x1) - 0x10;
|
||||
*code_ptr++ = 10 + 3;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT(reg_map[TMP_REG3] == 9);
|
||||
*code_ptr++ = REX_W | REX_B;
|
||||
*code_ptr++ = MOV_r_i32 + 1;
|
||||
jump->addr = (sljit_uw)code_ptr;
|
||||
|
||||
if (jump->flags & JUMP_LABEL)
|
||||
jump->flags |= PATCH_MD;
|
||||
else
|
||||
sljit_unaligned_store_sw(code_ptr, jump->u.target);
|
||||
|
||||
code_ptr += sizeof(sljit_sw);
|
||||
*code_ptr++ = REX_B;
|
||||
*code_ptr++ = GROUP_FF;
|
||||
*code_ptr++ = (type >= SLJIT_FAST_CALL) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1);
|
||||
|
||||
return code_ptr;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
sljit_s32 i, tmp, size, saved_register_size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Two/four register slots for parameters plus space for xmm6 register if needed. */
|
||||
if (fscratches >= 6 || fsaveds >= 1)
|
||||
compiler->locals_offset = 6 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
/* Including the return address saved by the call instruction. */
|
||||
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
|
||||
|
||||
tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
|
||||
for (i = SLJIT_S0; i >= tmp; i--) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
PUSH_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
PUSH_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
if (args > 0) {
|
||||
size = args * 3;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(size);
|
||||
|
||||
#ifndef _WIN64
|
||||
if (args > 0) {
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x7 /* rdi */;
|
||||
}
|
||||
if (args > 1) {
|
||||
*inst++ = REX_W | REX_R;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_lmap[SLJIT_S1] << 3) | 0x6 /* rsi */;
|
||||
}
|
||||
if (args > 2) {
|
||||
*inst++ = REX_W | REX_R;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_lmap[SLJIT_S2] << 3) | 0x2 /* rdx */;
|
||||
}
|
||||
#else
|
||||
if (args > 0) {
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x1 /* rcx */;
|
||||
}
|
||||
if (args > 1) {
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S1] << 3) | 0x2 /* rdx */;
|
||||
}
|
||||
if (args > 2) {
|
||||
*inst++ = REX_W | REX_B;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (reg_map[SLJIT_S2] << 3) | 0x0 /* r8 */;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
|
||||
compiler->local_size = local_size;
|
||||
|
||||
#ifdef _WIN64
|
||||
if (local_size > 1024) {
|
||||
/* Allocate stack for the callback, which grows the stack. */
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + (3 + sizeof(sljit_s32)));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4 + (3 + sizeof(sljit_s32)));
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_83;
|
||||
*inst++ = MOD_REG | SUB | reg_map[SLJIT_SP];
|
||||
/* Allocated size for registers must be divisible by 8. */
|
||||
SLJIT_ASSERT(!(saved_register_size & 0x7));
|
||||
/* Aligned to 16 byte. */
|
||||
if (saved_register_size & 0x8) {
|
||||
*inst++ = 5 * sizeof(sljit_sw);
|
||||
local_size -= 5 * sizeof(sljit_sw);
|
||||
} else {
|
||||
*inst++ = 4 * sizeof(sljit_sw);
|
||||
local_size -= 4 * sizeof(sljit_sw);
|
||||
}
|
||||
/* Second instruction */
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R0] < 8);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_rm_i32;
|
||||
*inst++ = MOD_REG | reg_lmap[SLJIT_R0];
|
||||
sljit_unaligned_store_s32(inst, local_size);
|
||||
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|
||||
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
|
||||
compiler->skip_checks = 1;
|
||||
#endif
|
||||
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack)));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (local_size > 0) {
|
||||
if (local_size <= 127) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_83;
|
||||
*inst++ = MOD_REG | SUB | reg_map[SLJIT_SP];
|
||||
*inst++ = local_size;
|
||||
}
|
||||
else {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 7);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(7);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_81;
|
||||
*inst++ = MOD_REG | SUB | reg_map[SLJIT_SP];
|
||||
sljit_unaligned_store_s32(inst, local_size);
|
||||
inst += sizeof(sljit_s32);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Save xmm6 register: movaps [rsp + 0x20], xmm6 */
|
||||
if (fscratches >= 6 || fsaveds >= 1) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(5);
|
||||
*inst++ = GROUP_0F;
|
||||
sljit_unaligned_store_s32(inst, 0x20247429);
|
||||
}
|
||||
#endif
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
|
||||
sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
|
||||
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
|
||||
{
|
||||
sljit_s32 saved_register_size;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
|
||||
set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Two/four register slots for parameters plus space for xmm6 register if needed. */
|
||||
if (fscratches >= 6 || fsaveds >= 1)
|
||||
compiler->locals_offset = 6 * sizeof(sljit_sw);
|
||||
else
|
||||
compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
|
||||
#endif
|
||||
|
||||
/* Including the return address saved by the call instruction. */
|
||||
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
|
||||
compiler->local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_s32 i, tmp, size;
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
|
||||
|
||||
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Restore xmm6 register: movaps xmm6, [rsp + 0x20] */
|
||||
if (compiler->fscratches >= 6 || compiler->fsaveds >= 1) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(5);
|
||||
*inst++ = GROUP_0F;
|
||||
sljit_unaligned_store_s32(inst, 0x20247428);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (compiler->local_size > 0) {
|
||||
if (compiler->local_size <= 127) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(4);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_83;
|
||||
*inst++ = MOD_REG | ADD | 4;
|
||||
*inst = compiler->local_size;
|
||||
}
|
||||
else {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 7);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(7);
|
||||
*inst++ = REX_W;
|
||||
*inst++ = GROUP_BINARY_81;
|
||||
*inst++ = MOD_REG | ADD | 4;
|
||||
sljit_unaligned_store_s32(inst, compiler->local_size);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = compiler->scratches;
|
||||
for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
POP_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
|
||||
for (i = tmp; i <= SLJIT_S0; i++) {
|
||||
size = reg_map[i] >= 8 ? 2 : 1;
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(size);
|
||||
if (reg_map[i] >= 8)
|
||||
*inst++ = REX_B;
|
||||
POP_REG(reg_lmap[i]);
|
||||
}
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
RET();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Operators */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static sljit_s32 emit_do_imm32(struct sljit_compiler *compiler, sljit_u8 rex, sljit_u8 opcode, sljit_sw imm)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_s32 length = 1 + (rex ? 1 : 0) + sizeof(sljit_s32);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + length);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(length);
|
||||
if (rex)
|
||||
*inst++ = rex;
|
||||
*inst++ = opcode;
|
||||
sljit_unaligned_store_s32(inst, imm);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
|
||||
/* The register or immediate operand. */
|
||||
sljit_s32 a, sljit_sw imma,
|
||||
/* The general operand (not immediate). */
|
||||
sljit_s32 b, sljit_sw immb)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
sljit_u8 *buf_ptr;
|
||||
sljit_u8 rex = 0;
|
||||
sljit_s32 flags = size & ~0xf;
|
||||
sljit_s32 inst_size;
|
||||
|
||||
/* The immediate operand must be 32 bit. */
|
||||
SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma));
|
||||
/* Both cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
|
||||
/* Size flags not allowed for typed instructions. */
|
||||
SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
|
||||
/* Both size flags cannot be switched on. */
|
||||
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
|
||||
/* SSE2 and immediate is not possible. */
|
||||
SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
|
||||
SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
|
||||
&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
|
||||
&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
|
||||
|
||||
size &= 0xf;
|
||||
inst_size = size;
|
||||
|
||||
if (!compiler->mode32 && !(flags & EX86_NO_REXW))
|
||||
rex |= REX_W;
|
||||
else if (flags & EX86_REX)
|
||||
rex |= REX;
|
||||
|
||||
if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
|
||||
inst_size++;
|
||||
if (flags & EX86_PREF_66)
|
||||
inst_size++;
|
||||
|
||||
/* Calculate size of b. */
|
||||
inst_size += 1; /* mod r/m byte. */
|
||||
if (b & SLJIT_MEM) {
|
||||
if (!(b & OFFS_REG_MASK)) {
|
||||
if (NOT_HALFWORD(immb)) {
|
||||
PTR_FAIL_IF(emit_load_imm64(compiler, TMP_REG3, immb));
|
||||
immb = 0;
|
||||
if (b & REG_MASK)
|
||||
b |= TO_OFFS_REG(TMP_REG3);
|
||||
else
|
||||
b |= TMP_REG3;
|
||||
}
|
||||
else if (reg_lmap[b & REG_MASK] == 4)
|
||||
b |= TO_OFFS_REG(SLJIT_SP);
|
||||
}
|
||||
|
||||
if ((b & REG_MASK) == SLJIT_UNUSED)
|
||||
inst_size += 1 + sizeof(sljit_s32); /* SIB byte required to avoid RIP based addressing. */
|
||||
else {
|
||||
if (reg_map[b & REG_MASK] >= 8)
|
||||
rex |= REX_B;
|
||||
|
||||
if (immb != 0 && (!(b & OFFS_REG_MASK) || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP))) {
|
||||
/* Immediate operand. */
|
||||
if (immb <= 127 && immb >= -128)
|
||||
inst_size += sizeof(sljit_s8);
|
||||
else
|
||||
inst_size += sizeof(sljit_s32);
|
||||
}
|
||||
else if (reg_lmap[b & REG_MASK] == 5)
|
||||
inst_size += sizeof(sljit_s8);
|
||||
|
||||
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED) {
|
||||
inst_size += 1; /* SIB byte. */
|
||||
if (reg_map[OFFS_REG(b)] >= 8)
|
||||
rex |= REX_X;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(flags & EX86_SSE2_OP2) && reg_map[b] >= 8)
|
||||
rex |= REX_B;
|
||||
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BIN_INS) {
|
||||
if (imma <= 127 && imma >= -128) {
|
||||
inst_size += 1;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
} else
|
||||
inst_size += 4;
|
||||
}
|
||||
else if (flags & EX86_SHIFT_INS) {
|
||||
imma &= compiler->mode32 ? 0x1f : 0x3f;
|
||||
if (imma != 1) {
|
||||
inst_size ++;
|
||||
flags |= EX86_BYTE_ARG;
|
||||
}
|
||||
} else if (flags & EX86_BYTE_ARG)
|
||||
inst_size++;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
inst_size += sizeof(short);
|
||||
else
|
||||
inst_size += sizeof(sljit_s32);
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
|
||||
/* reg_map[SLJIT_PREF_SHIFT_REG] is less than 8. */
|
||||
if (!(flags & EX86_SSE2_OP1) && reg_map[a] >= 8)
|
||||
rex |= REX_R;
|
||||
}
|
||||
|
||||
if (rex)
|
||||
inst_size++;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
|
||||
PTR_FAIL_IF(!inst);
|
||||
|
||||
/* Encoding the byte. */
|
||||
INC_SIZE(inst_size);
|
||||
if (flags & EX86_PREF_F2)
|
||||
*inst++ = 0xf2;
|
||||
if (flags & EX86_PREF_F3)
|
||||
*inst++ = 0xf3;
|
||||
if (flags & EX86_PREF_66)
|
||||
*inst++ = 0x66;
|
||||
if (rex)
|
||||
*inst++ = rex;
|
||||
buf_ptr = inst + size;
|
||||
|
||||
/* Encode mod/rm byte. */
|
||||
if (!(flags & EX86_SHIFT_INS)) {
|
||||
if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
|
||||
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
|
||||
|
||||
if ((a & SLJIT_IMM) || (a == 0))
|
||||
*buf_ptr = 0;
|
||||
else if (!(flags & EX86_SSE2_OP1))
|
||||
*buf_ptr = reg_lmap[a] << 3;
|
||||
else
|
||||
*buf_ptr = a << 3;
|
||||
}
|
||||
else {
|
||||
if (a & SLJIT_IMM) {
|
||||
if (imma == 1)
|
||||
*inst = GROUP_SHIFT_1;
|
||||
else
|
||||
*inst = GROUP_SHIFT_N;
|
||||
} else
|
||||
*inst = GROUP_SHIFT_CL;
|
||||
*buf_ptr = 0;
|
||||
}
|
||||
|
||||
if (!(b & SLJIT_MEM))
|
||||
*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_lmap[b] : b);
|
||||
else if ((b & REG_MASK) != SLJIT_UNUSED) {
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
|
||||
if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr |= 0x40;
|
||||
else
|
||||
*buf_ptr |= 0x80;
|
||||
}
|
||||
|
||||
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
|
||||
*buf_ptr++ |= reg_lmap[b & REG_MASK];
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3);
|
||||
}
|
||||
|
||||
if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
|
||||
if (immb <= 127 && immb >= -128)
|
||||
*buf_ptr++ = immb; /* 8 bit displacement. */
|
||||
else {
|
||||
sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_s32);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (reg_lmap[b & REG_MASK] == 5)
|
||||
*buf_ptr |= 0x40;
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6);
|
||||
if (reg_lmap[b & REG_MASK] == 5)
|
||||
*buf_ptr++ = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*buf_ptr++ |= 0x04;
|
||||
*buf_ptr++ = 0x25;
|
||||
sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
|
||||
buf_ptr += sizeof(sljit_s32);
|
||||
}
|
||||
|
||||
if (a & SLJIT_IMM) {
|
||||
if (flags & EX86_BYTE_ARG)
|
||||
*buf_ptr = imma;
|
||||
else if (flags & EX86_HALF_ARG)
|
||||
sljit_unaligned_store_s16(buf_ptr, imma);
|
||||
else if (!(flags & EX86_SHIFT_INS))
|
||||
sljit_unaligned_store_s32(buf_ptr, imma);
|
||||
}
|
||||
|
||||
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Call / return instructions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static SLJIT_INLINE sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 type)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
#ifndef _WIN64
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R1] == 6 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
|
||||
if (type >= SLJIT_CALL3) {
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x2 /* rdx */ << 3) | reg_lmap[SLJIT_R2];
|
||||
}
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x7 /* rdi */ << 3) | reg_lmap[SLJIT_R0];
|
||||
#else
|
||||
SLJIT_ASSERT(reg_map[SLJIT_R1] == 2 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8);
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
|
||||
if (type >= SLJIT_CALL3) {
|
||||
*inst++ = REX_W | REX_R;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x0 /* r8 */ << 3) | reg_lmap[SLJIT_R2];
|
||||
}
|
||||
*inst++ = REX_W;
|
||||
*inst++ = MOV_r_rm;
|
||||
*inst++ = MOD_REG | (0x1 /* rcx */ << 3) | reg_lmap[SLJIT_R0];
|
||||
#endif
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
|
||||
ADJUST_LOCAL_OFFSET(dst, dstw);
|
||||
|
||||
/* For UNUSED dst. Uncommon, but possible. */
|
||||
if (dst == SLJIT_UNUSED)
|
||||
dst = TMP_REG1;
|
||||
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (reg_map[dst] < 8) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
POP_REG(reg_lmap[dst]);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(2);
|
||||
*inst++ = REX_B;
|
||||
POP_REG(reg_lmap[dst]);
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* REX_W is not necessary (src is not immediate). */
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = POP_rm;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_u8 *inst;
|
||||
|
||||
CHECK_ERROR();
|
||||
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
|
||||
ADJUST_LOCAL_OFFSET(src, srcw);
|
||||
|
||||
if ((src & SLJIT_IMM) && NOT_HALFWORD(srcw)) {
|
||||
FAIL_IF(emit_load_imm64(compiler, TMP_REG1, srcw));
|
||||
src = TMP_REG1;
|
||||
}
|
||||
|
||||
if (FAST_IS_REG(src)) {
|
||||
if (reg_map[src] < 8) {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(1 + 1);
|
||||
PUSH_REG(reg_lmap[src]);
|
||||
}
|
||||
else {
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(2 + 1);
|
||||
*inst++ = REX_B;
|
||||
PUSH_REG(reg_lmap[src]);
|
||||
}
|
||||
}
|
||||
else if (src & SLJIT_MEM) {
|
||||
/* REX_W is not necessary (src is not immediate). */
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = GROUP_FF;
|
||||
*inst |= PUSH_rm;
|
||||
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
|
||||
FAIL_IF(!inst);
|
||||
INC_SIZE(1);
|
||||
}
|
||||
else {
|
||||
SLJIT_ASSERT(IS_HALFWORD(srcw));
|
||||
/* SLJIT_IMM. */
|
||||
inst = (sljit_u8*)ensure_buf(compiler, 1 + 5 + 1);
|
||||
FAIL_IF(!inst);
|
||||
|
||||
INC_SIZE(5 + 1);
|
||||
*inst++ = PUSH_i32;
|
||||
sljit_unaligned_store_s32(inst, srcw);
|
||||
inst += sizeof(sljit_s32);
|
||||
}
|
||||
|
||||
RET();
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Extend input */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
|
||||
sljit_s32 dst, sljit_sw dstw,
|
||||
sljit_s32 src, sljit_sw srcw)
|
||||
{
|
||||
sljit_u8* inst;
|
||||
sljit_s32 dst_r;
|
||||
|
||||
compiler->mode32 = 0;
|
||||
|
||||
if (dst == SLJIT_UNUSED && !(src & SLJIT_MEM))
|
||||
return SLJIT_SUCCESS; /* Empty instruction. */
|
||||
|
||||
if (src & SLJIT_IMM) {
|
||||
if (FAST_IS_REG(dst)) {
|
||||
if (sign || ((sljit_uw)srcw <= 0x7fffffff)) {
|
||||
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = MOV_rm_i32;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
return emit_load_imm64(compiler, dst, srcw);
|
||||
}
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = MOV_rm_i32;
|
||||
compiler->mode32 = 0;
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
|
||||
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
|
||||
|
||||
if ((dst & SLJIT_MEM) && FAST_IS_REG(src))
|
||||
dst_r = src;
|
||||
else {
|
||||
if (sign) {
|
||||
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw);
|
||||
FAIL_IF(!inst);
|
||||
*inst++ = MOVSXD_r_rm;
|
||||
} else {
|
||||
compiler->mode32 = 1;
|
||||
FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw));
|
||||
compiler->mode32 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (dst & SLJIT_MEM) {
|
||||
compiler->mode32 = 1;
|
||||
inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
|
||||
FAIL_IF(!inst);
|
||||
*inst = MOV_rm_r;
|
||||
compiler->mode32 = 0;
|
||||
}
|
||||
|
||||
return SLJIT_SUCCESS;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,421 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file contains a simple executable memory allocator
|
||||
|
||||
It is assumed, that executable code blocks are usually medium (or sometimes
|
||||
large) memory blocks, and the allocator is not too frequently called (less
|
||||
optimized than other allocators). Thus, using it as a generic allocator is
|
||||
not suggested.
|
||||
|
||||
How does it work:
|
||||
Memory is allocated in continuous memory areas called chunks by alloc_chunk()
|
||||
Chunk format:
|
||||
[ block ][ block ] ... [ block ][ block terminator ]
|
||||
|
||||
All blocks and the block terminator is started with block_header. The block
|
||||
header contains the size of the previous and the next block. These sizes
|
||||
can also contain special values.
|
||||
Block size:
|
||||
0 - The block is a free_block, with a different size member.
|
||||
1 - The block is a block terminator.
|
||||
n - The block is used at the moment, and the value contains its size.
|
||||
Previous block size:
|
||||
0 - This is the first block of the memory chunk.
|
||||
n - The size of the previous block.
|
||||
|
||||
Using these size values we can go forward or backward on the block chain.
|
||||
The unused blocks are stored in a chain list pointed by free_blocks. This
|
||||
list is useful if we need to find a suitable memory area when the allocator
|
||||
is called.
|
||||
|
||||
When a block is freed, the new free block is connected to its adjacent free
|
||||
blocks if possible.
|
||||
|
||||
[ free block ][ used block ][ free block ]
|
||||
and "used block" is freed, the three blocks are connected together:
|
||||
[ one big free block ]
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* System (OS) functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* 64 KByte. */
|
||||
#define CHUNK_SIZE 0x10000
|
||||
|
||||
struct chunk_header {
|
||||
void *executable;
|
||||
int fd;
|
||||
};
|
||||
|
||||
/*
|
||||
alloc_chunk / free_chunk :
|
||||
* allocate executable system memory chunks
|
||||
* the size is always divisible by CHUNK_SIZE
|
||||
allocator_grab_lock / allocator_release_lock :
|
||||
* make the allocator thread safe
|
||||
* can be empty if the OS (or the application) does not support threading
|
||||
* only the allocator requires this lock, sljit is fully thread safe
|
||||
as it only uses local variables
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef O_NOATIME
|
||||
#define O_NOATIME 0
|
||||
#endif
|
||||
|
||||
#ifdef __O_TMPFILE
|
||||
#ifndef O_TMPFILE
|
||||
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int mkostemp(char *template, int flags);
|
||||
char *secure_getenv(const char *name);
|
||||
|
||||
static SLJIT_INLINE int create_tempfile(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
char tmp_name[256];
|
||||
size_t tmp_name_len;
|
||||
char *dir;
|
||||
size_t len;
|
||||
|
||||
#ifdef P_tmpdir
|
||||
len = (P_tmpdir != NULL) ? strlen(P_tmpdir) : 0;
|
||||
|
||||
if (len > 0 && len < sizeof(tmp_name)) {
|
||||
strcpy(tmp_name, P_tmpdir);
|
||||
tmp_name_len = len;
|
||||
}
|
||||
else {
|
||||
strcpy(tmp_name, "/tmp");
|
||||
tmp_name_len = 4;
|
||||
}
|
||||
#else
|
||||
strcpy(tmp_name, "/tmp");
|
||||
tmp_name_len = 4;
|
||||
#endif
|
||||
|
||||
dir = secure_getenv("TMPDIR");
|
||||
if (dir) {
|
||||
len = strlen(dir);
|
||||
if (len > 0 && len < sizeof(tmp_name)) {
|
||||
strcpy(tmp_name, dir);
|
||||
tmp_name_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
SLJIT_ASSERT(tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name));
|
||||
|
||||
while (tmp_name_len > 0 && tmp_name[tmp_name_len - 1] == '/') {
|
||||
tmp_name_len--;
|
||||
tmp_name[tmp_name_len] = '\0';
|
||||
}
|
||||
|
||||
#ifdef O_TMPFILE
|
||||
fd = open(tmp_name, O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, S_IRUSR | S_IWUSR);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
#endif
|
||||
|
||||
if (tmp_name_len + 7 >= sizeof(tmp_name))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(tmp_name + tmp_name_len, "/XXXXXX");
|
||||
fd = mkostemp(tmp_name, O_CLOEXEC | O_NOATIME);
|
||||
|
||||
if (fd == -1)
|
||||
return fd;
|
||||
|
||||
if (unlink(tmp_name)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE struct chunk_header* alloc_chunk(sljit_uw size)
|
||||
{
|
||||
struct chunk_header *retval;
|
||||
int fd;
|
||||
|
||||
fd = create_tempfile();
|
||||
if (fd == -1)
|
||||
return NULL;
|
||||
|
||||
if (ftruncate(fd, size)) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retval = (struct chunk_header *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
|
||||
if (retval == MAP_FAILED) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retval->executable = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
|
||||
|
||||
if (retval->executable == MAP_FAILED) {
|
||||
munmap(retval, size);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retval->fd = fd;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
|
||||
{
|
||||
struct chunk_header *header = ((struct chunk_header *)chunk) - 1;
|
||||
|
||||
int fd = header->fd;
|
||||
munmap(header->executable, size);
|
||||
munmap(header, size);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Common functions */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define CHUNK_MASK (~(CHUNK_SIZE - 1))
|
||||
|
||||
struct block_header {
|
||||
sljit_uw size;
|
||||
sljit_uw prev_size;
|
||||
sljit_sw executable_offset;
|
||||
};
|
||||
|
||||
struct free_block {
|
||||
struct block_header header;
|
||||
struct free_block *next;
|
||||
struct free_block *prev;
|
||||
sljit_uw size;
|
||||
};
|
||||
|
||||
#define AS_BLOCK_HEADER(base, offset) \
|
||||
((struct block_header*)(((sljit_u8*)base) + offset))
|
||||
#define AS_FREE_BLOCK(base, offset) \
|
||||
((struct free_block*)(((sljit_u8*)base) + offset))
|
||||
#define MEM_START(base) ((void*)((base) + 1))
|
||||
#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7) & ~7)
|
||||
|
||||
static struct free_block* free_blocks;
|
||||
static sljit_uw allocated_size;
|
||||
static sljit_uw total_size;
|
||||
|
||||
static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
|
||||
{
|
||||
free_block->header.size = 0;
|
||||
free_block->size = size;
|
||||
|
||||
free_block->next = free_blocks;
|
||||
free_block->prev = NULL;
|
||||
if (free_blocks)
|
||||
free_blocks->prev = free_block;
|
||||
free_blocks = free_block;
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
|
||||
{
|
||||
if (free_block->next)
|
||||
free_block->next->prev = free_block->prev;
|
||||
|
||||
if (free_block->prev)
|
||||
free_block->prev->next = free_block->next;
|
||||
else {
|
||||
SLJIT_ASSERT(free_blocks == free_block);
|
||||
free_blocks = free_block->next;
|
||||
}
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
||||
{
|
||||
struct chunk_header *chunk_header;
|
||||
struct block_header *header;
|
||||
struct block_header *next_header;
|
||||
struct free_block *free_block;
|
||||
sljit_uw chunk_size;
|
||||
sljit_sw executable_offset;
|
||||
|
||||
allocator_grab_lock();
|
||||
if (size < (64 - sizeof(struct block_header)))
|
||||
size = (64 - sizeof(struct block_header));
|
||||
size = ALIGN_SIZE(size);
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
if (free_block->size >= size) {
|
||||
chunk_size = free_block->size;
|
||||
if (chunk_size > size + 64) {
|
||||
/* We just cut a block from the end of the free block. */
|
||||
chunk_size -= size;
|
||||
free_block->size = chunk_size;
|
||||
header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
header->prev_size = chunk_size;
|
||||
header->executable_offset = free_block->header.executable_offset;
|
||||
AS_BLOCK_HEADER(header, size)->prev_size = size;
|
||||
}
|
||||
else {
|
||||
sljit_remove_free_block(free_block);
|
||||
header = (struct block_header*)free_block;
|
||||
size = chunk_size;
|
||||
}
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
free_block = free_block->next;
|
||||
}
|
||||
|
||||
chunk_size = sizeof(struct chunk_header) + sizeof(struct block_header);
|
||||
chunk_size = (chunk_size + size + CHUNK_SIZE - 1) & CHUNK_MASK;
|
||||
|
||||
chunk_header = alloc_chunk(chunk_size);
|
||||
if (!chunk_header) {
|
||||
allocator_release_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
executable_offset = (sljit_sw)((sljit_u8*)chunk_header->executable - (sljit_u8*)chunk_header);
|
||||
|
||||
chunk_size -= sizeof(struct chunk_header) + sizeof(struct block_header);
|
||||
total_size += chunk_size;
|
||||
|
||||
header = (struct block_header *)(chunk_header + 1);
|
||||
|
||||
header->prev_size = 0;
|
||||
header->executable_offset = executable_offset;
|
||||
if (chunk_size > size + 64) {
|
||||
/* Cut the allocated space into a free and a used block. */
|
||||
allocated_size += size;
|
||||
header->size = size;
|
||||
chunk_size -= size;
|
||||
|
||||
free_block = AS_FREE_BLOCK(header, size);
|
||||
free_block->header.prev_size = size;
|
||||
free_block->header.executable_offset = executable_offset;
|
||||
sljit_insert_free_block(free_block, chunk_size);
|
||||
next_header = AS_BLOCK_HEADER(free_block, chunk_size);
|
||||
}
|
||||
else {
|
||||
/* All space belongs to this allocation. */
|
||||
allocated_size += chunk_size;
|
||||
header->size = chunk_size;
|
||||
next_header = AS_BLOCK_HEADER(header, chunk_size);
|
||||
}
|
||||
next_header->size = 1;
|
||||
next_header->prev_size = chunk_size;
|
||||
next_header->executable_offset = executable_offset;
|
||||
allocator_release_lock();
|
||||
return MEM_START(header);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
|
||||
{
|
||||
struct block_header *header;
|
||||
struct free_block* free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
|
||||
header = AS_BLOCK_HEADER(header, -header->executable_offset);
|
||||
allocated_size -= header->size;
|
||||
|
||||
/* Connecting free blocks together if possible. */
|
||||
|
||||
/* If header->prev_size == 0, free_block will equal to header.
|
||||
In this case, free_block->header.size will be > 0. */
|
||||
free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
|
||||
if (SLJIT_UNLIKELY(!free_block->header.size)) {
|
||||
free_block->size += header->size;
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
else {
|
||||
free_block = (struct free_block*)header;
|
||||
sljit_insert_free_block(free_block, header->size);
|
||||
}
|
||||
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
if (SLJIT_UNLIKELY(!header->size)) {
|
||||
free_block->size += ((struct free_block*)header)->size;
|
||||
sljit_remove_free_block((struct free_block*)header);
|
||||
header = AS_BLOCK_HEADER(free_block, free_block->size);
|
||||
header->prev_size = free_block->size;
|
||||
}
|
||||
|
||||
/* The whole chunk is free. */
|
||||
if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
|
||||
/* If this block is freed, we still have (allocated_size / 2) free space. */
|
||||
if (total_size - free_block->size > (allocated_size * 3 / 2)) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
}
|
||||
|
||||
allocator_release_lock();
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
|
||||
{
|
||||
struct free_block* free_block;
|
||||
struct free_block* next_free_block;
|
||||
|
||||
allocator_grab_lock();
|
||||
|
||||
free_block = free_blocks;
|
||||
while (free_block) {
|
||||
next_free_block = free_block->next;
|
||||
if (!free_block->header.prev_size &&
|
||||
AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
|
||||
total_size -= free_block->size;
|
||||
sljit_remove_free_block(free_block);
|
||||
free_chunk(free_block, free_block->size + sizeof(struct block_header));
|
||||
}
|
||||
free_block = next_free_block;
|
||||
}
|
||||
|
||||
SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
|
||||
allocator_release_lock();
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr)
|
||||
{
|
||||
return ((struct block_header *)(ptr))[-1].executable_offset;
|
||||
}
|
||||
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Stack-less Just-In-Time compiler
|
||||
*
|
||||
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Locks */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) || (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
static SLJIT_INLINE void allocator_grab_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void allocator_release_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void)
|
||||
{
|
||||
/* Always successful. */
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
|
||||
|
||||
#elif defined(_WIN32) /* SLJIT_SINGLE_THREADED */
|
||||
|
||||
#include "windows.h"
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
static HANDLE allocator_mutex = 0;
|
||||
|
||||
static SLJIT_INLINE void allocator_grab_lock(void)
|
||||
{
|
||||
/* No idea what to do if an error occures. Static mutexes should never fail... */
|
||||
if (!allocator_mutex)
|
||||
allocator_mutex = CreateMutex(NULL, TRUE, NULL);
|
||||
else
|
||||
WaitForSingleObject(allocator_mutex, INFINITE);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void allocator_release_lock(void)
|
||||
{
|
||||
ReleaseMutex(allocator_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
static HANDLE global_mutex = 0;
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
|
||||
{
|
||||
/* No idea what to do if an error occures. Static mutexes should never fail... */
|
||||
if (!global_mutex)
|
||||
global_mutex = CreateMutex(NULL, TRUE, NULL);
|
||||
else
|
||||
WaitForSingleObject(global_mutex, INFINITE);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void)
|
||||
{
|
||||
ReleaseMutex(global_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static SLJIT_INLINE void allocator_grab_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&allocator_mutex);
|
||||
}
|
||||
|
||||
static SLJIT_INLINE void allocator_release_lock(void)
|
||||
{
|
||||
pthread_mutex_unlock(&allocator_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
|
||||
{
|
||||
pthread_mutex_lock(&global_mutex);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void)
|
||||
{
|
||||
pthread_mutex_unlock(&global_mutex);
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Stack */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) || (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
/* Provides mmap function. */
|
||||
#include <sys/mman.h>
|
||||
/* For detecting the page size. */
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef MAP_ANON
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Some old systems does not have MAP_ANON. */
|
||||
static sljit_s32 dev_zero = -1;
|
||||
|
||||
#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
|
||||
|
||||
static SLJIT_INLINE sljit_s32 open_dev_zero(void)
|
||||
{
|
||||
dev_zero = open("/dev/zero", O_RDWR);
|
||||
return dev_zero < 0;
|
||||
}
|
||||
|
||||
#else /* SLJIT_SINGLE_THREADED */
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static SLJIT_INLINE sljit_s32 open_dev_zero(void)
|
||||
{
|
||||
pthread_mutex_lock(&dev_zero_mutex);
|
||||
/* The dev_zero might be initialized by another thread during the waiting. */
|
||||
if (dev_zero < 0) {
|
||||
dev_zero = open("/dev/zero", O_RDWR);
|
||||
}
|
||||
pthread_mutex_unlock(&dev_zero_mutex);
|
||||
return dev_zero < 0;
|
||||
}
|
||||
|
||||
#endif /* SLJIT_SINGLE_THREADED */
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SLJIT_UTIL_STACK || SLJIT_EXECUTABLE_ALLOCATOR */
|
||||
|
||||
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK)
|
||||
|
||||
/* Planning to make it even more clever in the future. */
|
||||
static sljit_sw sljit_page_align = 0;
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit, void *allocator_data)
|
||||
{
|
||||
struct sljit_stack *stack;
|
||||
void *ptr;
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO si;
|
||||
#endif
|
||||
|
||||
SLJIT_UNUSED_ARG(allocator_data);
|
||||
if (limit > max_limit || limit < 1)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!sljit_page_align) {
|
||||
GetSystemInfo(&si);
|
||||
sljit_page_align = si.dwPageSize - 1;
|
||||
}
|
||||
#else
|
||||
if (!sljit_page_align) {
|
||||
sljit_page_align = sysconf(_SC_PAGESIZE);
|
||||
/* Should never happen. */
|
||||
if (sljit_page_align < 0)
|
||||
sljit_page_align = 4096;
|
||||
sljit_page_align--;
|
||||
}
|
||||
#endif
|
||||
|
||||
stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data);
|
||||
if (!stack)
|
||||
return NULL;
|
||||
|
||||
/* Align max_limit. */
|
||||
max_limit = (max_limit + sljit_page_align) & ~sljit_page_align;
|
||||
|
||||
#ifdef _WIN32
|
||||
ptr = VirtualAlloc(NULL, max_limit, MEM_RESERVE, PAGE_READWRITE);
|
||||
if (!ptr) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
stack->max_limit = (sljit_u8 *)ptr;
|
||||
stack->base = stack->max_limit + max_limit;
|
||||
stack->limit = stack->base;
|
||||
if (sljit_stack_resize(stack, stack->base - limit)) {
|
||||
sljit_free_stack(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#ifdef MAP_ANON
|
||||
ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#else
|
||||
if (dev_zero < 0) {
|
||||
if (open_dev_zero()) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0);
|
||||
#endif
|
||||
if (ptr == MAP_FAILED) {
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
return NULL;
|
||||
}
|
||||
stack->max_limit = (sljit_u8 *)ptr;
|
||||
stack->base = stack->max_limit + max_limit;
|
||||
stack->limit = stack->base - limit;
|
||||
#endif
|
||||
stack->top = stack->base;
|
||||
return stack;
|
||||
}
|
||||
|
||||
#undef PAGE_ALIGN
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack *stack, void *allocator_data)
|
||||
{
|
||||
SLJIT_UNUSED_ARG(allocator_data);
|
||||
#ifdef _WIN32
|
||||
VirtualFree((void*)stack->max_limit, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap((void*)stack->max_limit, stack->base - stack->max_limit);
|
||||
#endif
|
||||
SLJIT_FREE(stack, allocator_data);
|
||||
}
|
||||
|
||||
SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_limit)
|
||||
{
|
||||
sljit_uw aligned_old_limit;
|
||||
sljit_uw aligned_new_limit;
|
||||
|
||||
if ((new_limit < stack->max_limit) || (new_limit >= stack->base))
|
||||
return -1;
|
||||
#ifdef _WIN32
|
||||
aligned_new_limit = (sljit_uw)new_limit & ~sljit_page_align;
|
||||
aligned_old_limit = ((sljit_uw)stack->limit) & ~sljit_page_align;
|
||||
if (aligned_new_limit != aligned_old_limit) {
|
||||
if (aligned_new_limit < aligned_old_limit) {
|
||||
if (!VirtualAlloc((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MEM_COMMIT, PAGE_READWRITE))
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
if (!VirtualFree((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MEM_DECOMMIT))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
stack->limit = new_limit;
|
||||
return 0;
|
||||
#else
|
||||
if (new_limit <= stack->limit) {
|
||||
stack->limit = new_limit;
|
||||
return 0;
|
||||
}
|
||||
aligned_new_limit = (sljit_uw)new_limit & ~sljit_page_align;
|
||||
aligned_old_limit = ((sljit_uw)stack->limit) & ~sljit_page_align;
|
||||
/* If madvise is available, we release the unnecessary space. */
|
||||
#if defined(MADV_DONTNEED)
|
||||
if (aligned_new_limit > aligned_old_limit)
|
||||
madvise((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MADV_DONTNEED);
|
||||
#elif defined(POSIX_MADV_DONTNEED)
|
||||
if (aligned_new_limit > aligned_old_limit)
|
||||
posix_madvise((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, POSIX_MADV_DONTNEED);
|
||||
#endif
|
||||
stack->limit = new_limit;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* SLJIT_UTIL_STACK */
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user