Optimizations to the generated bindings
This change gets rid of the call-time method binding query, instead it queries all method bindings up-front at initialization time so that no extra cost is added at function call time. In addition, also converted the "icall" code to a header-only library so one level of unnecessary call-stack is eliminated. Also changed binding generator to use real_t instead of double everywhere (except at the GDNative interface where unfortunately using doubles is hard-coded on the engine side). All this comes at a minimal increase in binary size (for the library, as actual native modules might not even increase in size in practice).pull/262/head
parent
f0fe88bd36
commit
01606fa212
|
@ -28,15 +28,15 @@ def generate_bindings(path):
|
||||||
source_file.write(impl)
|
source_file.write(impl)
|
||||||
|
|
||||||
|
|
||||||
icall_header_file = open("src/gen/__icalls.hpp", "w+")
|
icall_header_file = open("include/gen/__icalls.hpp", "w+")
|
||||||
icall_header_file.write(generate_icall_header(icalls))
|
icall_header_file.write(generate_icall_header(icalls))
|
||||||
|
|
||||||
icall_source_file = open("src/gen/__icalls.cpp", "w+")
|
|
||||||
icall_source_file.write(generate_icall_implementation(icalls))
|
|
||||||
|
|
||||||
register_types_file = open("src/gen/__register_types.cpp", "w+")
|
register_types_file = open("src/gen/__register_types.cpp", "w+")
|
||||||
register_types_file.write(generate_type_registry(classes))
|
register_types_file.write(generate_type_registry(classes))
|
||||||
|
|
||||||
|
init_method_bindings_file = open("src/gen/__init_method_bindings.cpp", "w+")
|
||||||
|
init_method_bindings_file.write(generate_init_method_bindings(classes))
|
||||||
|
|
||||||
|
|
||||||
def is_reference_type(t):
|
def is_reference_type(t):
|
||||||
for c in classes:
|
for c in classes:
|
||||||
|
@ -58,9 +58,10 @@ def make_gdnative_type(t):
|
||||||
if t == "int":
|
if t == "int":
|
||||||
return "int64_t "
|
return "int64_t "
|
||||||
if t == "float" or t == "real":
|
if t == "float" or t == "real":
|
||||||
return "double "
|
return "real_t "
|
||||||
return strip_name(t) + " "
|
return strip_name(t) + " "
|
||||||
|
|
||||||
|
|
||||||
def generate_class_header(used_classes, c):
|
def generate_class_header(used_classes, c):
|
||||||
|
|
||||||
source = []
|
source = []
|
||||||
|
@ -126,8 +127,8 @@ def generate_class_header(used_classes, c):
|
||||||
|
|
||||||
if c["base_class"] == "":
|
if c["base_class"] == "":
|
||||||
source.append("public: enum { ___CLASS_IS_SCRIPT = 0, };")
|
source.append("public: enum { ___CLASS_IS_SCRIPT = 0, };")
|
||||||
source.append("private:")
|
|
||||||
source.append("")
|
source.append("")
|
||||||
|
source.append("private:")
|
||||||
|
|
||||||
if c["singleton"]:
|
if c["singleton"]:
|
||||||
source.append("\tstatic " + class_name + " *_singleton;")
|
source.append("\tstatic " + class_name + " *_singleton;")
|
||||||
|
@ -135,8 +136,18 @@ def generate_class_header(used_classes, c):
|
||||||
source.append("\t" + class_name + "();")
|
source.append("\t" + class_name + "();")
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
|
# Generate method table
|
||||||
|
source.append("\tstruct ___method_bindings {")
|
||||||
|
|
||||||
|
for method in c["methods"]:
|
||||||
|
source.append("\t\tgodot_method_bind *mb_" + method["name"] + ";")
|
||||||
|
|
||||||
|
source.append("\t};")
|
||||||
|
source.append("\tstatic ___method_bindings ___mb;")
|
||||||
|
source.append("")
|
||||||
source.append("public:")
|
source.append("public:")
|
||||||
|
source.append("\tstatic void ___init_method_bindings();")
|
||||||
|
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
|
|
||||||
|
@ -335,7 +346,17 @@ def generate_class_implementation(icalls, used_classes, c):
|
||||||
source.append("")
|
source.append("")
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
|
# Method table initialization
|
||||||
|
source.append(class_name + "::___method_bindings " + class_name + "::___mb = {};")
|
||||||
|
source.append("")
|
||||||
|
|
||||||
|
source.append("void " + class_name + "::___init_method_bindings() {")
|
||||||
|
|
||||||
|
for method in c["methods"]:
|
||||||
|
source.append("\t___mb.mb_" + method["name"] + " = godot::api->godot_method_bind_get_method(\"" + c["name"] + "\", \"" + method["name"] + "\");")
|
||||||
|
|
||||||
|
source.append("}")
|
||||||
|
source.append("")
|
||||||
|
|
||||||
if c["instanciable"]:
|
if c["instanciable"]:
|
||||||
source.append(class_name + " *" + strip_name(c["name"]) + "::_new()")
|
source.append(class_name + " *" + strip_name(c["name"]) + "::_new()")
|
||||||
|
@ -373,12 +394,6 @@ def generate_class_implementation(icalls, used_classes, c):
|
||||||
source.append("}")
|
source.append("}")
|
||||||
source.append("")
|
source.append("")
|
||||||
continue
|
continue
|
||||||
else:
|
|
||||||
|
|
||||||
source.append("\tstatic godot_method_bind *mb = nullptr;")
|
|
||||||
source.append("\tif (mb == nullptr) {")
|
|
||||||
source.append("\t\tmb = godot::api->godot_method_bind_get_method(\"" + c["name"] +"\", \"" + method["name"] + "\");")
|
|
||||||
source.append("\t}")
|
|
||||||
|
|
||||||
return_statement = ""
|
return_statement = ""
|
||||||
|
|
||||||
|
@ -441,7 +456,7 @@ def generate_class_implementation(icalls, used_classes, c):
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
source.append("\tVariant __result;")
|
source.append("\tVariant __result;")
|
||||||
source.append("\t*(godot_variant *) &__result = godot::api->godot_method_bind_call(mb, ((const Object *) " + core_object_name + ")->_owner, (const godot_variant **) __args, " + size + ", nullptr);")
|
source.append("\t*(godot_variant *) &__result = godot::api->godot_method_bind_call(___mb.mb_" + method["name"] + ", ((const Object *) " + core_object_name + ")->_owner, (const godot_variant **) __args, " + size + ", nullptr);")
|
||||||
|
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
|
@ -485,7 +500,7 @@ def generate_class_implementation(icalls, used_classes, c):
|
||||||
|
|
||||||
icall_name = get_icall_name(icall_sig)
|
icall_name = get_icall_name(icall_sig)
|
||||||
|
|
||||||
return_statement += icall_name + "(mb, (const Object *) " + core_object_name
|
return_statement += icall_name + "(___mb.mb_" + method["name"] + ", (const Object *) " + core_object_name
|
||||||
|
|
||||||
for arg in method["arguments"]:
|
for arg in method["arguments"]:
|
||||||
return_statement += ", " + escape_cpp(arg["name"]) + (".ptr()" if is_reference_type(arg["type"]) else "")
|
return_statement += ", " + escape_cpp(arg["name"]) + (".ptr()" if is_reference_type(arg["type"]) else "")
|
||||||
|
@ -520,60 +535,6 @@ def generate_icall_header(icalls):
|
||||||
source.append("#include <stdint.h>")
|
source.append("#include <stdint.h>")
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
source.append("#include <core/CoreTypes.hpp>")
|
|
||||||
source.append("#include \"Object.hpp\"")
|
|
||||||
source.append("")
|
|
||||||
source.append("")
|
|
||||||
|
|
||||||
source.append("namespace godot {")
|
|
||||||
source.append("")
|
|
||||||
|
|
||||||
for icall in icalls:
|
|
||||||
ret_type = icall[0]
|
|
||||||
args = icall[1]
|
|
||||||
|
|
||||||
method_signature = ""
|
|
||||||
|
|
||||||
method_signature += return_type(ret_type) + get_icall_name(icall) + "(godot_method_bind *mb, const Object *inst"
|
|
||||||
|
|
||||||
for arg in args:
|
|
||||||
method_signature += ", const "
|
|
||||||
|
|
||||||
if is_core_type(arg):
|
|
||||||
method_signature += arg + "&"
|
|
||||||
elif arg == "int":
|
|
||||||
method_signature += "int64_t "
|
|
||||||
elif arg == "float":
|
|
||||||
method_signature += "double "
|
|
||||||
elif is_primitive(arg):
|
|
||||||
method_signature += arg
|
|
||||||
else:
|
|
||||||
method_signature += "Object *"
|
|
||||||
|
|
||||||
method_signature += ");"
|
|
||||||
|
|
||||||
source.append(method_signature)
|
|
||||||
|
|
||||||
source.append("")
|
|
||||||
|
|
||||||
source.append("}")
|
|
||||||
source.append("")
|
|
||||||
|
|
||||||
source.append("#endif")
|
|
||||||
|
|
||||||
return "\n".join(source)
|
|
||||||
|
|
||||||
|
|
||||||
def generate_icall_implementation(icalls):
|
|
||||||
source = []
|
|
||||||
source.append("#include \"__icalls.hpp\"")
|
|
||||||
|
|
||||||
source.append("")
|
|
||||||
|
|
||||||
source.append("#include <gdnative_api_struct.gen.h>")
|
|
||||||
source.append("#include <stdint.h>")
|
|
||||||
source.append("")
|
|
||||||
|
|
||||||
source.append("#include <core/GodotGlobal.hpp>")
|
source.append("#include <core/GodotGlobal.hpp>")
|
||||||
source.append("#include <core/CoreTypes.hpp>")
|
source.append("#include <core/CoreTypes.hpp>")
|
||||||
source.append("#include \"Object.hpp\"")
|
source.append("#include \"Object.hpp\"")
|
||||||
|
@ -587,15 +548,15 @@ def generate_icall_implementation(icalls):
|
||||||
ret_type = icall[0]
|
ret_type = icall[0]
|
||||||
args = icall[1]
|
args = icall[1]
|
||||||
|
|
||||||
method_signature = ""
|
method_signature = "static inline "
|
||||||
|
|
||||||
method_signature += return_type(ret_type) + get_icall_name(icall) + "(godot_method_bind *mb, const Object *inst"
|
method_signature += get_icall_return_type(ret_type) + get_icall_name(icall) + "(godot_method_bind *mb, const Object *inst"
|
||||||
|
|
||||||
for i, arg in enumerate(args):
|
for i, arg in enumerate(args):
|
||||||
method_signature += ", const "
|
method_signature += ", const "
|
||||||
|
|
||||||
if is_core_type(arg):
|
if is_core_type(arg):
|
||||||
method_signature += arg + "& "
|
method_signature += arg + "&"
|
||||||
elif arg == "int":
|
elif arg == "int":
|
||||||
method_signature += "int64_t "
|
method_signature += "int64_t "
|
||||||
elif arg == "float":
|
elif arg == "float":
|
||||||
|
@ -612,7 +573,7 @@ def generate_icall_implementation(icalls):
|
||||||
source.append(method_signature + " {")
|
source.append(method_signature + " {")
|
||||||
|
|
||||||
if ret_type != "void":
|
if ret_type != "void":
|
||||||
source.append("\t" + ("godot_object *" if is_class_type(ret_type) else return_type(ret_type)) + "ret;")
|
source.append("\t" + ("godot_object *" if is_class_type(ret_type) else get_icall_return_type(ret_type)) + "ret;")
|
||||||
if is_class_type(ret_type):
|
if is_class_type(ret_type):
|
||||||
source.append("\tret = nullptr;")
|
source.append("\tret = nullptr;")
|
||||||
|
|
||||||
|
@ -646,15 +607,16 @@ def generate_icall_implementation(icalls):
|
||||||
source.append("\treturn ret;")
|
source.append("\treturn ret;")
|
||||||
|
|
||||||
source.append("}")
|
source.append("}")
|
||||||
|
source.append("")
|
||||||
|
|
||||||
source.append("}")
|
source.append("}")
|
||||||
source.append("")
|
source.append("")
|
||||||
|
|
||||||
|
source.append("#endif")
|
||||||
|
|
||||||
return "\n".join(source)
|
return "\n".join(source)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def generate_type_registry(classes):
|
def generate_type_registry(classes):
|
||||||
source = []
|
source = []
|
||||||
|
|
||||||
|
@ -695,18 +657,34 @@ def generate_type_registry(classes):
|
||||||
return "\n".join(source)
|
return "\n".join(source)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_init_method_bindings(classes):
|
||||||
|
source = []
|
||||||
|
|
||||||
|
for c in classes:
|
||||||
|
source.append("#include <" + strip_name(c["name"]) + ".hpp>")
|
||||||
|
|
||||||
|
source.append("")
|
||||||
|
source.append("")
|
||||||
|
|
||||||
|
source.append("namespace godot {")
|
||||||
|
|
||||||
|
source.append("void ___init_method_bindings()")
|
||||||
|
source.append("{")
|
||||||
|
|
||||||
|
for c in classes:
|
||||||
|
class_name = strip_name(c["name"])
|
||||||
|
|
||||||
|
source.append("\t" + strip_name(c["name"]) + "::___init_method_bindings();")
|
||||||
|
|
||||||
|
source.append("}")
|
||||||
|
|
||||||
|
source.append("")
|
||||||
|
source.append("}")
|
||||||
|
|
||||||
|
return "\n".join(source)
|
||||||
|
|
||||||
|
|
||||||
|
def get_icall_return_type(t):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def return_type(t):
|
|
||||||
if is_class_type(t):
|
if is_class_type(t):
|
||||||
return "Object *"
|
return "Object *"
|
||||||
if t == "int":
|
if t == "int":
|
||||||
|
|
Loading…
Reference in New Issue