Skip to content

Commit

Permalink
🐛 Fix virtual methods to not use template meta programming
Browse files Browse the repository at this point in the history
Implementation to test godotengine/godot#80671

Fixes #11
  • Loading branch information
fuzzybinary committed Aug 16, 2023
1 parent a818a72 commit 845db37
Show file tree
Hide file tree
Showing 13 changed files with 2,996 additions and 503 deletions.
3,272 changes: 2,902 additions & 370 deletions godot-headers/godot/extension_api.json

Large diffs are not rendered by default.

56 changes: 50 additions & 6 deletions godot-headers/godot/gdextension_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ typedef void (*GDExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instan
typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance)(void *p_userdata);
typedef void (*GDExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance);
typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual)(void *p_userdata, GDExtensionConstStringNamePtr p_name);
typedef void *(*GDExtensionClassGetVirtuaCallData)(void *p_userdata, GDExtensionConstStringNamePtr p_name);
typedef void (*GDExtensionClassCallVirtualWithData)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, void *p_userdata, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);

typedef struct {
GDExtensionBool is_virtual;
Expand All @@ -283,6 +285,12 @@ typedef struct {
GDExtensionClassCreateInstance create_instance_func; // (Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract.
GDExtensionClassFreeInstance free_instance_func; // Destructor; mandatory.
GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
// Can be used instead of `get_virtual_func`. Returns user data (non-null) that will be passed back when calling `call_virtual_func`.
// Returning `null` from this function signals to Godot that the virutal function is not overriden.
// Data provided to this function must live until the GDExtensionInstance is freed, but should be deleted when `free_instance_func` is called.
GDExtensionClassGetVirtuaCallData get_virtual_call_data_func;
// Used to call virtual functions when `get_virtual_call_data_func` is not null.
GDExtensionClassCallVirtualWithData call_virtual_func;
GDExtensionClassGetRID get_rid_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings.
} GDExtensionClassCreationInfo;
Expand Down Expand Up @@ -1526,6 +1534,25 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqWcstr)(GDExtensionStringP
*/
typedef void (*GDExtensionInterfaceStringOperatorPlusEqC32str)(GDExtensionStringPtr p_self, const char32_t *p_b);

/**
* @name string_resize
* @since 4.2
*
* Resizes the underlying string data to the given number of characters.
*
* Space needs to be allocated for the null terminating character ('\0') which
* also must be added manually, in order for all string functions to work correctly.
*
* Warning: This is an error-prone operation - only use it if there's no other
* efficient way to accomplish your goal.
*
* @param p_self A pointer to the String.
* @param p_resize The new length for the String.
*
* @return Error code signifying if the operation successful.
*/
typedef GDExtensionInt (*GDExtensionInterfaceStringResize)(GDExtensionStringPtr p_self, GDExtensionInt p_resize);

/* INTERFACE: XMLParser Utilities */

/**
Expand Down Expand Up @@ -2110,13 +2137,13 @@ typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate)
/**
* @name object_get_script_instance
* @since 4.2
*
*
* Get the script instance data attached to this object.
*
* @param p_object A pointer to the Object
* @param p_language A pointer to the language expected for this script instance
*
* @return A GDExtensionScriptInstanceDataPtr that was attached to this object as part of script_instance_create
*
* @param p_object A pointer to the Object.
* @param p_language A pointer to the language expected for this script instance.
*
* @return A GDExtensionScriptInstanceDataPtr that was attached to this object as part of script_instance_create.
*/
typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptInstance)(GDExtensionConstObjectPtr p_object, GDExtensionObjectPtr p_language);

Expand Down Expand Up @@ -2224,6 +2251,23 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant)
*/
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassProperty)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter);

/**
* @name classdb_register_extension_class_property_indexed
* @since 4.2
*
* Registers an indexed property on an extension class in the ClassDB.
*
* Provided struct can be safely freed once the function returns.
*
* @param p_library A pointer the library received by the GDExtension's entry point function.
* @param p_class_name A pointer to a StringName with the class name.
* @param p_info A pointer to a GDExtensionPropertyInfo struct.
* @param p_setter A pointer to a StringName with the name of the setter method.
* @param p_getter A pointer to a StringName with the name of the getter method.
* @param p_index The index to pass as the first argument to the getter and setter methods.
*/
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassPropertyIndexed)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter, GDExtensionInt p_index);

