#include #include "Cppia.h" #include "CppiaStream.h" namespace hx { class CppiaEnumBase : public EnumBase_obj { public: #if (HXCPP_API_LEVEL<330) CppiaClassInfo *classInfo; #endif CppiaEnumBase(CppiaClassInfo *inInfo) { classInfo = inInfo; } ::hx::ObjectPtr __GetClass() const; ::String GetEnumName( ) const; ::String __ToString() const; }; struct CppiaEnumConstructor { struct Arg { Arg(int inNameId, int inTypeId) : nameId(inNameId), typeId(inTypeId) { } int nameId; int typeId; }; std::vector args; CppiaClassInfo *classInfo; int nameId; Dynamic value; int index; String name; CppiaEnumConstructor(CppiaModule &inModule, CppiaStream &inStream, CppiaClassInfo *inClassInfo) { classInfo = inClassInfo; nameId = inStream.getInt(); index = -1; name = String(); int argCount = inStream.getInt(); for(int a=0;a inArgs ) { bool ok = inArgs.mPtr ? (inArgs->length==args.size()) : args.size()==0; if (!ok) throw Dynamic(HX_CSTRING("Bad enum arg count")); if (args.size()==0) return value.mPtr; #if (HXCPP_API_LEVEL >= 330) EnumBase_obj *result = new ((int)args.size()*sizeof(cpp::Variant)) CppiaEnumBase(classInfo); result->_hx_setIdentity(name, index, args.size()); for(int i=0;i_hx_init( i, inArgs[i] ); #else EnumBase_obj *result = new CppiaEnumBase(classInfo); result->__Set(name, index, inArgs); #endif return result; } #ifdef CPPIA_JIT static EnumBase_obj * SLJIT_CALL createEnumBase( CppiaEnumConstructor *enumCtor) { EnumBase_obj *result = new ((int)enumCtor->args.size()*sizeof(cpp::Variant)) CppiaEnumBase(enumCtor->classInfo); result->_hx_setIdentity(enumCtor->name, enumCtor->index, enumCtor->args.size()); return result; } cpp::Variant::Type getVariantType(ExprType inType) { switch(inType) { case etVoid: return cpp::Variant::typeObject; case etNull: return cpp::Variant::typeObject; case etObject: return cpp::Variant::typeObject; case etString: return cpp::Variant::typeString; case etFloat: return cpp::Variant::typeDouble; case etInt: return cpp::Variant::typeInt; } return cpp::Variant::typeObject; } void genCode(CppiaCompiler *compiler, Expressions &inArgs, const JitVal &inDest, ExprType destType) { bool ok = args.size() && args.size()==inArgs.size(); if (!ok) printf("Bad enum arg count\n"); #if (HXCPP_API_LEVEL >= 330) compiler->callNative( (void *)createEnumBase, (void *)this ); JitTemp result(compiler,jtPointer); compiler->move(result, sJitReturnReg); int offset = sizeof(EnumBase_obj); for(int i=0;igetType(); JitTemp val(compiler,getJitType(type)); inArgs[i]->genCode(compiler, val, inArgs[i]->getType()); compiler->move( sJitReturnReg.as(jtPointer), result ); if (type==etString) { compiler->move( sJitReturnReg.star(jtInt,offset + offsetof(cpp::Variant,valStringLen)), val.as(jtInt) ); compiler->move( sJitReturnReg.star(jtPointer,offset), val.as(jtPointer) + StringOffset::Ptr); } else { compiler->move( sJitReturnReg.star(type,offset), val ); } compiler->move( sJitReturnReg.star(jtInt,offset + offsetof(cpp::Variant,type)), (int)getVariantType(type) ); offset += sizeof(cpp::Variant); } if (destType==etObject) compiler->move(inDest, sJitReturnReg.as(jtPointer)); #endif } #endif }; class EnumConstructorClosure : public hx::Object { public: CppiaEnumConstructor &constructor; EnumConstructorClosure(CppiaEnumConstructor &c) : constructor(c) { } Dynamic __Run(const Array &inArgs) { return constructor.create(inArgs); } int __GetType() const { return vtFunction; } int __ArgCount() const { return constructor.args.size(); } String toString() { return HX_CSTRING("#function(") + constructor.name + HX_CSTRING(")"); } }; hx::Object *createEnumClosure(CppiaEnumConstructor &inContructor) { return new EnumConstructorClosure(inContructor); } #ifdef CPPIA_JIT void SLJIT_CALL createEnum(hx::Class_obj *inClass, String *inName, int inArgs) { StackContext *ctx = StackContext::getCurrent(); // ctx.pointer points to end-of-args unsigned char *oldPointer = ctx->pointer; hx::Object **base = ((hx::Object **)(ctx->frame) ); Array args = Array_obj::__new(inArgs); TRY_NATIVE for(int i=0;iConstructEnum(*inName, args).mPtr; CATCH_NATIVE ctx->pointer = oldPointer; } #endif struct EnumField : public CppiaDynamicExpr { int enumId; int fieldId; CppiaEnumConstructor *value; Expressions args; // Mark class? String enumName; hx::Class enumClass; Dynamic enumValue; EnumField(CppiaStream &stream,bool inWithArgs) { enumId = stream.getInt(); fieldId = stream.getInt(); value= 0; if (inWithArgs) { int argCount = stream.getInt(); for(int a=0;acppiaClass) { if (!type->cppiaClass->isEnum) throw "Field of non-enum"; value = type->cppiaClass->findEnum(fieldId); } else { enumClass = hx::Class_obj::Resolve(type->name); if (!enumClass.mPtr) { printf("Could not find enum %s\n", type->name.out_str() ); throw "Bad enum"; } enumName = inModule.strings[fieldId]; inModule.markable.push_back(this); } LinkExpressions(args,inModule); return this; } hx::Object *getValue() { if (value) return value->value.mPtr; if (!enumValue.mPtr) { enumValue = enumClass->ConstructEnum(enumName,null()); } return enumValue.mPtr; } hx::Object *runObject(CppiaCtx *ctx) { int s = args.size(); if (s==0) return getValue(); Array dynArgs = Array_obj::__new(s,s); for(int a=0;arunObject(ctx); BCR_CHECK; } return value ? value->create(dynArgs) : enumClass->ConstructEnum(enumName,dynArgs).mPtr; } void mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(enumName); HX_MARK_MEMBER(enumClass); HX_MARK_MEMBER(enumValue); } #ifdef HXCPP_VISIT_ALLOCS void visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(enumName); HX_VISIT_MEMBER(enumClass); HX_VISIT_MEMBER(enumValue); } #endif #ifdef CPPIA_JIT void genCode(CppiaCompiler *compiler, const JitVal &inDest, ExprType destType) { int s = args.size(); if (s==0) { // TODO GC pin if (destType==etObject) compiler->move(inDest, (void *)getValue()); } else if (value) { value->genCode(compiler, args, inDest, destType); } else { { AutoFramePos frame(compiler); for(int a=0;agenCode(compiler, JitFramePos(compiler->getCurrentFrameSize(),etObject), etObject); compiler->addFrame(etObject); } } compiler->add(sJitCtxFrame, sJitFrame, compiler->getCurrentFrameSize()); compiler->callNative((void *)createEnum,(void *)enumClass.mPtr,(void *)&enumName,(int)args.size() ); if (destType!=etVoid && destType!=etNull) compiler->convertResult( etObject, inDest, destType ); } } #endif }; CppiaExpr *createEnumField(CppiaStream &stream,bool inWithArgs) { return new EnumField(stream, inWithArgs); } int getScriptId(hx::Class inClass); void linkCppiaClass(hx::Class_obj *inClass, CppiaModule &cppia, String inName); // Class Info... CppiaClassInfo::CppiaClassInfo(CppiaModule &inCppia) : cppia(inCppia) { isLinked = false; haxeBase = 0; extraData = 0; containsPointers = false; classSize = 0; newFunc = 0; initExpr = 0; enumMeta = 0; isInterface = false; interfaceSlotSize = 0; superType = 0; typeId = 0; vtable = 0; type = 0; mClass.mPtr = 0; dynamicMapOffset = 0; haxeBaseVTable = 0; } /* class CppiaClass *getCppiaClass() { return (class CppiaClass *)mClass.mPtr; } */ hx::Object *CppiaClassInfo::createInstance(CppiaCtx *ctx,Expressions &inArgs, bool inCallNew) { hx::Object *obj = haxeBase->factory(vtable,extraData); createDynamicFunctions(obj); if (newFunc && inCallNew) runFunExpr(ctx, newFunc->funExpr, obj, inArgs ); return obj; } hx::Object *CppiaClassInfo::createInstance(CppiaCtx *ctx,Array &inArgs) { hx::Object *obj = haxeBase->factory(vtable,extraData); createDynamicFunctions(obj); if (newFunc) runFunExprDynamicVoid(ctx, newFunc->funExpr, obj, inArgs ); return obj; } void *CppiaClassInfo::getHaxeBaseVTable() { if (!haxeBase || haxeBaseVTable) return haxeBaseVTable; hx::Object *temp = haxeBase->factory(vtable,extraData); haxeBaseVTable = *(void **)temp; if (!containsPointers && ( ((unsigned int *)temp)[-1] & IMMIX_ALLOC_IS_CONTAINER) ) containsPointers = true; return haxeBaseVTable; } int CppiaClassInfo::getScriptVTableOffset() { return haxeBase ? (int)(haxeBase->mDataOffset - sizeof(void *)) : sizeof(hx::Object); } bool CppiaClassInfo::isNativeProperty(const String &inString) { return nativeProperties.find(inString) != nativeProperties.end(); } int CppiaClassInfo::__GetType() { return isEnum ? vtEnum : vtClass; } int CppiaClassInfo::getEnumIndex(String inName) { for(int i=0;iname==inName) return i; } throw Dynamic(HX_CSTRING("Bad enum index")); return 0; } bool CppiaClassInfo::implementsInterface(CppiaClassInfo *inInterface) { for(int i=0;itypeId) return true; return false; } ScriptCallable *CppiaClassInfo::findFunction(bool inStatic,int inId) { Functions &funcs = inStatic ? staticFunctions : memberFunctions; for(int i=0;inameId == inId) return funcs[i]->funExpr; } return 0; } CppiaFunction *CppiaClassInfo::findVTableFunction(int inId) { for(int i=0;inameId == inId) return memberFunctions[i]; } return 0; } ScriptCallable *CppiaClassInfo::findInterfaceFunction(const std::string &inName) { Functions &funcs = memberFunctions; for(int i=0;inameId].utf8_str() == inName) return funcs[i]->funExpr; } return 0; } ScriptCallable *CppiaClassInfo::findFunction(bool inStatic, const String &inName) { Functions &funcs = inStatic ? staticFunctions : memberFunctions; for(int i=0;inameId] == inName) return funcs[i]->funExpr; } return 0; } inline ScriptCallable *CppiaClassInfo::findFunction(FunctionMap &inMap,const String &inName) { FunctionMap::iterator it = inMap.find(inName.utf8_str()); if (it!=inMap.end()) return it->second; return 0; } bool CppiaClassInfo::getField(hx::Object *inThis, String inName, hx::PropertyAccess inCallProp, Dynamic &outValue) { if (inCallProp==paccDynamic) inCallProp = isNativeProperty(inName) ? paccAlways : paccNever; if (inCallProp) { ScriptCallable *getter = findMemberGetter(inName); if (getter) { Array empty; outValue.mPtr = runFunExprDynamic(CppiaCtx::getCurrent(),getter,inThis, empty); return true; } } ScriptCallable *closure = findFunction(false,inName); if (closure) { outValue.mPtr = createMemberClosure(inThis,closure); return true; } // Look for dynamic function (variable) for(int i=0;inameId ]==inName) { CppiaVar *d = dynamicFunctions[i]; outValue = d->getValue(inThis); return true; } } for(int i=0;i__GetFieldMap(); if (map) { if (hx::FieldMapGet(map,inName,outValue)) return true; } //printf("Get field not found (%s) %s\n", inThis->toString().out_str(),inName.out_str()); return false; } bool CppiaClassInfo::setField(hx::Object *inThis, String inName, Dynamic inValue, hx::PropertyAccess inCallProp, Dynamic &outValue) { if (inCallProp==paccDynamic) inCallProp = isNativeProperty(inName) ? paccAlways : paccNever; if (inCallProp) { //printf("Set field %s %s = %s\n", inThis->toString().out_str(), inName.out_str(), inValue->toString().out_str()); ScriptCallable *setter = findMemberSetter(inName); if (setter) { Array args = Array_obj::__new(1,1); args[0] = inValue; outValue.mPtr = runFunExprDynamic(CppiaCtx::getCurrent(),setter,inThis, args); return true; } } // Look for dynamic function (variable) for(int i=0;inameId ]==inName) { CppiaVar *d = dynamicFunctions[i]; outValue = d->setValue(inThis,inValue); return true; } } for(int i=0;i__GetFieldMap(); if (map) { #ifdef HXCPP_GC_GENERATIONAL FieldMapSet(inThis,map, inName, inValue); #else FieldMapSet(map, inName, inValue); #endif outValue = inValue; return true; } // Fall though to haxe base //printf("Set field not found (%s) %s map=%p o=%d\n", inThis->toString().out_str(),inName.out_str(), map, dynamicMapOffset); return false; } int CppiaClassInfo::findFunctionSlot(int inName) { for(int i=0;inameId==inName) return memberFunctions[i]->vtableSlot; return -1; } ExprType CppiaClassInfo::findFunctionType(CppiaModule &inModule, int inName) { for(int i=0;inameId==inName) return inModule.types[ memberFunctions[i]->returnType ]->expressionType; return etVoid; } CppiaVar *CppiaClassInfo::findVar(bool inStatic,int inId) { std::vector &vars = inStatic ? staticVars : memberVars; for(int i=0;inameId == inId) return vars[i]; } std::vector &dvars = inStatic ? staticDynamicFunctions : dynamicFunctions; for(int i=0;inameId == inId) return dvars[i]; } if (superType && superType->cppiaClass) return superType->cppiaClass->findVar(inStatic,inId); return 0; } void CppiaClassInfo::dumpVars(const char *inMessage, std::vector &vars) { printf(" %s:\n", inMessage); for(int i=0;inameId ].out_str(), vars[i]->nameId ); } void CppiaClassInfo::dumpFunctions(const char *inMessage, std::vector &funcs) { printf(" %s:\n", inMessage); for(int i=0;inameId ].out_str(), funcs[i]->nameId); } void CppiaClassInfo::dump() { printf("Class %s\n", name.c_str()); dumpFunctions("Member functions",memberFunctions); dumpFunctions("Static functions",staticFunctions); dumpVars("Member vars",memberVars); dumpVars("Member dyns",dynamicFunctions); dumpVars("Static vars",staticVars); dumpVars("Static dyns",staticDynamicFunctions); } CppiaEnumConstructor *CppiaClassInfo::findEnum(int inFieldId) { for(int i=0;inameId==inFieldId) return enumConstructors[i]; return 0; } void CppiaClassInfo::mark(hx::MarkContext *__inCtx) { HX_MARK_MEMBER(mClass); for(int i=0;ivalue); HX_MARK_MEMBER(enumConstructors[i]->name); } for(int i=0;imark(__inCtx); for(int i=0;imark(__inCtx); } #ifdef HXCPP_VISIT_ALLOCS void CppiaClassInfo::visit(hx::VisitContext *__inCtx) { HX_VISIT_MEMBER(mClass); for(int i=0;ivalue); HX_VISIT_MEMBER(enumConstructors[i]->name); } for(int i=0;ivisit(__inCtx); for(int i=0;ivisit(__inCtx); } #endif bool CppiaClassInfo::load(CppiaStream &inStream) { CppiaOp op = inStream.getOp(); isInterface = isEnum = false; if (op==IaClass) isInterface = false; else if (op==IaInterface) isInterface = true; else if (op==IaEnum) isEnum = true; else { DBGLOG("Invalid class field op %d\n", op); throw "Bad class type"; } std::string tok; typeId = inStream.getInt(); mClass.mPtr = createCppiaClass(this); superId = isEnum ? 0 : inStream.getInt(); int implementCount = isEnum ? 0 : inStream.getInt(); implements.resize(implementCount); for(int i=0;icppiaClass = this; } else { DBGLOG("Already has registered %s - ignore\n",name.c_str()); } inStream.module->creatingClass = name.c_str(); int fields = inStream.getInt(); for(int f=0;fload(inStream,!isInterface); if (isDynamic) { if (isStatic) staticDynamicFunctions.push_back( new CppiaVar(func) ); else dynamicFunctions.push_back( new CppiaVar(func) ); } else { if (isStatic) staticFunctions.push_back(func); else { memberFunctions.push_back(func); } } } else if (tok=="VAR") { bool isStatic = inStream.getStatic(); CppiaVar *var = new CppiaVar(isStatic); if (isStatic) staticVars.push_back(var); else memberVars.push_back(var); var->load(inStream); } else if (tok=="IMPLDYNAMIC") { // Fill in later dynamicMapOffset = -1; } else if (tok=="INLINE") { // OK } else throw "unknown field type"; } } if (isEnum) { if (inStream.getBool()) enumMeta = createCppiaExpr(inStream); } inStream.module->creatingClass = 0; return isNew; } #if (HXCPP_API_LEVEL<330) void **CppiaClassInfo::createInterfaceVTable(int inTypeId) { std::vector vtable; HaxeNativeInterface *interface = cppia.types[inTypeId]->interfaceBase; // Native-defined interface... if (interface) { vtable.push_back( findInterfaceFunction("toString") ); ScriptNamedFunction *functions = interface->functions; if (functions != 0) { for(ScriptNamedFunction *f = functions; f->name; f++) if (strcmp(f->name,"toString")) vtable.push_back( findInterfaceFunction(f->name) ); } } CppiaClassInfo *cls = cppia.types[inTypeId]->cppiaClass; if (!cls && !interface) throw "vtable for unknown class"; if (cls && !cls->isInterface) throw "vtable for non-interface"; if (cls) { for(int i=0;imemberFunctions.size();i++) { CppiaFunction *func = cls->memberFunctions[i]; vtable.push_back( findFunction(false,func->nameId) ); } } void **result = new void *[ vtable.size() + 1]; result[0] = this; result++; memcpy(result, &vtable[0], sizeof(void *)*vtable.size()); return result; } #endif hx::Class *CppiaClassInfo::getSuperClass() { DBGLOG("getSuperClass %s %d\n", name.c_str(), superId); if (!superId) return 0; TypeData *superType = cppia.types[ superId ]; if (!superType) throw "Unknown super type!"; if (superType->cppiaClass) return &superType->cppiaClass->mClass; if (!superType->haxeClass.mPtr) { printf("Invalid super class '%s' for '%s'.\n", superType->name.c_str(), name.c_str()); throw "Missing super class"; } return &superType->haxeClass; } void CppiaClassInfo::addMemberFunction(Functions &ioCombined, CppiaFunction *inNewFunc) { for(int j=0;jname==inNewFunc->name) { ioCombined[j] = inNewFunc; return; } ioCombined.push_back(inNewFunc); } void CppiaClassInfo::linkTypes() { if (isLinked) return; isLinked = true; type = cppia.types[typeId]; mClass->mName = type->name; superType = superId ? cppia.types[ superId ] : 0; CppiaClassInfo *cppiaSuper = superType ? superType->cppiaClass : 0; // Link super first if (superType && superType->cppiaClass) superType->cppiaClass->linkTypes(); // implemented interfaces before main class for(int i=0;icppiaClass) cppia.types[ implements[i] ]->cppiaClass->linkTypes(); // Add super interfaces ... TypeData *extraInterfaces = cppia.types[ superId ]; while(extraInterfaces) { if (extraInterfaces->cppiaClass) { CppiaClassInfo &parent = *extraInterfaces->cppiaClass; std::vector &impl = parent.implements; for(int i=0;i= 330) HaxeNativeInterface *native = HaxeNativeInterface::findInterface( extraInterfaces->name.utf8_str() ); if (native) { String hashName = extraInterfaces->name.split(HX_CSTRING(".")).mPtr->join(HX_CSTRING("::")); interfaceScriptTables[hashName.hash()] = native->scriptTable; ScriptNamedFunction *functions = native->functions; for(ScriptNamedFunction *f = functions; f && f->name; f++) { nativeInterfaceFunctions.push_back(f); int slot = cppia.getInterfaceSlot(f->name); if (slot<0) printf("Interface slot '%s' not found\n",f->name); if (slot>interfaceSlotSize) interfaceSlotSize = slot; } } #endif break; } } DBGLOG(" Linking class '%s' ", type->name.out_str()); if (!superType) { DBGLOG("script base\n"); } else if (cppiaSuper) { DBGLOG("extends script '%s'\n", superType->name.out_str()); } else { DBGLOG("extends haxe '%s'\n", superType->name.out_str()); } // Link class before we combine the function list... linkCppiaClass(mClass.mPtr,cppia,type->name); haxeBase = type->haxeBase; if (!haxeBase && !isInterface) throw "No base defined for non-interface"; classSize = haxeBase ? haxeBase->mDataOffset : 0; // Combine member vars ... if (cppiaSuper) { classSize = cppiaSuper->classSize; containsPointers = cppiaSuper->containsPointers; if (cppiaSuper->dynamicMapOffset!=0) dynamicMapOffset = cppiaSuper->dynamicMapOffset; std::vector combinedVars(cppiaSuper->memberVars ); for(int i=0;inameId==memberVars[i]->nameId) printf("Warning duplicate member var %s\n", cppia.strings[memberVars[i]->nameId].out_str()); combinedVars.push_back(memberVars[i]); } memberVars.swap(combinedVars); std::vector combinedDynamics(cppiaSuper->dynamicFunctions ); for(int i=0;inameId == combinedDynamics[j]->nameId) { // Overwrite dynamicFunctions[i]->offset = combinedDynamics[j]->offset; combinedDynamics[j] = dynamicFunctions[i]; found = true; } if (!found) combinedDynamics.push_back(dynamicFunctions[i]); } dynamicFunctions.swap(combinedDynamics); // Combine member functions ... Functions combinedFunctions(cppiaSuper->memberFunctions ); if (isInterface) { // 'implements' interfaces are like extra super-classes for interfaces // For non-interface classes, these function will show up in the members anyhow for(int i=0;icppiaClass; if (cppiaInterface) { Functions &intfFuncs = cppiaInterface->memberFunctions; for(int j=0;jname.c_str(), classSize); for(int i=0;ioffset) { DBGLOG(" super var %s @ %d\n", cppia.identStr(memberVars[i]->nameId), memberVars[i]->offset); } else { DBGLOG(" link var %s @ %d\n", cppia.identStr(memberVars[i]->nameId), classSize); memberVars[i]->linkVarTypes(cppia,classSize); containsPointers = containsPointers || memberVars[i]->hasPointer(); } } for(int i=0;ioffset) { DBGLOG(" super dynamic function %s @ %d\n", cppia.identStr(dynamicFunctions[i]->nameId), dynamicFunctions[i]->offset); } else { DBGLOG(" link dynamic function %s @ %d\n", cppia.identStr(dynamicFunctions[i]->nameId), classSize); dynamicFunctions[i]->linkVarTypes(cppia,classSize); } } if (dynamicMapOffset==-1) { dynamicMapOffset = classSize; classSize += sizeof( hx::FieldMap * ); containsPointers = true; } extraData = classSize - haxeBase->mDataOffset; if (!containsPointers) getHaxeBaseVTable(); } DBGLOG(" script member vars size = %d\n", extraData); for(int i=0;inameId)); staticVars[i]->linkVarTypes(cppia); } for(int i=0;inameId)); staticDynamicFunctions[i]->linkVarTypes(cppia); } // Combine vtable positions... DBGLOG(" format haxe callable vtable (%d)....\n", (int)memberFunctions.size()); std::vector table; if (haxeBase) haxeBase->addVtableEntries(table); for(int i=0;iname) { idx = j; break; } if (idx<0) { if (isInterface) { idx = cppia.getInterfaceSlot(memberFunctions[i]->name); if (idx==-1) throw "Missing function in interface"; if (idx>interfaceSlotSize) interfaceSlotSize = idx; idx = -idx; DBGLOG("Using interface vtable[%d] = %s\n", idx, memberFunctions[i]->name.c_str() ); } else { idx = vtableSlot++; DBGLOG(" cppia slot [%d] = %s\n", idx, memberFunctions[i]->name.c_str() ); } } else DBGLOG(" override slot [%d] = %s\n", idx, memberFunctions[i]->name.c_str() ); memberFunctions[i]->setVTableSlot(idx); } // Create interface vtables... for(int i=0;i 0) { TypeData *interface = cppia.types[id]; CppiaClassInfo *cppiaInterface = interface->cppiaClass; #if (HXCPP_API_LEVEL >= 330) HaxeNativeInterface *native = HaxeNativeInterface::findInterface( interface->name.utf8_str() ); if (native) { String hashName = interface->name.split(HX_CSTRING(".")).mPtr->join(HX_CSTRING("::")); interfaceScriptTables[hashName.hash()] = native->scriptTable; ScriptNamedFunction *functions = native->functions; if (functions != 0) { for(ScriptNamedFunction *f = functions; f->name; f++) { nativeInterfaceFunctions.push_back(f); int slot = cppia.getInterfaceSlot(f->name); if (slot<0) printf("Interface slot '%s' not found\n",f->name); if (slot>interfaceSlotSize) interfaceSlotSize = slot; } } } #else interfaceVTables[ interface->name.utf8_str() ] = vtable; #endif if (!cppiaInterface) break; Functions &intfFuncs = cppiaInterface->memberFunctions; for(int f=0;fname); if (slot<0) printf("Interface slot '%s' not found\n",intfFuncs[f]->name.c_str()); if (slot>interfaceSlotSize) interfaceSlotSize = slot; } id = cppiaInterface->superId; } } if (interfaceSlotSize) interfaceSlotSize++; vtable = new void*[vtableSlot + 2 + interfaceSlotSize]; memset(vtable, 0, sizeof(void *)*(vtableSlot+2+interfaceSlotSize)); vtable += interfaceSlotSize; *vtable++ = this; DBGLOG(" vtable size %d -> %p\n", vtableSlot, vtable); // Extract special function ... for(int i=0;iname == "new") { newFunc = staticFunctions[i]; staticFunctions.erase( staticFunctions.begin() + i); } else if (staticFunctions[i]->name == "__init__") { initExpr = staticFunctions[i]->funExpr; staticFunctions.erase( staticFunctions.begin() + i); } else i++; } for(int i=0;i=330) base->_hx_setIdentity(cppia.strings[e.nameId],i,0); #else base->__Set( cppia.strings[e.nameId],i,null() ); #endif } else { e.index = i; e.value = createEnumClosure(e); } } if (!newFunc && cppiaSuper && cppiaSuper->newFunc) { //throw "No chaining constructor"; newFunc = cppiaSuper->newFunc; } DBGLOG(" this constructor %p\n", newFunc); } #ifdef CPPIA_JIT void CppiaClassInfo::compile() { for(int i=0;iname.c_str() ); staticFunctions[i]->compile(); } if (newFunc) newFunc->compile(); // Functions for(int i=0;iname.c_str() ); memberFunctions[i]->compile(); } } #endif void CppiaClassInfo::link() { int newPos = -1; for(int i=0;iname.c_str() ); staticFunctions[i]->link(); } if (newFunc) newFunc->link(); if (initExpr) initExpr = initExpr->link(cppia); // Functions for(int i=0;iname.c_str() ); memberFunctions[i]->link(); } for(int i=0;ilink(cppia); for(int i=0;ilink(cppia); for(int i=0;ivtableSlot ] = memberFunctions[i]->funExpr; if (interfaceSlotSize) { int interfaceSlot = cppia.findInterfaceSlot( memberFunctions[i]->name ); DBGLOG("Set %s : %s to %d @%p\n", name.c_str(), memberFunctions[i]->name.c_str(), interfaceSlot, vtable); if (interfaceSlot>0 && interfaceSlotfunExpr; } } // Find interface functions that are not implemented in client, but rely on host fallback... #if (HXCPP_API_LEVEL >= 330) if (!isInterface) { std::vector &nativeInterfaceFuncs = type->cppiaClass->nativeInterfaceFunctions; for(int i=0;iname); if (!vtable[-interfaceSlot]) vtable[-interfaceSlot] = new ScriptCallable(cppia,nativeInterfaceFuncs[i]); } } #endif // Vars ... if (!isInterface) { for(int i=0;ilink(cppia); //printf("Found haxeBase %s = %p / %d\n", cppia.types[typeId]->name.out_str(), haxeBase, dataSize ); } void CppiaClassInfo::init(CppiaCtx *ctx, int inPhase) { unsigned char *pointer = ctx->pointer; ctx->push( (hx::Object *) 0 ); // this AutoStack save(ctx,pointer); if (inPhase==0) { for(int i=0;irunInit(ctx); if (staticVars[i]->name==HX_CSTRING("__meta__")) { // Todo - delete/clean value mClass->__meta__ = staticVars[i]->objVal; staticVars.erase( staticVars.begin() + i ); i--; } } if (enumMeta) mClass->__meta__ = enumMeta->runObject(ctx); for(int i=0;irunInit(ctx); } else if (inPhase==1) { if (initExpr) initExpr->runVoid(ctx); } } Dynamic CppiaClassInfo::getStaticValue(const String &inName,hx::PropertyAccess inCallProp) { if (inCallProp==paccDynamic) inCallProp = isNativeProperty(inName) ? paccAlways : paccNever; if (inCallProp) { ScriptCallable *getter = findStaticGetter(inName); if (getter) { Array empty; return runFunExprDynamic(CppiaCtx::getCurrent(),getter,0, empty); } } CppiaExpr *closure = findFunction(true,inName); if (closure) return createMemberClosure(0,(ScriptCallable*)closure); // Look for dynamic function (variable) for(int i=0;inameId ]==inName) { CppiaVar *d = staticDynamicFunctions[i]; return d->getStaticValue(); } } for(int i=0;inameId ]==inName) return true; for(int i=0;i args = Array_obj::__new(1,1); args[0] = inValue; return runFunExprDynamic(CppiaCtx::getCurrent(),setter,0, args); } } // Look for dynamic function (variable) for(int i=0;inameId ]==inName) { CppiaVar *d = staticDynamicFunctions[i]; return d->setStaticValue(inValue); } } for(int i=0;i &ioFields) { for(int i=0;ipush(var.name); } if (inObject) { hx::FieldMap *map = inObject->__GetFieldMap(); if (map) FieldMapAppendFields(map, ioFields); } } Array CppiaClassInfo::GetClassFields() { Array result = Array_obj::__new(); if (isEnum) { for(int i=0;ipush(enumConstructors[i]->name); } else { for(int i=0;ipush(var.name); } for(int i=0;ipush(var.name); } for(int i=0;ipush(func.getName()); } } return result; } void CppiaClassInfo::markInstance(hx::Object *inThis, hx::MarkContext *__inCtx) { if (dynamicMapOffset) HX_MARK_MEMBER(getFieldMap(inThis)); for(int i=0;imark(inThis, __inCtx); // Only script members? for(int i=0;imark(inThis, __inCtx); } #ifdef HXCPP_VISIT_ALLOCS void CppiaClassInfo::visitInstance(hx::Object *inThis, hx::VisitContext *__inCtx) { if (dynamicMapOffset) HX_VISIT_MEMBER(getFieldMap(inThis)); for(int i=0;ivisit(inThis, __inCtx); for(int i=0;ivisit(inThis, __inCtx); } #endif // --- CppiaClass -------- class CppiaClass : public hx::Class_obj { public: CppiaClassInfo *info; CppiaClass(CppiaClassInfo *inInfo) { info = inInfo; } Array GetClassFields() { return info->GetClassFields(); } Array GetInstanceFields() { Array members = mSuper ? (*mSuper)->GetInstanceFields() : Array_obj::__new(0,0); for(int i=0;imemberFunctions.size();i++) { CppiaFunction *func = info->memberFunctions[i]; String name = func->getName(); if (members->Find(name)<0) members->push(name); } CppiaModule &module = info->cppia; for(int i=0;imemberVars.size();i++) { CppiaVar *var = info->memberVars[i]; if (var->isVirtual) continue; String name = module.strings[var->nameId]; if (members->Find(name)<0) members->push( name ); } for(int i=0;idynamicFunctions.size();i++) { CppiaVar *var = info->dynamicFunctions[i]; if (var->isVirtual) continue; String name = module.strings[var->nameId]; if (members->Find(name)<0) members->push(name); } return members; } void linkClass(CppiaModule &inModule,String inName) { mName = inName; mSuper = info->getSuperClass(); DBGLOG("LINK %p ########################### %s -> %p\n", this, mName.out_str(), mSuper ); //mStatics = Array_obj::__new(0,0); bool overwrite = false; hx::Class old = hx::Class_obj::Resolve(inName); // Overwrite cppia classes if (old.mPtr && dynamic_cast( old.mPtr ) ) overwrite = true; registerScriptable(overwrite); } Dynamic ConstructEmpty() { if (info->isEnum) return Dynamic(); Expressions none; return info->createInstance(CppiaCtx::getCurrent(),none,false); } Dynamic ConstructArgs(hx::DynamicArray inArgs) { return info->createInstance(CppiaCtx::getCurrent(),inArgs); } bool __IsEnum() { return info->isEnum; } Dynamic ConstructEnum(String inName,hx::DynamicArray inArgs) { if (!info->isEnum) return Dynamic(); int index = info->getEnumIndex(inName); return info->enumConstructors[index]->create(inArgs); } bool VCanCast(hx::Object *inPtr) { if (!inPtr) return false; hx::Class c = inPtr->__GetClass(); if (!c.mPtr) return false; if (info->isInterface) { // Can only be this cppia interface if it is a cppia class... CppiaClass *cppiaClass = dynamic_cast(c.mPtr); if (!cppiaClass) return false; return cppiaClass->info->implementsInterface(info); } hx::Class_obj *classPtr = c.mPtr; while(classPtr) { if (classPtr==this) return true; if (info->isEnum) return false; classPtr = classPtr->GetSuper().mPtr; } return false; } hx::Val __Field(const String &inName,hx::PropertyAccess inCallProp) { if (inName==HX_CSTRING("__meta__")) return __meta__; return info->getStaticValue(inName,inCallProp); } hx::Val __SetField(const String &inName,const hx::Val &inValue ,hx::PropertyAccess inCallProp) { return info->setStaticValue(inName,inValue,inCallProp); } bool __HasField(const String &inName) { if (inName==HX_CSTRING("__meta__")) return __meta__!=null(); return info->hasStaticValue(inName); } }; hx::Class_obj *createCppiaClass(CppiaClassInfo *inInfo) { return new CppiaClass(inInfo); } // --- Enum Base --- ::hx::ObjectPtr CppiaEnumBase::__GetClass() const { return classInfo->getClass(); } ::String CppiaEnumBase::GetEnumName( ) const { return classInfo->getClass()->mName; } ::String CppiaEnumBase::__ToString() const { #if (HXCPP_API_LEVEL>=330) return classInfo->getClass()->mName + HX_CSTRING(".") + _hx_tag; #else return classInfo->getClass()->mName + HX_CSTRING(".") + tag; #endif } void cppiaClassInit(CppiaClassInfo *inClass, CppiaCtx *ctx, int inPhase) { inClass->init(ctx,inPhase); } void cppiaClassMark(CppiaClassInfo *inClass,hx::MarkContext *__inCtx) { inClass->mark(__inCtx); } #ifdef HXCPP_VISIT_ALLOCS void cppiaClassVisit(CppiaClassInfo *inClass,hx::VisitContext *__inCtx) { inClass->visit(__inCtx); } #endif void linkCppiaClass(hx::Class_obj *inClass, CppiaModule &cppia, String inName) { ((CppiaClass *)inClass)->linkClass(cppia,inName); } int getScriptId(hx::Class inClass) { hx::Class_obj *ptr = inClass.mPtr; if (!ptr) return 0; CppiaClass *cls = dynamic_cast(ptr); if (!cls) return 0; return cls->info->cppia.scriptId; } ::String ScriptableToString(void *inClass) { CppiaClassInfo *info = (CppiaClassInfo *)inClass; return info->getClass()->toString(); } int ScriptableGetType(void *inClass) { CppiaClassInfo *info = (CppiaClassInfo *)inClass; return info->__GetType(); } hx::Class ScriptableGetClass(void *inClass) { CppiaClassInfo *info = (CppiaClassInfo *)inClass; return info->getClass(); } // Called by haxe generated code ... void ScriptableMark(void *inClass, hx::Object *inThis, hx::MarkContext *__inCtx) { ((CppiaClassInfo *)inClass)->markInstance(inThis, __inCtx); } #ifdef HXCPP_VISIT_ALLOCS void ScriptableVisit(void *inClass, hx::Object *inThis, hx::VisitContext *__inCtx) { ((CppiaClassInfo *)inClass)->visitInstance(inThis, __inCtx); } #endif bool ScriptableField(hx::Object *inObj, const ::String &inName,hx::PropertyAccess inCallProp,Dynamic &outResult) { void **vtable = inObj->__GetScriptVTable(); return ((CppiaClassInfo *)vtable[-1])->getField(inObj,inName,inCallProp,outResult); } bool ScriptableField(hx::Object *inObj, int inName,hx::PropertyAccess inCallProp,Float &outResult) { void **vtable = inObj->__GetScriptVTable(); Dynamic result; if ( ((CppiaClassInfo *)vtable[-1])->getField(inObj,__hxcpp_field_from_id(inName),inCallProp,result) ) { //CPPIA_CHECK(result); if (result.mPtr) outResult = result->__ToDouble(); else outResult = 0; return true; } return false; } bool ScriptableField(hx::Object *inObj, int inName,hx::PropertyAccess inCallProp,Dynamic &outResult) { void **vtable = inObj->__GetScriptVTable(); return ((CppiaClassInfo *)vtable[-1])->getField(inObj,__hxcpp_field_from_id(inName),inCallProp,outResult); } void ScriptableGetFields(hx::Object *inObject, Array< ::String> &outFields) { void **vtable = inObject->__GetScriptVTable(); return ((CppiaClassInfo *)vtable[-1])->GetInstanceFields(inObject,outFields); } bool ScriptableSetField(hx::Object *inObj, const ::String &inName, Dynamic inValue,hx::PropertyAccess inCallProp, Dynamic &outResult) { void **vtable = inObj->__GetScriptVTable(); return ((CppiaClassInfo *)vtable[-1])->setField(inObj,inName,inValue,inCallProp,outResult); } #if (HXCPP_API_LEVEL >= 330) void *hx::Object::_hx_getInterface(int inId) { void **vtable = __GetScriptVTable(); if (!vtable) return 0; CppiaClassInfo *info = ((CppiaClassInfo *)vtable[-1]); void *result = info->interfaceScriptTables[inId]; return info->interfaceScriptTables[inId]; } #endif } // end namespace hx