diff --git a/source/gui/scripting/JSInterface_GUITypes.cpp b/source/gui/scripting/JSInterface_GUITypes.cpp index 3cdac32268..16253fbf77 100644 --- a/source/gui/scripting/JSInterface_GUITypes.cpp +++ b/source/gui/scripting/JSInterface_GUITypes.cpp @@ -94,8 +94,8 @@ CStr ToPercentString(double pix, double per) bool JSI_GUISize::toString(JSContext* cx, uint argc, JS::Value* vp) { - UNUSED2(argc); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); + // JSAutoRequest not needed for the calls below + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); CStr buffer; try @@ -103,8 +103,8 @@ bool JSI_GUISize::toString(JSContext* cx, uint argc, JS::Value* vp) ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; double val, valr; #define SIDE(side) \ - pScriptInterface->GetProperty(rec.thisv(), #side, val); \ - pScriptInterface->GetProperty(rec.thisv(), "r"#side, valr); \ + pScriptInterface->GetProperty(args.thisv(), #side, val); \ + pScriptInterface->GetProperty(args.thisv(), "r"#side, valr); \ buffer += ToPercentString(val, valr); SIDE(left); @@ -118,10 +118,10 @@ bool JSI_GUISize::toString(JSContext* cx, uint argc, JS::Value* vp) } catch (PSERROR_Scripting_ConversionFailed&) { - ScriptInterface::ToJSVal(cx, rec.rval(), std::string("")); + ScriptInterface::ToJSVal(cx, args.rval(), std::string("")); return true; } - ScriptInterface::ToJSVal(cx, rec.rval(), buffer); + ScriptInterface::ToJSVal(cx, args.rval(), buffer); return true; } diff --git a/source/gui/scripting/JSInterface_IGUIObject.cpp b/source/gui/scripting/JSInterface_IGUIObject.cpp index ae1a36985a..3e498db868 100644 --- a/source/gui/scripting/JSInterface_IGUIObject.cpp +++ b/source/gui/scripting/JSInterface_IGUIObject.cpp @@ -52,7 +52,7 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Handle JSAutoRequest rq(cx); ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); + IGUIObject* e = ScriptInterface::GetPrivate(cx, obj, &JSI_IGUIObject::JSI_class); if (!e) return false; @@ -126,7 +126,7 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Handle bool JSI_IGUIObject::setProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp, JS::ObjectOpResult& result) { - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); + IGUIObject* e = ScriptInterface::GetPrivate(cx, obj, &JSI_IGUIObject::JSI_class); if (!e) return result.fail(JSMSG_NOT_NONNULL_OBJECT); @@ -179,63 +179,50 @@ void JSI_IGUIObject::init(ScriptInterface& scriptInterface) scriptInterface.DefineCustomObjectType(&JSI_class, nullptr, 1, nullptr, JSI_methods, nullptr, nullptr); } -bool JSI_IGUIObject::toString(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool JSI_IGUIObject::toString(JSContext* cx, uint argc, JS::Value* vp) { - JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); - - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); - - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); + // No JSAutoRequest needed for these calls + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + IGUIObject* e = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); if (!e) return false; - ScriptInterface::ToJSVal(cx, rec.rval(), "[GUIObject: " + e->GetName() + "]"); + ScriptInterface::ToJSVal(cx, args.rval(), "[GUIObject: " + e->GetName() + "]"); return true; } -bool JSI_IGUIObject::focus(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool JSI_IGUIObject::focus(JSContext* cx, uint argc, JS::Value* vp) { - JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); - - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); - - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); + // No JSAutoRequest needed for these calls + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + IGUIObject* e = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); if (!e) return false; e->GetGUI()->SetFocusedObject(e); - - rec.rval().setUndefined(); + args.rval().setUndefined(); return true; } -bool JSI_IGUIObject::blur(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool JSI_IGUIObject::blur(JSContext* cx, uint argc, JS::Value* vp) { - JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); - - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); - - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); + // No JSAutoRequest needed for these calls + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + IGUIObject* e = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); if (!e) return false; e->GetGUI()->SetFocusedObject(NULL); - - rec.rval().setUndefined(); + args.rval().setUndefined(); return true; } -bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint argc, JS::Value* vp) { JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); - - IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, NULL); + IGUIObject* e = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); if (!e) return false; @@ -258,6 +245,6 @@ bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint UNUSED(argc), JS::Value return false; } - rec.rval().set(objVal); + args.rval().set(objVal); return true; } diff --git a/source/gui/scripting/JSInterface_IGUITextOwner.cpp b/source/gui/scripting/JSInterface_IGUITextOwner.cpp index 1020791e18..2ad2b5d61c 100644 --- a/source/gui/scripting/JSInterface_IGUITextOwner.cpp +++ b/source/gui/scripting/JSInterface_IGUITextOwner.cpp @@ -33,27 +33,23 @@ void JSI_IGUITextOwner::RegisterScriptFunctions(JSContext* cx, JS::HandleObject JS_DefineFunctions(cx, obj, JSI_methods); } -bool JSI_IGUITextOwner::GetTextSize(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool JSI_IGUITextOwner::GetTextSize(JSContext* cx, uint argc, JS::Value* vp) { - JSAutoRequest rq(cx); - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); - JS::RootedObject thisObj(cx, &rec.thisv().toObject()); - - IGUIObject* obj = static_cast(JS_GetInstancePrivate(cx, thisObj, &JSI_IGUIObject::JSI_class, nullptr)); + // No JSAutoRequest needed for these calls + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + IGUIObject* obj = ScriptInterface::GetPrivate(cx, args, &JSI_IGUIObject::JSI_class); if (!obj) - { - JS_ReportError(cx, "This is not an IGUIObject!"); return false; - } // Avoid dynamic_cast for performance reasons IGUITextOwner* objText = static_cast(obj->GetTextOwner()); if (!objText) { + JSAutoRequest rq(cx); JS_ReportError(cx, "This IGUIObject is not an IGUITextOwner!"); return false; } - ScriptInterface::ToJSVal(cx, rec.rval(), objText->CalculateTextSize()); + ScriptInterface::ToJSVal(cx, args.rval(), objText->CalculateTextSize()); return true; } diff --git a/source/scriptinterface/NativeWrapperDefns.h b/source/scriptinterface/NativeWrapperDefns.h index db93eb0958..17b62c7c6b 100644 --- a/source/scriptinterface/NativeWrapperDefns.h +++ b/source/scriptinterface/NativeWrapperDefns.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -132,9 +132,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) { \ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \ JSAutoRequest rq(cx); \ - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); \ - if (ScriptInterface::GetClass(thisObj) != CLS) return false; \ - TC* c = static_cast(ScriptInterface::GetPrivate(thisObj)); \ + TC* c = ScriptInterface::GetPrivate(cx, args, CLS); \ if (! c) return false; \ BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ JS::RootedValue rval(cx); \ @@ -152,9 +150,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~) { \ JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \ JSAutoRequest rq(cx); \ - JS::RootedObject thisObj(cx, JS_THIS_OBJECT(cx, vp)); \ - if (ScriptInterface::GetClass(thisObj) != CLS) return false; \ - TC* c = static_cast(ScriptInterface::GetPrivate(thisObj)); \ + TC* c = ScriptInterface::GetPrivate(cx, args, CLS); \ if (! c) return false; \ BOOST_PP_REPEAT_##z (i, CONVERT_ARG, ~) \ JS::RootedValue rval(cx); \ diff --git a/source/scriptinterface/ScriptInterface.cpp b/source/scriptinterface/ScriptInterface.cpp index 1e765fa64b..9d96ff37a7 100644 --- a/source/scriptinterface/ScriptInterface.cpp +++ b/source/scriptinterface/ScriptInterface.cpp @@ -252,15 +252,15 @@ bool ProfileStart(JSContext* cx, uint argc, JS::Value* vp) return true; } -bool ProfileStop(JSContext* UNUSED(cx), uint UNUSED(argc), JS::Value* vp) +bool ProfileStop(JSContext* UNUSED(cx), uint argc, JS::Value* vp) { - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); if (CProfileManager::IsInitialised() && ThreadUtil::IsMainThread()) g_Profiler.Stop(); g_Profiler2.RecordRegionLeave(); - rec.rval().setUndefined(); + args.rval().setUndefined(); return true; } @@ -308,14 +308,14 @@ static double generate_uniform_real(boost::rand48& rng, double min, double max) } } -bool Math_random(JSContext* cx, uint UNUSED(argc), JS::Value* vp) +bool Math_random(JSContext* cx, uint argc, JS::Value* vp) { - JS::CallReceiver rec = JS::CallReceiverFromVp(vp); + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); double r; if (!ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->MathRandom(r)) return false; - rec.rval().setNumber(r); + args.rval().setNumber(r); return true; } @@ -1104,17 +1104,6 @@ bool ScriptInterface::IsExceptionPending(JSContext* cx) return JS_IsExceptionPending(cx) ? true : false; } -const JSClass* ScriptInterface::GetClass(JS::HandleObject obj) -{ - return JS_GetClass(obj); -} - -void* ScriptInterface::GetPrivate(JS::HandleObject obj) -{ - // TODO: use JS_GetInstancePrivate - return JS_GetPrivate(obj); -} - JS::Value ScriptInterface::CloneValueFromOtherContext(const ScriptInterface& otherContext, JS::HandleValue val) const { PROFILE("CloneValueFromOtherContext"); diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index cfa610c9e3..b37d43da24 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -336,6 +336,39 @@ public: shared_ptr WriteStructuredClone(JS::HandleValue v) const; void ReadStructuredClone(const shared_ptr& ptr, JS::MutableHandleValue ret) const; + /** + * Retrieve the private data field of a JSObject that is an instance of the given JSClass. + */ + template + static T* GetPrivate(JSContext* cx, JS::HandleObject thisobj, JSClass* jsClass) + { + JSAutoRequest rq(cx); + T* value = static_cast(JS_GetInstancePrivate(cx, thisobj, jsClass, nullptr)); + if (value == nullptr && !JS_IsExceptionPending(cx)) + JS_ReportError(cx, "Private data of the given object is null!"); + return value; + } + + /** + * Retrieve the private data field of a JS Object that is an instance of the given JSClass. + * If an error occurs, GetPrivate will report it with the according stack. + */ + template + static T* GetPrivate(JSContext* cx, JS::CallArgs& callArgs, JSClass* jsClass) + { + JSAutoRequest rq(cx); + if (!callArgs.thisv().isObject()) + { + JS_ReportError(cx, "Cannot retrieve private JS class data because from a non-object value!"); + return nullptr; + } + JS::RootedObject thisObj(cx, &callArgs.thisv().toObject()); + T* value = static_cast(JS_GetInstancePrivate(cx, thisObj, jsClass, &callArgs)); + if (value == nullptr && !JS_IsExceptionPending(cx)) + JS_ReportError(cx, "Private data of the given object is null!"); + return value; + } + /** * Converts |a| if needed and assigns it to |handle|. * This is meant for use in other templates where we want to use the same code for JS::RootedValue&/JS::HandleValue and @@ -380,8 +413,6 @@ private: bool GetProperty_(JS::HandleValue obj, const char* name, JS::MutableHandleValue out) const; bool GetPropertyInt_(JS::HandleValue obj, int name, JS::MutableHandleValue value) const; static bool IsExceptionPending(JSContext* cx); - static const JSClass* GetClass(JS::HandleObject obj); - static void* GetPrivate(JS::HandleObject obj); struct CustomType {