/**
* @name classdb_register_extension_class_property_group
* @since 4.1
Expand Down
39 changes: 28 additions & 11 deletions src/cpp/dart_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include <godot/gdextension_interface.h>

#include "dart_script_instance.h"
#include "dart_vtable_wrapper.h"
#include "gde_dart_converters.h"
#include "gde_wrapper.h"
#include "godot_string_wrappers.h"
Expand Down Expand Up @@ -144,8 +143,6 @@ GodotDartBindings::~GodotDartBindings() {
}

bool GodotDartBindings::initialize(const char *script_path, const char *package_config) {
dart_vtable_wrapper::init_virtual_thunks();

DartDllConfig config;
if (GDEWrapper::instance()->is_editor_hint()) {
config.service_port = 6222;
Expand Down Expand Up @@ -653,22 +650,23 @@ void GodotDartBindings::class_free_instance(void *p_userdata, GDExtensionClassIn
});
}

GDExtensionClassCallVirtual GodotDartBindings::get_virtual_func(void *p_userdata,
GDExtensionConstStringNamePtr p_name) {
void *GodotDartBindings::get_virtual_call_data(void *p_userdata, GDExtensionConstStringNamePtr p_name) {
GodotDartBindings *bindings = GodotDartBindings::instance();
if (!bindings) {
// oooff
return nullptr;
}

GDExtensionClassCallVirtual func = nullptr;
void *user_data = nullptr;
bindings->execute_on_dart_thread([&]() {
DartBlockScope scope;

Dart_Handle type = Dart_HandleFromPersistent(reinterpret_cast<Dart_PersistentHandle>(p_userdata));

DART_CHECK(typeInfo, Dart_GetField(type, Dart_NewStringFromCString("sTypeInfo")), "Error finding sTypeInfo on Type");
DART_CHECK(vtable, Dart_GetField(typeInfo, Dart_NewStringFromCString("vTable")), "Error finding vTable from TypeInfo");
DART_CHECK(typeInfo, Dart_GetField(type, Dart_NewStringFromCString("sTypeInfo")),
"Error finding sTypeInfo on Type");
DART_CHECK(vtable, Dart_GetField(typeInfo, Dart_NewStringFromCString("vTable")),
"Error finding vTable from TypeInfo");
if (Dart_IsNull(vtable)) {
return;
}
Expand All @@ -687,10 +685,27 @@ GDExtensionClassCallVirtual GodotDartBindings::get_virtual_func(void *p_userdata
uint64_t address = 0;
Dart_IntegerToUint64(dart_address, &address);

func = dart_vtable_wrapper::get_wrapped_virtual(reinterpret_cast<GDExtensionClassCallVirtual>(address));
user_data = (void *)address;
});

return func;
return user_data;
}

void GodotDartBindings::call_virtual_func(void* p_instance, GDExtensionConstStringNamePtr p_name,
void *p_userdata, const GDExtensionConstTypePtr *p_args,
GDExtensionTypePtr r_ret) {
GodotDartBindings *bindings = GodotDartBindings::instance();
if (!bindings) {
// oooff
return;
}

bindings->execute_on_dart_thread([&]() {
DartBlockScope scope;

GDExtensionClassCallVirtual dart_call = (GDExtensionClassCallVirtual)p_userdata;
dart_call(p_instance, p_args, r_ret);
});
}

/* Static Functions From Dart */
Expand Down Expand Up @@ -737,7 +752,9 @@ void bind_class(Dart_NativeArguments args) {
info.class_userdata = (void *)Dart_NewPersistentHandle(type_arg);
info.create_instance_func = GodotDartBindings::class_create_instance;
info.free_instance_func = GodotDartBindings::class_free_instance;
info.get_virtual_func = GodotDartBindings::get_virtual_func;
//info.get_virtual_func = GodotDartBindings::get_virtual_func;
info.get_virtual_call_data_func = GodotDartBindings::get_virtual_call_data;
info.call_virtual_func = GodotDartBindings::call_virtual_func;

gde_classdb_register_extension_class(GDEWrapper::instance()->get_library_ptr(), sn_name, sn_parent, &info);
}
Expand Down
4 changes: 3 additions & 1 deletion src/cpp/dart_bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ class GodotDartBindings {

static GDExtensionObjectPtr class_create_instance(void *p_userdata);
static void class_free_instance(void *p_userdata, GDExtensionClassInstancePtr p_instance);
static GDExtensionClassCallVirtual get_virtual_func(void *p_userdata, GDExtensionConstStringNamePtr p_name);
static void *get_virtual_call_data(void *p_userdata, GDExtensionConstStringNamePtr p_name);
static void call_virtual_func(void* p_instance, GDExtensionConstStringNamePtr p_name,
void *p_userdata, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);

private:
static void bind_call(void *method_userdata, GDExtensionClassInstancePtr instance,
Expand Down
16 changes: 9 additions & 7 deletions src/cpp/dart_script_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,13 +284,16 @@ void DartScriptInstance::call(const GDStringName *p_method, const GDExtensionCon
if (gde == nullptr) {
return;
}

// TODO: Figure out wth placeholders do
if (_is_placeholder) {
// Placeholders always return CALL_ERROR_INVALID_METHOD
r_error->error = GDEXTENSION_CALL_ERROR_INVALID_METHOD;
return;
}

Dart_Handle *dart_args = nullptr;

gde->execute_on_dart_thread([&] {
DartBlockScope scope;

Expand All @@ -317,7 +320,6 @@ void DartScriptInstance::call(const GDStringName *p_method, const GDExtensionCon
intptr_t arg_count = 0;
Dart_ListLength(args_list, &arg_count);

Dart_Handle *dart_args = nullptr;
if (arg_count != 0) {
dart_args = new Dart_Handle[arg_count];
Dart_Handle args_address = Dart_NewInteger(reinterpret_cast<intptr_t>(p_args));
Expand Down Expand Up @@ -367,13 +369,13 @@ void DartScriptInstance::call(const GDStringName *p_method, const GDExtensionCon
gde_variant_new_copy(r_return, reinterpret_cast<GDExtensionConstVariantPtr>(variantDataPtr));
}
}

// TODO - these leak on error
if (dart_args != nullptr) {
delete[] dart_args;
}
});
// TODO

if (dart_args != nullptr) {
delete[] dart_args;
}

// TODO: How do we throw exceptions in Godot?
r_error->error = GDEXTENSION_CALL_OK;
}

Expand Down
81 changes: 0 additions & 81 deletions src/cpp/dart_vtable_wrapper.cpp

This file was deleted.

10 changes: 0 additions & 10 deletions src/cpp/dart_vtable_wrapper.h

This file was deleted.

11 changes: 0 additions & 11 deletions src/cpp/godot_dart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,4 @@ void GDE_EXPORT godot_dart_init(GDExtensionInterfaceGetProcAddress p_get_proc_ad
r_initialization->minimum_initialization_level = GDEXTENSION_INITIALIZATION_SCENE;
}

//GDExtensionBool GDE_EXPORT godot_dart_init(const GDExtensionInterface *p_interface,
// GDExtensionClassLibraryPtr p_library,
// GDExtensionInitialization *r_initialization) {
// GDEWrapper::create_instance(p_interface, p_library);
//
// r_initialization->initialize = initialize_level;
// r_initialization->deinitialize = deinitialize_level;
// r_initialization->minimum_initialization_level = GDEXTENSION_INITIALIZATION_SCENE;
//
// return true;
//}
}
2 changes: 0 additions & 2 deletions src/cpp/godot_dart.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
<ItemGroup>
<ClCompile Include="dart_bindings.cpp" />
<ClCompile Include="dart_script_instance.cpp" />
<ClCompile Include="dart_vtable_wrapper.cpp" />
<ClCompile Include="gde_c_interface.cpp" />
<ClCompile Include="gde_dart_converters.cpp" />
<ClCompile Include="godot_dart.cpp" />
Expand All @@ -31,7 +30,6 @@
<ItemGroup>
<ClInclude Include="dart_bindings.h" />
<ClInclude Include="dart_script_instance.h" />
<ClInclude Include="dart_vtable_wrapper.h" />
<ClInclude Include="gde_c_interface.h" />
<ClInclude Include="gde_dart_converters.h" />
<ClInclude Include="gde_wrapper.h" />
Expand Down
2 changes: 0 additions & 2 deletions src/cpp/godot_dart.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<ClCompile Include="godot_dart.cpp" />
<ClCompile Include="dart_bindings.cpp" />
<ClCompile Include="gde_wrapper..cpp" />
<ClCompile Include="dart_vtable_wrapper.cpp" />
<ClCompile Include="godot_string_wrappers.cpp" />
<ClCompile Include="dart_script_instance.cpp" />
<ClCompile Include="gde_dart_converters.cpp" />
Expand All @@ -13,7 +12,6 @@
<ItemGroup>
<ClInclude Include="dart_bindings.h" />
<ClInclude Include="gde_wrapper.h" />
<ClInclude Include="dart_vtable_wrapper.h" />
<ClInclude Include="godot_string_wrappers.h" />
<ClInclude Include="dart_script_instance.h" />
<ClInclude Include="gde_dart_converters.h" />
Expand Down
4 changes: 2 additions & 2 deletions src/dart/godot_dart_build/.dart_tool/package_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@
"languageVersion": "2.18"
}
],
"generated": "2023-07-22T01:31:46.664742Z",
"generated": "2023-08-16T01:22:04.221907Z",
"generator": "pub",
"generatorVersion": "3.0.3"
"generatorVersion": "3.0.6"
}
1 change: 1 addition & 0 deletions src/dart/godot_dart_build/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: godot_dart_build
description: build_runner interface for simplifying binding to Godot
version: 1.0.0
publish_to: none

environment:
sdk: '>=2.18.2 <3.0.0'
Expand Down
Loading

0 comments on commit 845db37

Please sign in to comment.