Index: source/gui/CGUI.h =================================================================== --- source/gui/CGUI.h +++ source/gui/CGUI.h @@ -611,6 +611,8 @@ * It would be simpler to recreate the functions on every JS call, but that is slower * (this may or may not matter now and in the future). * Another alternative would be to store them on each proxied object, but that wastes memory. + * Note that proxied objects store a pointer to the map objects directly, + * so usage of std::unordered_map, which won't invalidate references, is required. */ std::unordered_map m_ProxyData; Index: source/gui/ObjectBases/IGUIObject.cpp =================================================================== --- source/gui/ObjectBases/IGUIObject.cpp +++ source/gui/ObjectBases/IGUIObject.cpp @@ -456,9 +456,11 @@ js::ProxyOptions options; options.setClass(&JSI_GUIProxy::ClassDefinition()); - JS::RootedValue cppObj(rq.cx); + JS::RootedValue cppObj(rq.cx), data(rq.cx); + cppObj.get().setPrivate(this); + data.get().setPrivate(&GetGUI().GetProxyData("iguiobject")); m_JSObject.init(rq.cx, js::NewProxyObject(rq.cx, &JSI_GUIProxy::Singleton(), cppObj, nullptr, options)); - JS_SetPrivate(m_JSObject.get(), this); + js::SetProxyReservedSlot(m_JSObject, 0, data); } JSObject* IGUIObject::GetJSObject() Index: source/gui/ObjectTypes/CText.cpp =================================================================== --- source/gui/ObjectTypes/CText.cpp +++ source/gui/ObjectTypes/CText.cpp @@ -261,9 +261,11 @@ js::ProxyOptions options; options.setClass(&JSI_GUIProxy::ClassDefinition()); - JS::RootedValue cppObj(rq.cx); + JS::RootedValue cppObj(rq.cx), data(rq.cx); + cppObj.get().setPrivate(this); + data.get().setPrivate(&GetGUI().GetProxyData("text")); m_JSObject.init(rq.cx, js::NewProxyObject(rq.cx, &JSI_GUIProxy::Singleton(), cppObj, nullptr, options)); - JS_SetPrivate(m_JSObject.get(), this); + js::SetProxyReservedSlot(m_JSObject, 0, data); } void CText::getTextSize(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) Index: source/gui/Scripting/JSInterface_CText.cpp =================================================================== --- source/gui/Scripting/JSInterface_CText.cpp +++ source/gui/Scripting/JSInterface_CText.cpp @@ -44,9 +44,10 @@ } template <> -bool JSI_GUIProxy::funcGetter(CText* elem, const std::string& propName, JS::MutableHandleValue vp) const +bool JSI_GUIProxy::funcGetter(JS::HandleObject proxy, const std::string& propName, JS::MutableHandleValue vp) const { - const SData& data = *static_cast(elem->GetGUI().GetProxyData(this)); + const SData& data = *static_cast(js::GetProxyPrivate(proxy).toPrivate()); + js::GetProxyReservedSlot(proxy, 0). if (propName == "toString") return vp.setObjectOrNull(data.m_ToString), true; if (propName == "focus") Index: source/gui/Scripting/JSInterface_GUIProxy.h =================================================================== --- source/gui/Scripting/JSInterface_GUIProxy.h +++ source/gui/Scripting/JSInterface_GUIProxy.h @@ -55,7 +55,7 @@ // This handles returning function properties. // Specialize this. - bool funcGetter(GUIObjectType* elem, const std::string& propName, JS::MutableHandleValue vp) const; + bool funcGetter(JS::HandleObject proxy, const std::string& propName, JS::MutableHandleValue vp) const; protected: // BaseProxyHandler interface below @@ -88,9 +88,9 @@ return true; } // Return nothing. - virtual bool enumerate(JSContext* UNUSED(cx), JS::HandleObject UNUSED(proxy), JS::MutableHandleObject UNUSED(objp)) const override + virtual JSObject* enumerate(JSContext* UNUSED(cx), JS::HandleObject UNUSED(proxy)) const override { - return true; + return nullptr; } // Throw an exception is JS attempts to query the prototype. virtual bool getPrototypeIfOrdinary(JSContext* UNUSED(cx), JS::HandleObject UNUSED(proxy), bool* UNUSED(isOrdinary), JS::MutableHandleObject UNUSED(protop)) const override Index: source/gui/Scripting/JSInterface_GUIProxy_impl.h =================================================================== --- source/gui/Scripting/JSInterface_GUIProxy_impl.h +++ source/gui/Scripting/JSInterface_GUIProxy_impl.h @@ -20,7 +20,7 @@ template js::Class& JSI_GUIProxy::ClassDefinition() { - static js::Class c = PROXY_CLASS_DEF("GUIObjectProxy", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy)); + static js::Class c = PROXY_CLASS_DEF("GUIObjectProxy", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy) | JSCLASS_HAS_RESERVED_SLOTS(1)); return c; } @@ -37,7 +37,7 @@ inline bool apply_to(JSContext* cx, uint argc, JS::Value* vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - OG* e = static_cast(JS_GetPrivate(args.thisv().toObjectOrNull())); + OG* e = static_cast(js::GetProxyPrivate(args.thisv().toObjectOrNull()).toPrivate()); if (!e) return false; @@ -53,7 +53,7 @@ ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; ScriptRequest rq(*pScriptInterface); - T* e = static_cast(JS_GetPrivate(proxy.get())); + T* e = static_cast(js::GetProxyPrivate(proxy).toPrivate()); if (!e) return false; @@ -66,7 +66,7 @@ return false; // Return function properties. Specializable. - if (funcGetter(e, propName, vp)) + if (funcGetter(proxy, propName, vp)) return true; // Use onWhatever to access event handlers @@ -121,7 +121,7 @@ bool JSI_GUIProxy::set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue vp, JS::HandleValue UNUSED(receiver), JS::ObjectOpResult& result) const { - T* e = static_cast(JS_GetPrivate(proxy.get())); + T* e = static_cast(js::GetProxyPrivate(proxy).toPrivate()); if (!e) return result.fail(JSMSG_NOT_NONNULL_OBJECT); @@ -173,7 +173,7 @@ template bool JSI_GUIProxy::delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::ObjectOpResult& result) const { - T* e = static_cast(JS_GetPrivate(proxy.get())); + T* e = static_cast(js::GetProxyPrivate(proxy).toPrivate()); if (!e) return result.fail(JSMSG_NOT_NONNULL_OBJECT); Index: source/gui/Scripting/JSInterface_GUISize.cpp =================================================================== --- source/gui/Scripting/JSInterface_GUISize.cpp +++ source/gui/Scripting/JSInterface_GUISize.cpp @@ -30,7 +30,7 @@ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, JSI_GUISize::construct, nullptr + nullptr, JSI_GUISize::construct, nullptr }; JSFunctionSpec JSI_GUISize::JSI_methods[] = Index: source/gui/Scripting/JSInterface_IGUIObject.cpp =================================================================== --- source/gui/Scripting/JSInterface_IGUIObject.cpp +++ source/gui/Scripting/JSInterface_IGUIObject.cpp @@ -43,9 +43,9 @@ } template <> -bool JSI_GUIProxy::funcGetter(IGUIObject* elem, const std::string& propName, JS::MutableHandleValue vp) const +bool JSI_GUIProxy::funcGetter(JS::HandleObject proxy, const std::string& propName, JS::MutableHandleValue vp) const { - const SData& data = *static_cast(elem->GetGUI().GetProxyData(this)); + const SData& data = *static_cast(js::GetProxyPrivate(proxy).toPrivate()); if (propName == "toString") return vp.setObjectOrNull(data.m_ToString), true; if (propName == "focus") Index: source/scriptinterface/ScriptContext.cpp =================================================================== --- source/scriptinterface/ScriptContext.cpp +++ source/scriptinterface/ScriptContext.cpp @@ -219,7 +219,7 @@ printf("Finishing incremental GC because gcBytes > m_ContextSize / 2. \n"); #endif PrepareCompartmentsForIncrementalGC(); - JS::FinishIncrementalGC(m_cx, JS::gcreason::REFRESH_FRAME); + JS::FinishIncrementalGC(m_cx, JS::gcreason::API); } else { @@ -249,9 +249,9 @@ #endif PrepareCompartmentsForIncrementalGC(); if (!JS::IsIncrementalGCInProgress(m_cx)) - JS::StartIncrementalGC(m_cx, GC_NORMAL, JS::gcreason::REFRESH_FRAME, GCSliceTimeBudget); + JS::StartIncrementalGC(m_cx, GC_NORMAL, JS::gcreason::API, GCSliceTimeBudget); else - JS::IncrementalGCSlice(m_cx, JS::gcreason::REFRESH_FRAME, GCSliceTimeBudget); + JS::IncrementalGCSlice(m_cx, JS::gcreason::API, GCSliceTimeBudget); } m_LastGCBytes = gcBytes; } @@ -262,7 +262,7 @@ { JS_SetGCParameter(m_cx, JSGC_MODE, JSGC_MODE_ZONE); JS::PrepareForFullGC(m_cx); - JS::GCForReason(m_cx, GC_SHRINK, JS::gcreason::REFRESH_FRAME); + JS::GCForReason(m_cx, GC_SHRINK, JS::gcreason::API); JS_SetGCParameter(m_cx, JSGC_MODE, JSGC_MODE_INCREMENTAL); } Index: source/scriptinterface/ScriptInterface.cpp =================================================================== --- source/scriptinterface/ScriptInterface.cpp +++ source/scriptinterface/ScriptInterface.cpp @@ -98,7 +98,7 @@ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; @@ -327,10 +327,7 @@ JS::CompartmentCreationOptions creationOpt; // Keep JIT code during non-shrinking GCs. This brings a quite big performance improvement. creationOpt.setPreserveJitCode(true); - JS::CompartmentBehaviors behaviors; - behaviors.setVersion(JSVERSION_LATEST); - - JS::CompartmentOptions opt(creationOpt, behaviors); + JS::CompartmentOptions opt(creationOpt, JS::CompartmentBehaviors{}); JSAutoRequest rq(m_cx); m_glob = JS_NewGlobalObject(m_cx, &global_class, nullptr, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt); @@ -494,7 +491,7 @@ ps, fs, // Properties, methods static_ps, static_fs)); // Constructor properties, methods - if (obj == NULL) + if (obj == nullptr) { ScriptException::CatchPending(rq); throw PSERROR_Scripting_DefineType_CreationFailed(); Index: source/simulation2/serialization/BinarySerializer.cpp =================================================================== --- source/simulation2/serialization/BinarySerializer.cpp +++ source/simulation2/serialization/BinarySerializer.cpp @@ -68,7 +68,7 @@ switch (JS_TypeOfValue(rq.cx, val)) { - case JSTYPE_VOID: + case JSTYPE_UNDEFINED: { m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_VOID); break;