Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/dukglue/detail_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ namespace dukglue

duk_pop_2(ctx);

static_assert(sizeof(RetType(*)(Ts...)) == sizeof(void*), "Function pointer and data pointer are different sizes");
static_assert(sizeof(RetType(*)(Ts...)) == sizeof(void*), "Function pointer and data pointer are different sizes");
RetType(*funcToCall)(Ts...) = reinterpret_cast<RetType(*)(Ts...)>(fp_void);

actually_call(ctx, funcToCall, dukglue::detail::get_stack_values<Ts...>(ctx));
Expand Down
83 changes: 77 additions & 6 deletions include/dukglue/detail_method.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ namespace dukglue
{
static duk_ret_t finalize_method(duk_context* ctx)
{
// clean up the MethodHolder reference
duk_get_prop_string(ctx, 0, "\xFF" "method_holder");
// clean up the MethodHolder reference
duk_get_prop_string(ctx, 0, "\xFF" "method_holder");

void* method_holder_void = duk_require_pointer(ctx, -1);
MethodHolder* method_holder = static_cast<MethodHolder*>(method_holder_void);
delete method_holder;
void* method_holder_void = duk_require_pointer(ctx, -1);
MethodHolder* method_holder = static_cast<MethodHolder*>(method_holder_void);
delete method_holder;

return 0;
return 0;
}

static duk_ret_t call_native_method(duk_context* ctx)
Expand Down Expand Up @@ -135,6 +135,77 @@ namespace dukglue
dukglue::detail::apply_method(method, obj, args);
}
};

struct InterceptedMethodRuntime
{
static duk_ret_t finalize_method(duk_context* ctx)
{
// clean up the MethodHolder reference
//duk_get_prop_string(ctx, 0, "\xFF" "method_holder");

//void* method_holder_void = duk_require_pointer(ctx, -1);
//MethodHolder* method_holder = static_cast<MethodHolder*>(method_holder_void);
//delete method_holder;

return 0;
}

static duk_ret_t call_native_method(duk_context* ctx)
{
// get this.obj_ptr
duk_push_this(ctx);
duk_get_prop_string(ctx, -1, "\xFF" "obj_ptr");
void* obj_void = duk_get_pointer(ctx, -1);
if (obj_void == nullptr) {
duk_error(ctx, DUK_RET_REFERENCE_ERROR, "Invalid native object for 'this'");
return DUK_RET_REFERENCE_ERROR;
}

duk_pop_2(ctx); // pop this.obj_ptr and this

// get current_function.method_info
duk_push_current_function(ctx);
duk_get_prop_string(ctx, -1, "\xFF" "func_ptr");
void* fp_void = duk_require_pointer(ctx, -1);
if (fp_void == nullptr) {
duk_error(ctx, DUK_RET_TYPE_ERROR, "Function pointer missing?!");
return DUK_RET_TYPE_ERROR;
}

duk_pop_2(ctx);

// (should always be valid unless someone is intentionally messing with this.obj_ptr...)
Cls* obj = static_cast<Cls*>(obj_void);

static_assert(sizeof(RetType(*)(Cls* obj, duk_context* ctx, Ts...)) == sizeof(void*), "Function pointer and data pointer are different sizes");
RetType(*funcToCall)(Cls* obj, duk_context* ctx, Ts...) = reinterpret_cast<RetType(*)(Cls* obj, duk_context* ctx, Ts...)>(fp_void);

// read arguments and call method
auto bakedArgs = dukglue::detail::get_stack_values<Ts...>(ctx);
actually_call(ctx, obj, funcToCall, bakedArgs);
return std::is_void<RetType>::value ? 0 : 1;
}

// this mess is to support functions with void return values
template<typename Dummy = RetType, typename... BakedTs>
static typename std::enable_if<!std::is_void<Dummy>::value>::type actually_call(duk_context* ctx, Cls* obj, RetType(*funcToCall)(Cls* obj, duk_context* ctx, Ts...), const std::tuple<BakedTs...>& args)
{
// ArgStorage has some static_asserts in it that validate value types,
// so we typedef it to force ArgStorage<RetType> to compile and run the asserts
typedef typename dukglue::types::ArgStorage<RetType>::type ValidateReturnType;

RetType return_val = dukglue::detail::apply_fp_intercepted(obj, ctx, funcToCall, args);

using namespace dukglue::types;
DukType<typename Bare<RetType>::type>::template push<RetType>(ctx, std::move(return_val));
}

template<typename Dummy = RetType, typename... BakedTs>
static typename std::enable_if<std::is_void<Dummy>::value>::type actually_call(duk_context* ctx, Cls* obj, RetType(*funcToCall)(Cls* obj, duk_context* ctx, Ts...), const std::tuple<BakedTs...>& args)
{
dukglue::detail::apply_fp_intercepted(obj, ctx, funcToCall, args);
}
};
};

