Skip to content

Commit

Permalink
Optimizations to the generated bindings
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
aqnuep committed Apr 10, 2019
1 parent f0fe88b commit 01606fa
Showing 1 changed file with 53 additions and 75 deletions.
128 changes: 53 additions & 75 deletions binding_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ def generate_bindings(path):
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_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.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):
for c in classes:
Expand All @@ -58,9 +58,10 @@ def make_gdnative_type(t):
if t == "int":
return "int64_t "
if t == "float" or t == "real":
return "double "
return "real_t "
return strip_name(t) + " "


def generate_class_header(used_classes, c):

source = []
Expand Down Expand Up @@ -126,17 +127,27 @@ def generate_class_header(used_classes, c):

if c["base_class"] == "":
source.append("public: enum { ___CLASS_IS_SCRIPT = 0, };")
source.append("private:")
source.append("")
source.append("private:")

if c["singleton"]:
source.append("\tstatic " + class_name + " *_singleton;")
source.append("")
source.append("\t" + class_name + "();")
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("\tstatic void ___init_method_bindings();")

source.append("")


Expand Down Expand Up @@ -335,7 +346,17 @@ def generate_class_implementation(icalls, used_classes, c):
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"]:
source.append(class_name + " *" + strip_name(c["name"]) + "::_new()")
Expand Down Expand Up @@ -373,12 +394,6 @@ def generate_class_implementation(icalls, used_classes, c):
source.append("}")
source.append("")
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 = ""

Expand Down Expand Up @@ -441,7 +456,7 @@ def get_icall_type_name(name):
source.append("")

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("")

Expand Down Expand Up @@ -485,7 +500,7 @@ def get_icall_type_name(name):

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"]:
return_statement += ", " + escape_cpp(arg["name"]) + (".ptr()" if is_reference_type(arg["type"]) else "")
Expand Down Expand Up @@ -520,60 +535,6 @@ def generate_icall_header(icalls):
source.append("#include <stdint.h>")
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/CoreTypes.hpp>")
source.append("#include \"Object.hpp\"")
Expand All @@ -587,15 +548,15 @@ def generate_icall_implementation(icalls):
ret_type = icall[0]
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):
method_signature += ", const "

if is_core_type(arg):
method_signature += arg + "& "
method_signature += arg + "&"
elif arg == "int":
method_signature += "int64_t "
elif arg == "float":
Expand All @@ -612,7 +573,7 @@ def generate_icall_implementation(icalls):
source.append(method_signature + " {")

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):
source.append("\tret = nullptr;")

Expand Down Expand Up @@ -646,13 +607,14 @@ def generate_icall_implementation(icalls):
source.append("\treturn ret;")

source.append("}")
source.append("")

source.append("}")
source.append("")

return "\n".join(source)

source.append("#endif")

return "\n".join(source)


def generate_type_registry(classes):
Expand Down Expand Up @@ -695,18 +657,34 @@ def generate_type_registry(classes):
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 return_type(t):
def get_icall_return_type(t):
if is_class_type(t):
return "Object *"
if t == "int":
Expand Down

0 comments on commit 01606fa

Please sign in to comment.