void CSModuleWriter::GenerateManagedModuleClass(String& sourceOut) { Indent(); String source; String line = ToString("public static partial class %sModule\n", module_->GetName().CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); source += IndentLine("public static void Initialize()\n"); source += IndentLine("{\n"); Indent(); Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values(); for (unsigned i = 0; i < classes.Size(); i++) { JSBClass* klass = classes.At(i); JSBPackage* package = module_->GetPackage(); if (klass->IsNumberArray() || klass->IsAbstract()) continue; line = ToString("NativeCore.RegisterNativeType(typeof(%s));\n", klass->GetName().CString()); source += IndentLine(line); line = ToString("NativeCore.nativeClassIDToManagedConstructor [ %s.csb_%s_%s_GetClassIDStatic ()] = (IntPtr x) => {\n", klass->GetName().CString(), package->GetName().CString(), klass->GetName().CString()); source += IndentLine(line); Indent(); source += IndentLine(ToString("return new %s (x);\n", klass->GetName().CString())); Dedent(); source += IndentLine("};\n"); } Dedent(); source += IndentLine("}\n"); Dedent(); source += IndentLine("}\n"); sourceOut += source; Dedent(); }
void JSFunctionWriter::WriteConstructor(String& source) { // TODO: refactor this if (function_->name_ == "RefCounted") { source.Append("// finalizer may be called more than once\n" \ "static int jsb_finalizer_RefCounted(duk_context *ctx)\n" \ "{\n" \ "JSVM* vm = JSVM::GetJSVM(ctx);\n" \ \ "duk_get_prop_index(ctx, 0, JS_INSTANCE_INDEX_FINALIZED);\n" \ \ "if (!duk_is_boolean(ctx, -1))\n" \ "{\n" \ "RefCounted* ref = vm->GetObjectPtr(duk_get_heapptr(ctx, 0));\n" \ "vm->RemoveObject(ref);\n" \ "ref->ReleaseRef();\n" \ "duk_push_boolean(ctx, 1);\n" \ "duk_put_prop_index(ctx, 0, JS_INSTANCE_INDEX_FINALIZED);\n" \ "}\n" \ \ "return 0;\n" \ "}\n"); } JSBClass* klass = function_->class_; JSBClass* base = klass->GetBaseClass(); // Constructor source.AppendWithFormat("duk_ret_t jsb_constructor_%s(duk_context* ctx)\n{\n", klass->GetName().CString()); source.Append( "\nJSVM* vm = JSVM::GetJSVM(ctx);\n" \ "duk_push_this(ctx);\n" \ "void *ptr = duk_get_heapptr(ctx, -1);\n" \ "duk_pop(ctx);\n\n"); source.Append(" if (!vm->GetObjectPtr(ptr, true))\n {\n"); if (!klass->IsAbstract() && !klass->IsNumberArray()) { String marshal; WriteParameterMarshal(marshal); String sparams; int cparam = 0; const Vector<JSBFunctionType*>& parameters = function_->GetParameters(); for (unsigned i = 0; i < parameters.Size(); i++, cparam++) { JSBFunctionType * ptype = parameters.At(i); String sarg; if (ptype->type_->asClassType()) { JSBClassType* classType = ptype->type_->asClassType(); JSBClass* klass = classType->class_; if (klass->GetName() == "Context") { sarg = "vm->GetContext()"; cparam--; } } if (!sarg.Length()) { sarg.AppendWithFormat("__arg%i", cparam); } sparams += sarg; if (i + 1 < parameters.Size()) sparams += ", "; } source.AppendWithFormat("if (!duk_get_top(ctx) || !duk_is_pointer(ctx, 0))\n"\ "{\n"\ "%s\n"\ "%s* native = new %s(%s);\n" \ "vm->AddObject(ptr, native, INSTANTIATION_JAVASCRIPT);\n"\ "}\n" \ "else if (duk_is_pointer(ctx, 0))\n" \ "{\n" \ "RefCounted* rc = (RefCounted*) duk_get_pointer(ctx, 0);\n" \ "vm->AddObject(ptr, rc, rc->GetInstantiationType());\n" \ "}\n", marshal.CString(), klass->GetNativeName().CString(), klass->GetNativeName().CString(), sparams.CString()); } else { if (klass->IsAbstract()) source.Append("assert(0); // abstract class new'd\n"); if (klass->IsNumberArray()) source.Append("assert(0); // number array class new'd\n"); } source.Append(" }\n"); if (base) { String basePackage = base->GetModule()->GetPackage()->GetName(); source.AppendWithFormat(" js_constructor_basecall(ctx, \"%s\", \"%s\");\n", basePackage.CString(), base->GetName().CString()); } if (function_->name_ == "RefCounted") { source.Append("duk_push_this(ctx);\n "\ "duk_push_c_function(ctx, jsb_finalizer_RefCounted, 1);\n "\ "duk_set_finalizer(ctx, -2);\n "\ "duk_pop(ctx);\n"); } source += " return 0;"; source += "\n}\n"; }
void CSFunctionWriter::WriteNativeFunction(String& source) { JSBClass* klass = function_->GetClass(); JSBPackage* package = klass->GetPackage(); String fname = function_->IsConstructor() ? "Constructor" : function_->GetName(); String returnType; String functionSig = CSTypeHelper::GetNativeFunctionSignature(function_, returnType); String line; line = ToString("ATOMIC_EXPORT_API %s %s\n", returnType.CString(), functionSig.CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); source += "\n"; bool returnValue = false; bool sharedPtrReturn = false; String returnStatement; if (returnType == "const char*") { returnValue = true; source += IndentLine("static String returnValue;\n"); returnStatement = "returnValue = "; } else if (function_->GetReturnClass() && function_->GetReturnClass()->IsNumberArray()) { returnStatement = "*returnValue = "; } else if (function_->GetReturnClass() && function_->GetReturnType()->isSharedPtr_) { returnStatement = ToString("SharedPtr<%s> returnValue = ", function_->GetReturnClass()->GetNativeName().CString()); sharedPtrReturn = true; } else { if (returnType != "void") { returnStatement = "return "; } } String callSig; GenNativeCallParameters(callSig); if (!function_->isConstructor_) { if (function_->IsStatic()) { line = ToString("%s%s::%s(%s);\n", returnStatement.CString(), klass->GetNativeName().CString(), function_->GetName().CString(), callSig.CString()); } else { line = ToString("%sself->%s(%s);\n", returnStatement.CString(), function_->GetName().CString(), callSig.CString()); } } else { if (klass->IsAbstract()) { line = "return 0; // Abstract Class\n"; } else if (klass->IsObject()) { if (callSig.Length()) line = ToString("return new %s(NETCore::GetContext(), %s);\n", klass->GetNativeName().CString(), callSig.CString()); else line = ToString("return new %s(NETCore::GetContext());\n", klass->GetNativeName().CString()); } else { line = ToString("return new %s(%s);\n", klass->GetNativeName().CString(), callSig.CString()); } } source += IndentLine(line); if (sharedPtrReturn) { source += IndentLine("returnValue->AddRef();\n"); source += IndentLine("return returnValue;\n"); } else if (returnType == "const char*") { source += IndentLine("return returnValue.CString();\n"); } Dedent(); source += IndentLine("}\n"); source += "\n"; }
void CSFunctionWriter::WriteNativeFunction(String& source) { JSBClass* klass = function_->GetClass(); JSBPackage* package = klass->GetPackage(); String fname = function_->IsConstructor() ? "Constructor" : function_->GetName(); String returnType; String functionSig = CSTypeHelper::GetNativeFunctionSignature(function_, returnType); String line; line = ToString("ATOMIC_EXPORT_API %s %s\n", returnType.CString(), functionSig.CString()); source += IndentLine(line); source += IndentLine("{\n"); Indent(); source += "\n"; // vector marshal bool hasVectorMarshal = false; const Vector<JSBFunctionType*>& fparams = function_->GetParameters(); for (unsigned i = 0; i < fparams.Size(); i++) { JSBFunctionType* ftype = fparams[i]; // Interface JSBClass* interface = 0; if (ftype->type_->asClassType() && ftype->type_->asClassType()->class_->IsInterface()) { // We need to downcast to the interface // TODO: this assumes Object* is in hierarchy, how do we validate this? interface = ftype->type_->asClassType()->class_; line = ToString("%s = dynamic_cast<%s*>((Object*)%s);\n", ftype->name_.CString(), interface->GetNativeName().CString(), ftype->name_.CString()); source += IndentLine(line); } // Vector JSBVectorType* vtype = ftype->type_->asVectorType(); if (!vtype) continue; JSBClassType* classType = vtype->vectorType_->asClassType(); if (!classType) continue; String className = classType->class_->GetName(); String vectorMarshal; hasVectorMarshal = true; if (vtype->isPODVector_) { const String& pname = ftype->name_; source += IndentLine(ToString("PODVector<%s*> %s__vector;\n", className.CString(), pname.CString())); source += IndentLine(ToString("if (%s) %s->AdaptToVector<%s*>(%s__vector);\n", pname.CString(), pname.CString(), className.CString(), pname.CString())); } else { // vectorMarshal = ToString("PODVector<%s*> %s__vector", className.CString(), ftype->name_.CString()); } if (vectorMarshal.Length()) { source += IndentLine(vectorMarshal); vectorMarshal = String::EMPTY; } } bool returnValue = false; bool sharedPtrReturn = false; String returnStatement; if (returnType == "const char*") { returnValue = true; source += IndentLine("static String returnValue;\n"); returnStatement = "returnValue = "; } else if (function_->GetReturnClass() && function_->GetReturnClass()->IsNumberArray()) { returnStatement = "*returnValue = "; } else if (function_->GetReturnClass() && function_->GetReturnType()->isSharedPtr_) { returnStatement = ToString("SharedPtr<%s> returnValue = ", function_->GetReturnClass()->GetNativeName().CString()); sharedPtrReturn = true; } else if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType()) { // we have an out parameter JSBVectorType* vtype = function_->GetReturnType()->type_->asVectorType(); if (!vtype->vectorTypeIsSharedPtr_ && !vtype->vectorTypeIsWeakPtr_) { returnStatement = ToString("%sVector<%s*> returnValue__vector = ", vtype->isPODVector_ ? "POD" : "", vtype->vectorType_->asClassType()->class_->GetName().CString()); } else { returnStatement = ToString("%sVector<%s<%s>> returnValue__vector = ", vtype->isPODVector_ ? "POD" : "", vtype->vectorTypeIsSharedPtr_ ? "SharedPtr" : "WeakPtr", vtype->vectorType_->asClassType()->class_->GetName().CString()); } } else { if (returnType != "void" && !hasVectorMarshal) { returnStatement = "return "; } else if (returnType != "void") { returnStatement = ToString("%s returnValue = ", returnType.CString()); } } String callSig; GenNativeCallParameters(callSig); if (!function_->isConstructor_) { if (function_->IsStatic()) { line = ToString("%s%s::%s(%s);\n", returnStatement.CString(), klass->GetNativeName().CString(), function_->GetName().CString(), callSig.CString()); } else { line = ToString("%sself->%s(%s);\n", returnStatement.CString(), function_->GetName().CString(), callSig.CString()); } } else { if (klass->IsAbstract()) { line = "return 0; // Abstract Class\n"; } else if (klass->IsObject()) { if (callSig.Length()) line = ToString("return new %s(NETCore::GetContext(), %s);\n", klass->GetNativeName().CString(), callSig.CString()); else line = ToString("return new %s(NETCore::GetContext());\n", klass->GetNativeName().CString()); } else { line = ToString("return new %s(%s);\n", klass->GetNativeName().CString(), callSig.CString()); } } source += IndentLine(line); // Vector marshaling for (unsigned i = 0; i < fparams.Size(); i++) { JSBFunctionType* ftype = fparams[i]; JSBVectorType* vtype = ftype->type_->asVectorType(); if (!vtype) continue; JSBClassType* classType = vtype->vectorType_->asClassType(); if (!classType) continue; String className = classType->class_->GetName(); String vectorMarshal; if (vtype->isPODVector_) { const String& pname = ftype->name_; source += IndentLine(ToString("if (%s) %s->AdaptFromVector<%s*>(%s__vector);\n", pname.CString(), pname.CString(), className.CString(), pname.CString())); } else { // vectorMarshal = ToString("PODVector<%s*> %s__vector", className.CString(), ftype->name_.CString()); } if (vectorMarshal.Length()) { source += IndentLine(vectorMarshal); vectorMarshal = String::EMPTY; } } if (sharedPtrReturn) { source += IndentLine("if (returnValue.NotNull()) returnValue->AddRef();\n"); source += IndentLine("return returnValue;\n"); } else if (returnType == "const char*") { source += IndentLine("return returnValue.CString();\n"); } else if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType()) { // we have an out parameter JSBVectorType* vtype = function_->GetReturnType()->type_->asVectorType(); source += IndentLine("if (returnValue) returnValue->AdaptFromVector(returnValue__vector);\n"); } else if (returnType != "void" && hasVectorMarshal) { source += IndentLine("return returnValue;\n"); } Dedent(); source += IndentLine("}\n"); source += "\n"; }