template <bool isConst, typename Cls>
Expand Down
15 changes: 14 additions & 1 deletion include/dukglue/detail_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,25 @@ namespace dukglue
return pf(std::forward<Args>(std::get<Indexes>(tup))...);
}

// function pointer
template<class Cls, class Ret, class... Args, class... BakedArgs, size_t... Indexes >
Ret apply_fp_helper_intercepted(Cls* obj, duk_context* ctx, Ret(*pf)(Cls* obj, duk_context* ctx, Args...), index_tuple< Indexes... >, std::tuple<BakedArgs...>&& tup)
{
return pf(obj, ctx, std::forward<Args>(std::get<Indexes>(tup))...);
}

template<class Ret, class ... Args, class ... BakedArgs>
Ret apply_fp(Ret(*pf)(Args...), const std::tuple<BakedArgs...>& tup)
{
return apply_fp_helper(pf, typename make_indexes<BakedArgs...>::type(), std::tuple<BakedArgs...>(tup));
}

template<class Cls, class Ret, class ... Args, class ... BakedArgs>
Ret apply_fp_intercepted(Cls* obj, duk_context* ctx, Ret(*pf)(Cls* obj, duk_context* ctx, Args...), const std::tuple<BakedArgs...>& tup)
{
return apply_fp_helper_intercepted(obj, ctx, pf, typename make_indexes<BakedArgs...>::type(), std::tuple<BakedArgs...>(tup));
}

// method pointer
template<class Cls, class Ret, class... Args, class... BakedArgs, size_t... Indexes >
Ret apply_method_helper(Ret(Cls::*pf)(Args...), index_tuple< Indexes... >, Cls* obj, std::tuple<BakedArgs...>&& tup)
Expand Down Expand Up @@ -119,4 +132,4 @@ namespace dukglue


}
}
}
27 changes: 26 additions & 1 deletion include/dukglue/register_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,31 @@ void dukglue_register_method(duk_context* ctx, RetType(Cls::*method)(Ts...), con
dukglue_register_method<false, Cls, RetType, Ts...>(ctx, method, name);
}


template<class Cls, typename RetType, typename... Ts>
void dukglue_register_intercepted_method(duk_context* ctx, const char* name, RetType(*funcToCall)(Cls*, duk_context*ctx, Ts...))
{
using namespace dukglue::detail;
typedef MethodInfo<false, Cls, RetType, Ts...> MethodInfo;

duk_c_function method_func = MethodInfo::InterceptedMethodRuntime::call_native_method;

ProtoManager::push_prototype<Cls>(ctx);

duk_push_c_function(ctx, method_func, sizeof...(Ts));

duk_push_pointer(ctx, reinterpret_cast<void*>(funcToCall));
duk_put_prop_string(ctx, -2, "\xFF" "func_ptr"); // consumes raw method pointer

// make sure we free the method_holder when this function is removed
duk_push_c_function(ctx, MethodInfo::InterceptedMethodRuntime::finalize_method, 1);
duk_set_finalizer(ctx, -2);

duk_put_prop_string(ctx, -2, name); // consumes method function

duk_pop(ctx); // pop prototype
}

template<class Cls, typename RetType, typename... Ts>
void dukglue_register_method(duk_context* ctx, RetType(Cls::*method)(Ts...) const, const char* name)
{
Expand Down Expand Up @@ -199,4 +224,4 @@ void dukglue_register_delete(duk_context* ctx)
duk_push_c_function(ctx, delete_func, 0);
duk_put_prop_string(ctx, -2, "delete");
duk_pop(ctx); // pop prototype
}
}
2 changes: 1 addition & 1 deletion include/dukglue/register_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void dukglue_register_function(duk_context* ctx, RetType(*funcToCall)(Ts...), co

duk_push_c_function(ctx, evalFunc, sizeof...(Ts));

static_assert(sizeof(RetType(*)(Ts...)) == sizeof(void*), "Function pointer and data pointer are different sizes");
static_assert(sizeof(RetType(*)(Ts...)) == sizeof(void*), "Function pointer and data pointer are different sizes");
duk_push_pointer(ctx, reinterpret_cast<void*>(funcToCall));
duk_put_prop_string(ctx, -2, "\xFF" "func_ptr");

Expand Down