From 31f9ca9ebfe791dabd8a9cac8122e50dd565f641 Mon Sep 17 00:00:00 2001 From: Yves Date: Sun, 20 Jul 2014 15:08:28 +0000 Subject: [PATCH] Implements CallFunction with JS::MutableHandle return type. Changes the CallFunction implementation to use macros because otherwise we'd have to write twice as many functions manually. Adapts GetSavedGameData to use the new function template. Additional callers will be changed in future commits. Refs #2415 Refs #2462 This was SVN commit r15541. --- source/gui/GUIManager.cpp | 9 +- source/scriptinterface/NativeWrapperDecls.h | 20 +++- source/scriptinterface/NativeWrapperDefns.h | 44 +++++++- source/scriptinterface/ScriptInterface.h | 113 -------------------- 4 files changed, 68 insertions(+), 118 deletions(-) diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp index 4e22da8b6c..06bbe85231 100644 --- a/source/gui/GUIManager.cpp +++ b/source/gui/GUIManager.cpp @@ -261,11 +261,14 @@ Status CGUIManager::ReloadChangedFile(const VfsPath& path) CScriptVal CGUIManager::GetSavedGameData(ScriptInterface*& pPageScriptInterface) { - CScriptVal data; - if (!top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "getSavedGameData", data)) + JSContext* cx = top()->GetScriptInterface()->GetContext(); + JSAutoRequest rq(cx); + + JS::RootedValue data(cx); + if (!top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "getSavedGameData", &data)) LOGERROR(L"Failed to call getSavedGameData() on the current GUI page"); pPageScriptInterface = GetScriptInterface().get(); - return data; + return CScriptVal(data); } std::string CGUIManager::GetSavedGameData() diff --git a/source/scriptinterface/NativeWrapperDecls.h b/source/scriptinterface/NativeWrapperDecls.h index a14c0afc33..54ea534d09 100644 --- a/source/scriptinterface/NativeWrapperDecls.h +++ b/source/scriptinterface/NativeWrapperDecls.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,6 +26,7 @@ #define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i // Some other things #define TYPED_ARGS(z, i, data) , T##i a##i +#define TYPED_ARGS_CONST_REF(z, i, data) const T##i& a##i, #define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal(cx, i < args.length() ? args.handleAt(i) : JS::UndefinedHandleValue, a##i)) return false; // List-generating macros, named roughly after their first list item @@ -35,6 +36,7 @@ #define T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, T) // "T0, T1, " #define T0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, T) // ", T0, T1" #define T0_A0(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS, ~) // "T0 a0, T1 a1" +#define T0_A0_CONST_REF(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS_CONST_REF, ~) // " const T0 a0, const T1 a1, " #define A0(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED, a) // "a0, a1" #define A0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, a) // ", a0, a1" @@ -68,3 +70,19 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) static size_t nargs() { return i; } BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS + +// Call the named property on the given object +#define OVERLOADS(z, i, data) \ + template \ + bool CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) R& ret); +BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) +#undef OVERLOADS + +// The trick is using JS::Rooted* and converting that to a JS::MutableHandle explicitly in the function body. +// Normally the function would take JS::MutableHandle and that conversion would happen implicitly. However, implicit +// conversion does not work with template argument deduction (only exact type matches allowed). +#define OVERLOADS(z, i, data) \ + template \ + bool CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted* ret); +BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) +#undef OVERLOADS diff --git a/source/scriptinterface/NativeWrapperDefns.h b/source/scriptinterface/NativeWrapperDefns.h index dc0aa37ebb..d84bd93ee3 100644 --- a/source/scriptinterface/NativeWrapperDefns.h +++ b/source/scriptinterface/NativeWrapperDefns.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2014 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -123,11 +123,52 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef OVERLOADS +#define TO_JS_VAL(z, i, data) ToJSVal(cx, argv.handleAt(i), a##i); + +#define OVERLOADS(z, i, data) \ +template \ +bool ScriptInterface::CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) R& ret) \ +{ \ + JSContext* cx = GetContext(); \ + JSAutoRequest rq(cx); \ + JS::RootedValue jsRet(cx); \ + JS::RootedValue val1(cx, val); \ + JS::AutoValueVector argv(cx); \ + argv.resize(i); \ + BOOST_PP_REPEAT_##z (i, TO_JS_VAL, ~) \ + bool ok = CallFunction_(val1, name, argv.length(), argv.begin(), &jsRet); \ + if (!ok) \ + return false; \ + return FromJSVal(cx, jsRet, ret); \ +} +BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) +#undef OVERLOADS + +#define OVERLOADS(z, i, data) \ +template \ +bool ScriptInterface::CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted* ret) \ +{ \ + JSContext* cx = GetContext(); \ + JSAutoRequest rq(cx); \ + JS::MutableHandle jsRet(ret); \ + JS::RootedValue val1(cx, val); \ + JS::AutoValueVector argv(cx); \ + argv.resize(i); \ + BOOST_PP_REPEAT_##z (i, TO_JS_VAL, ~) \ + bool ok = CallFunction_(val1, name, argv.length(), argv.begin(), jsRet); \ + if (!ok) \ + return false; \ + return true; \ +} +BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) +#undef OVERLOADS + // Clean up our mess #undef SCRIPT_PROFILE #undef NUMBERED_LIST_HEAD #undef NUMBERED_LIST_TAIL #undef NUMBERED_LIST_BALANCED +#undef TYPED_ARGS_CONST_REF #undef TYPED_ARGS #undef CONVERT_ARG #undef TYPENAME_T0_HEAD @@ -135,6 +176,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) #undef T0 #undef T0_HEAD #undef T0_TAIL +#undef T0_A0_CONST_REF #undef T0_A0 #undef A0 #undef A0_TAIL diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index b18e890c77..ff64d2f1d6 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -170,36 +170,6 @@ public: template bool CallFunctionVoid(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2); - /** - * Call the named property on the given object, with return type R and 0 arguments - */ - template - bool CallFunction(jsval val, const char* name, R& ret); - - /** - * Call the named property on the given object, with return type R and 1 argument - */ - template - bool CallFunction(jsval val, const char* name, const T0& a0, R& ret); - - /** - * Call the named property on the given object, with return type R and 2 arguments - */ - template - bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, R& ret); - - /** - * Call the named property on the given object, with return type R and 3 arguments - */ - template - bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, R& ret); - - /** - * Call the named property on the given object, with return type R and 4 arguments - */ - template - bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, const T3& a3, R& ret); - JSObject* CreateCustomObject(const std::string & typeName); void DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs); @@ -444,19 +414,6 @@ public: // Implement those declared functions #include "NativeWrapperDefns.h" -template -bool ScriptInterface::CallFunction(jsval val, const char* name, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - bool ok = CallFunction_(val1, name, 0, NULL, &jsRet); - if (!ok) - return false; - return FromJSVal(GetContext(), jsRet, ret); -} - template bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0) { @@ -499,76 +456,6 @@ bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0 return CallFunction_(val1, name, 3, argv.begin(), &jsRet); } -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - JS::AutoValueVector argv(cx); - argv.resize(1); - ToJSVal(cx, argv.handleAt(0), a0); - bool ok = CallFunction_(val1, name, 1, argv.begin(), &jsRet); - if (!ok) - return false; - return FromJSVal(cx, jsRet, ret); -} - -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - JS::AutoValueVector argv(cx); - argv.resize(2); - ToJSVal(cx, argv.handleAt(0), a0); - ToJSVal(cx, argv.handleAt(1), a1); - bool ok = CallFunction_(val1, name, 2, argv.begin(), &jsRet); - if (!ok) - return false; - return FromJSVal(cx, jsRet, ret); -} - -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - JS::AutoValueVector argv(cx); - argv.resize(3); - ToJSVal(cx, argv.handleAt(0), a0); - ToJSVal(cx, argv.handleAt(1), a1); - ToJSVal(cx, argv.handleAt(2), a2); - bool ok = CallFunction_(val1, name, 3, argv.begin(), &jsRet); - if (!ok) - return false; - return FromJSVal(cx, jsRet, ret); -} - -template -bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, const T3& a3, R& ret) -{ - JSContext* cx = GetContext(); - JSAutoRequest rq(cx); - JS::RootedValue jsRet(cx); - JS::RootedValue val1(cx, val); - JS::AutoValueVector argv(cx); - argv.resize(4); - ToJSVal(cx, argv.handleAt(0), a0); - ToJSVal(cx, argv.handleAt(1), a1); - ToJSVal(cx, argv.handleAt(2), a2); - ToJSVal(cx, argv.handleAt(3), a3); - bool ok = CallFunction_(val1, name, 4, argv.begin(), &jsRet); - if (!ok) - return false; - return FromJSVal(cx, jsRet, ret); -} - template bool ScriptInterface::SetGlobal(const char* name, const T& value, bool replace) {