Diff
Added: trunk/Source/_javascript_Core/API/glib/JSCWeakValue.cpp (0 => 230024)
--- trunk/Source/_javascript_Core/API/glib/JSCWeakValue.cpp (rev 0)
+++ trunk/Source/_javascript_Core/API/glib/JSCWeakValue.cpp 2018-03-28 06:21:57 UTC (rev 230024)
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2018 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "JSCWeakValue.h"
+
+#include "APICast.h"
+#include "JSCContextPrivate.h"
+#include "JSCInlines.h"
+#include "JSCValuePrivate.h"
+#include "Weak.h"
+#include "WeakHandleOwner.h"
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
+#include <wtf/glib/WTFGType.h>
+
+/**
+ * SECTION: JSCWeakValue
+ * @short_description: _javascript_ weak value
+ * @title: JSCWeakValue
+ * @see_also: JSCValue
+ *
+ * JSCWeakValue represents a weak reference to a value in a #JSCContext. It can be used
+ * to keep a reference to a _javascript_ value without protecting it from being garbage
+ * collected and without referencing the #JSCContext either.
+ */
+
+enum {
+ PROP_0,
+
+ PROP_VALUE,
+};
+
+enum {
+ CLEARED,
+
+ LAST_SIGNAL
+};
+
+// FIXME: move this to its own file to be shared by GLib and Objc APIs.
+class WeakValueRef {
+public:
+ ~WeakValueRef()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ switch (m_tag) {
+ case WeakTypeTag::NotSet:
+ return;
+ case WeakTypeTag::Primitive:
+ u.m_primitive = JSC::JSValue();
+ return;
+ case WeakTypeTag::Object:
+ u.m_object.clear();
+ return;
+ case WeakTypeTag::String:
+ u.m_string.clear();
+ return;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
+ bool isClear() const
+ {
+ switch (m_tag) {
+ case WeakTypeTag::NotSet:
+ return true;
+ case WeakTypeTag::Primitive:
+ return !u.m_primitive;
+ case WeakTypeTag::Object:
+ return !u.m_object;
+ case WeakTypeTag::String:
+ return !u.m_string;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
+ bool isSet() const { return m_tag != WeakTypeTag::NotSet; }
+ bool isPrimitive() const { return m_tag == WeakTypeTag::Primitive; }
+ bool isObject() const { return m_tag == WeakTypeTag::Object; }
+ bool isString() const { return m_tag == WeakTypeTag::String; }
+
+ void setPrimitive(JSC::JSValue primitive)
+ {
+ ASSERT(!isSet());
+ ASSERT(!u.m_primitive);
+ ASSERT(primitive.isPrimitive());
+ m_tag = WeakTypeTag::Primitive;
+ u.m_primitive = primitive;
+ }
+
+ void setObject(JSC::JSObject* object, JSC::WeakHandleOwner& owner, void* context)
+ {
+ ASSERT(!isSet());
+ ASSERT(!u.m_object);
+ m_tag = WeakTypeTag::Object;
+ JSC::Weak<JSC::JSObject> weak(object, &owner, context);
+ u.m_object.swap(weak);
+ }
+
+ void setString(JSC::JSString* string, JSC::WeakHandleOwner& owner, void* context)
+ {
+ ASSERT(!isSet());
+ ASSERT(!u.m_object);
+ m_tag = WeakTypeTag::String;
+ JSC::Weak<JSC::JSString> weak(string, &owner, context);
+ u.m_string.swap(weak);
+ }
+
+ JSC::JSObject* object() const
+ {
+ ASSERT(isObject());
+ return u.m_object.get();
+ }
+
+ JSC::JSValue primitive() const
+ {
+ ASSERT(isPrimitive());
+ return u.m_primitive;
+ }
+
+ JSC::JSString* string() const
+ {
+ ASSERT(isString());
+ return u.m_string.get();
+ }
+
+private:
+ enum class WeakTypeTag { NotSet, Primitive, Object, String };
+
+ WeakTypeTag m_tag { WeakTypeTag::NotSet };
+
+ union WeakValueUnion {
+ public:
+ WeakValueUnion()
+ : m_primitive(JSC::JSValue())
+ {
+ }
+
+ ~WeakValueUnion()
+ {
+ ASSERT(!m_primitive);
+ }
+
+ JSC::JSValue m_primitive;
+ JSC::Weak<JSC::JSObject> m_object;
+ JSC::Weak<JSC::JSString> m_string;
+ } u;
+};
+
+struct _JSCWeakValuePrivate {
+ JSC::Weak<JSC::JSGlobalObject> globalObject;
+ RefPtr<JSC::JSLock> lock;
+ WeakValueRef weakValueRef;
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+WEBKIT_DEFINE_TYPE(JSCWeakValue, jsc_weak_value, G_TYPE_OBJECT)
+
+static void jscWeakValueClear(JSCWeakValue* weakValue)
+{
+ JSCWeakValuePrivate* priv = weakValue->priv;
+ priv->globalObject.clear();
+ priv->weakValueRef.clear();
+}
+
+class JSCWeakValueHandleOwner : public JSC::WeakHandleOwner {
+public:
+ void finalize(JSC::Handle<JSC::Unknown>, void* context) override
+ {
+ auto* weakValue = JSC_WEAK_VALUE(context);
+ jscWeakValueClear(weakValue);
+ g_signal_emit(weakValue, signals[CLEARED], 0, nullptr);
+ }
+};
+
+static JSCWeakValueHandleOwner& weakValueHandleOwner()
+{
+ static NeverDestroyed<JSCWeakValueHandleOwner> jscWeakValueHandleOwner;
+ return jscWeakValueHandleOwner;
+}
+
+static void jscWeakValueInitialize(JSCWeakValue* weakValue, JSCValue* value)
+{
+ JSCWeakValuePrivate* priv = weakValue->priv;
+ auto* jsContext = jscContextGetJSContext(jsc_value_get_context(value));
+ JSC::ExecState* exec = toJS(jsContext);
+ JSC::JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ auto& owner = weakValueHandleOwner();
+ JSC::Weak<JSC::JSGlobalObject> weak(globalObject, &owner, weakValue);
+ priv->globalObject.swap(weak);
+ priv->lock = &exec->vm().apiLock();
+
+ JSC::JSValue jsValue = toJS(exec, jscValueGetJSValue(value));
+ if (jsValue.isObject())
+ priv->weakValueRef.setObject(JSC::jsCast<JSC::JSObject*>(jsValue.asCell()), owner, weakValue);
+ else if (jsValue.isString())
+ priv->weakValueRef.setString(JSC::jsCast<JSC::JSString*>(jsValue.asCell()), owner, weakValue);
+ else
+ priv->weakValueRef.setPrimitive(jsValue);
+}
+
+static void jscWeakValueSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* paramSpec)
+{
+ switch (propID) {
+ case PROP_VALUE:
+ jscWeakValueInitialize(JSC_WEAK_VALUE(object), JSC_VALUE(g_value_get_object(value)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
+ }
+}
+
+static void jscWeakValueDispose(GObject* object)
+{
+ JSCWeakValue* weakValue = JSC_WEAK_VALUE(object);
+ jscWeakValueClear(weakValue);
+
+ G_OBJECT_CLASS(jsc_weak_value_parent_class)->dispose(object);
+}
+
+static void jsc_weak_value_class_init(JSCWeakValueClass* klass)
+{
+ GObjectClass* objClass = G_OBJECT_CLASS(klass);
+ objClass->set_property = jscWeakValueSetProperty;
+ objClass->dispose = jscWeakValueDispose;
+
+ /**
+ * JSCWeakValue:value:
+ *
+ * The #JSCValue referencing the _javascript_ value.
+ */
+ g_object_class_install_property(objClass,
+ PROP_VALUE,
+ g_param_spec_object(
+ "value",
+ "JSCValue",
+ "JSC Value",
+ JSC_TYPE_VALUE,
+ static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+
+ /**
+ * JSCWeakValue::cleared:
+ * @weak_value: the #JSCWeakValue
+ *
+ * This signal is emitted when the _javascript_ value is destroyed.
+ */
+ signals[CLEARED] = g_signal_new(
+ "cleared",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ 0, nullptr, nullptr,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, 0,
+ G_TYPE_NONE);
+}
+
+/**
+ * jsc_weak_value_new:
+ * @value: a #JSCValue
+ *
+ * Create a new #JSCWeakValue for the _javascript_ value referenced by @value.
+ *
+ * Returns: (transfer full): a new #JSCWeakValue
+ */
+JSCWeakValue* jsc_weak_value_new(JSCValue* value)
+{
+ g_return_val_if_fail(JSC_IS_VALUE(value), nullptr);
+
+ return JSC_WEAK_VALUE(g_object_new(JSC_TYPE_WEAK_VALUE, "value", value, nullptr));
+}
+
+/**
+ * jsc_weak_value_get_value:
+ * @weak_value: a #JSCWeakValue
+ *
+ * Get a #JSCValue referencing the _javascript_ value of @weak_value.
+ *
+ * Returns: (transfer full): a new #JSCValue or %NULL if @weak_value was cleared.
+ */
+JSCValue* jsc_weak_value_get_value(JSCWeakValue* weakValue)
+{
+ g_return_val_if_fail(JSC_IS_WEAK_VALUE(weakValue), nullptr);
+
+ JSCWeakValuePrivate* priv = weakValue->priv;
+ WTF::Locker<JSC::JSLock> locker(priv->lock.get());
+ JSC::VM* vm = priv->lock->vm();
+ if (!vm)
+ return nullptr;
+
+ JSC::JSLockHolder apiLocker(vm);
+ if (!priv->globalObject || priv->weakValueRef.isClear())
+ return nullptr;
+
+ JSC::JSValue value;
+ if (priv->weakValueRef.isPrimitive())
+ value = priv->weakValueRef.primitive();
+ else if (priv->weakValueRef.isString())
+ value = priv->weakValueRef.string();
+ else
+ value = priv->weakValueRef.object();
+
+ JSC::ExecState* exec = priv->globalObject->globalExec();
+ GRefPtr<JSCContext> context = jscContextGetOrCreate(toGlobalRef(exec));
+ return jscContextGetOrCreateValue(context.get(), toRef(exec, value)).leakRef();
+}
Added: trunk/Source/_javascript_Core/API/glib/JSCWeakValue.h (0 => 230024)
--- trunk/Source/_javascript_Core/API/glib/JSCWeakValue.h (rev 0)
+++ trunk/Source/_javascript_Core/API/glib/JSCWeakValue.h 2018-03-28 06:21:57 UTC (rev 230024)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
+#error "Only <jsc/jsc.h> can be included directly."
+#endif
+
+#ifndef JSCWeakValue_h
+#define JSCWeakValue_h
+
+#include <glib-object.h>
+#include <jsc/JSCDefines.h>
+#include <jsc/JSCValue.h>
+
+G_BEGIN_DECLS
+
+#define JSC_TYPE_WEAK_VALUE (jsc_weak_value_get_type())
+#define JSC_WEAK_VALUE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JSC_TYPE_WEAK_VALUE, JSCWeakValue))
+#define JSC_IS_WEAK_VALUE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JSC_TYPE_WEAK_VALUE))
+#define JSC_WEAK_VALUE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JSC_TYPE_WEAK_VALUE, JSCWeakValueClass))
+#define JSC_IS_WEAK_VALUE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JSC_TYPE_WEAK_VALUE))
+#define JSC_WEAK_VALUE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JSC_TYPE_WEAK_VALUE, JSCWeakValueClass))
+
+typedef struct _JSCWeakValue JSCWeakValue;
+typedef struct _JSCWeakValueClass JSCWeakValueClass;
+typedef struct _JSCWeakValuePrivate JSCWeakValuePrivate;
+
+struct _JSCWeakValue {
+ GObject parent;
+
+ /*< private >*/
+ JSCWeakValuePrivate *priv;
+};
+
+struct _JSCWeakValueClass {
+ GObjectClass parent_class;
+
+ void (*_jsc_reserved0) (void);
+ void (*_jsc_reserved1) (void);
+ void (*_jsc_reserved2) (void);
+ void (*_jsc_reserved3) (void);
+};
+
+JSC_API GType
+jsc_weak_value_get_type (void);
+
+JSC_API JSCWeakValue *
+jsc_weak_value_new (JSCValue *value);
+
+JSC_API JSCValue *
+jsc_weak_value_get_value (JSCWeakValue *weak_value);
+
+G_END_DECLS
+
+#endif /* JSCWeakValue_h */
Modified: trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt (230023 => 230024)
--- trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt 2018-03-28 04:52:54 UTC (rev 230023)
+++ trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt 2018-03-28 06:21:57 UTC (rev 230024)
@@ -109,6 +109,27 @@
</SECTION>
<SECTION>
+<FILE>JSCWeakValue</FILE>
+<TITLE>JSCWeakValue</TITLE>
+JSCWeakValue
+jsc_weak_value_new
+jsc_weak_value_get_value
+
+<SUBSECTION Standard>
+JSCWeakValueClass
+JSC_TYPE_WEAK_VALUE
+JSC_WEAK_VALUE
+JSC_IS_WEAK_VALUE
+JSC_WEAK_VALUE_CLASS
+JSC_IS_WEAK_VALUE_CLASS
+JSC_WEAK_VALUE_GET_CLASS
+
+<SUBSECTION Private>
+JSCWeakValuePrivate
+jsc_weak_value_get_type
+</SECTION>
+
+<SECTION>
<FILE>JSCException</FILE>
<TITLE>JSCException</TITLE>
JSCException
Modified: trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-docs.sgml (230023 => 230024)
--- trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-docs.sgml 2018-03-28 04:52:54 UTC (rev 230023)
+++ trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-docs.sgml 2018-03-28 06:21:57 UTC (rev 230024)
@@ -14,6 +14,7 @@
<xi:include href=""
<xi:include href=""
<xi:include href=""
+ <xi:include href=""
<xi:include href=""
<xi:include href=""
<xi:include href=""
Modified: trunk/Source/_javascript_Core/API/glib/jsc.h (230023 => 230024)
--- trunk/Source/_javascript_Core/API/glib/jsc.h 2018-03-28 04:52:54 UTC (rev 230023)
+++ trunk/Source/_javascript_Core/API/glib/jsc.h 2018-03-28 06:21:57 UTC (rev 230024)
@@ -29,6 +29,7 @@
#include <jsc/JSCValue.h>
#include <jsc/JSCVersion.h>
#include <jsc/JSCVirtualMachine.h>
+#include <jsc/JSCWeakValue.h>
#include <jsc/JSCAutocleanups.h>
Modified: trunk/Source/_javascript_Core/ChangeLog (230023 => 230024)
--- trunk/Source/_javascript_Core/ChangeLog 2018-03-28 04:52:54 UTC (rev 230023)
+++ trunk/Source/_javascript_Core/ChangeLog 2018-03-28 06:21:57 UTC (rev 230024)
@@ -1,3 +1,41 @@
+2018-03-27 Carlos Garcia Campos <cgar...@igalia.com>
+
+ [GLIB] Add JSCWeakValue to _javascript_Core GLib API
+ https://bugs.webkit.org/show_bug.cgi?id=184041
+
+ Reviewed by Michael Catanzaro.
+
+ This allows to keep a reference to a _javascript_ value without protecting it, and without having a strong
+ reference of the context. When the value is cleared the JSCWeakValue::cleared signal is emitted and
+ jsc_weak_value_get_value() will always return nullptr.
+
+ * API/glib/JSCWeakValue.cpp: Added.
+ (WeakValueRef::~WeakValueRef):
+ (WeakValueRef::clear):
+ (WeakValueRef::isClear const):
+ (WeakValueRef::isSet const):
+ (WeakValueRef::isPrimitive const):
+ (WeakValueRef::isObject const):
+ (WeakValueRef::isString const):
+ (WeakValueRef::setPrimitive):
+ (WeakValueRef::setObject):
+ (WeakValueRef::setString):
+ (WeakValueRef::object const):
+ (WeakValueRef::primitive const):
+ (WeakValueRef::string const):
+ (weakValueHandleOwner):
+ (jscWeakValueInitialize):
+ (jscWeakValueSetProperty):
+ (jscWeakValueDispose):
+ (jsc_weak_value_class_init):
+ (jsc_weak_value_new):
+ (jsc_weak_value_get_value):
+ * API/glib/JSCWeakValue.h: Added.
+ * API/glib/docs/jsc-glib-4.0-sections.txt:
+ * API/glib/docs/jsc-glib-docs.sgml:
+ * API/glib/jsc.h:
+ * GLib.cmake:
+
2018-03-27 Yusuke Suzuki <utatane....@gmail.com>
[DFG] Remove unnecessary USE(JSVALUE32_64) / USE(JSVALUE64)
Modified: trunk/Source/_javascript_Core/GLib.cmake (230023 => 230024)
--- trunk/Source/_javascript_Core/GLib.cmake 2018-03-28 04:52:54 UTC (rev 230023)
+++ trunk/Source/_javascript_Core/GLib.cmake 2018-03-28 06:21:57 UTC (rev 230024)
@@ -10,6 +10,7 @@
API/glib/JSCValue.cpp
API/glib/JSCVersion.cpp
API/glib/JSCVirtualMachine.cpp
+ API/glib/JSCWeakValue.cpp
API/glib/JSCWrapperMap.cpp
)
@@ -28,6 +29,7 @@
${_javascript_CORE_DIR}/API/glib/JSCException.h
${_javascript_CORE_DIR}/API/glib/JSCValue.h
${_javascript_CORE_DIR}/API/glib/JSCVirtualMachine.h
+ ${_javascript_CORE_DIR}/API/glib/JSCWeakValue.h
${_javascript_CORE_DIR}/API/glib/jsc.h
)
Modified: trunk/Tools/ChangeLog (230023 => 230024)
--- trunk/Tools/ChangeLog 2018-03-28 04:52:54 UTC (rev 230023)
+++ trunk/Tools/ChangeLog 2018-03-28 06:21:57 UTC (rev 230024)
@@ -1,3 +1,17 @@
+2018-03-27 Carlos Garcia Campos <cgar...@igalia.com>
+
+ [GLIB] Add JSCWeakValue to _javascript_Core GLib API
+ https://bugs.webkit.org/show_bug.cgi?id=184041
+
+ Reviewed by Michael Catanzaro.
+
+ Add test case for JSCWeakValue.
+
+ * TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp:
+ (weakValueClearedCallback):
+ (testJSCWeakValue):
+ (main):
+
2018-03-27 Zalan Bujtas <za...@apple.com>
[LayoutReloaded] Start using window.collectTextRuns() to layout text lines in inline formatting context
Modified: trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp (230023 => 230024)
--- trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp 2018-03-28 04:52:54 UTC (rev 230023)
+++ trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp 2018-03-28 06:21:57 UTC (rev 230024)
@@ -1748,6 +1748,183 @@
}
}
+static void weakValueClearedCallback(JSCWeakValue* weakValue, bool* weakValueCleared)
+{
+ *weakValueCleared = true;
+ g_assert_null(jsc_weak_value_get_value(weakValue));
+}
+
+static void testJSCWeakValue()
+{
+ {
+ LeakChecker checker;
+ GRefPtr<JSCContext> context = adoptGRef(jsc_context_new());
+ checker.watch(context.get());
+ ExceptionHandler exceptionHandler(context.get());
+
+ GRefPtr<JSCValue> object = adoptGRef(jsc_value_new_object(context.get(), nullptr, nullptr));
+ checker.watch(object.get());
+
+ GRefPtr<JSCWeakValue> weak = adoptGRef(jsc_weak_value_new(object.get()));
+ checker.watch(weak.get());
+ bool weakValueCleared = false;
+ g_signal_connect(weak.get(), "cleared", G_CALLBACK(weakValueClearedCallback), &weakValueCleared);
+
+ jsc_context_set_value(context.get(), "foo", object.get());
+ jscContextGarbageCollect(context.get());
+ g_assert_false(weakValueCleared);
+
+ GRefPtr<JSCValue> foo = adoptGRef(jsc_context_get_value(context.get(), "foo"));
+ checker.watch(foo.get());
+ g_assert_true(object.get() == foo.get());
+
+ GRefPtr<JSCValue> weakFoo = adoptGRef(jsc_weak_value_get_value(weak.get()));
+ checker.watch(weakFoo.get());
+ g_assert_true(foo.get() == weakFoo.get());
+
+ GRefPtr<JSCValue> undefinedValue = adoptGRef(jsc_value_new_undefined(context.get()));
+ checker.watch(undefinedValue.get());
+ jsc_context_set_value(context.get(), "foo", undefinedValue.get());
+ weakFoo = nullptr;
+ foo = nullptr;
+ object = nullptr;
+
+ // The value is still reachable, but unprotected.
+ g_assert_false(weakValueCleared);
+ weakFoo = adoptGRef(jsc_weak_value_get_value(weak.get()));
+ checker.watch(weakFoo.get());
+ g_assert_true(jsc_value_is_object(weakFoo.get()));
+ weakFoo = nullptr;
+
+ jscContextGarbageCollect(context.get());
+ g_assert_true(weakValueCleared);
+ g_assert_null(jsc_weak_value_get_value(weak.get()));
+ }
+
+ {
+ LeakChecker checker;
+ GRefPtr<JSCWeakValue> weakObject;
+ bool weakValueCleared = false;
+ {
+ GRefPtr<JSCContext> context = adoptGRef(jsc_context_new());
+ checker.watch(context.get());
+ ExceptionHandler exceptionHandler(context.get());
+
+ GRefPtr<JSCValue> object = adoptGRef(jsc_context_evaluate(context.get(), "obj = {};"));
+ checker.watch(object.get());
+ g_assert_true(JSC_IS_VALUE(object.get()));
+ g_assert_true(jsc_value_is_object(object.get()));
+
+ weakObject = adoptGRef(jsc_weak_value_new(object.get()));
+ checker.watch(weakObject.get());
+ g_signal_connect(weakObject.get(), "cleared", G_CALLBACK(weakValueClearedCallback), &weakValueCleared);
+
+ object = adoptGRef(jsc_context_evaluate(context.get(), "obj = null"));
+ checker.watch(object.get());
+ g_assert_false(weakValueCleared);
+ }
+
+ g_assert_true(weakValueCleared);
+ g_assert_null(jsc_weak_value_get_value(weakObject.get()));
+ }
+
+ {
+ LeakChecker checker;
+ GRefPtr<JSCWeakValue> weakObj;
+ bool weakObjValueCleared = false;
+ GRefPtr<JSCWeakValue> weakStr;
+ bool weakStrValueCleared = false;
+ GRefPtr<JSCWeakValue> weakPrimitive;
+ bool weakPrimitiveValueCleared = false;
+ {
+ GRefPtr<JSCContext> context = adoptGRef(jsc_context_new());
+ checker.watch(context.get());
+ ExceptionHandler exceptionHandler(context.get());
+
+ GRefPtr<JSCValue> result = adoptGRef(jsc_context_evaluate(context.get(), "obj = { 'foo' : 'bar' }; str = 'Hello World'; primitive = 25;"));
+ checker.watch(result.get());
+
+ GRefPtr<JSCValue> value = adoptGRef(jsc_context_get_value(context.get(), "obj"));
+ checker.watch(value.get());
+ weakObj = adoptGRef(jsc_weak_value_new(value.get()));
+ checker.watch(weakObj.get());
+ g_signal_connect(weakObj.get(), "cleared", G_CALLBACK(weakValueClearedCallback), &weakObjValueCleared);
+
+ value = adoptGRef(jsc_context_get_value(context.get(), "str"));
+ checker.watch(value.get());
+ weakStr = adoptGRef(jsc_weak_value_new(value.get()));
+ checker.watch(weakStr.get());
+ g_signal_connect(weakStr.get(), "cleared", G_CALLBACK(weakValueClearedCallback), &weakStrValueCleared);
+
+ value = adoptGRef(jsc_context_get_value(context.get(), "primitive"));
+ checker.watch(value.get());
+ weakPrimitive = adoptGRef(jsc_weak_value_new(value.get()));
+ checker.watch(weakPrimitive.get());
+ g_signal_connect(weakPrimitive.get(), "cleared", G_CALLBACK(weakValueClearedCallback), &weakPrimitiveValueCleared);
+
+ value = nullptr;
+ jscContextGarbageCollect(context.get());
+ g_assert_false(weakObjValueCleared);
+ g_assert_false(weakStrValueCleared);
+ g_assert_false(weakPrimitiveValueCleared);
+
+ value = adoptGRef(jsc_weak_value_get_value(weakObj.get()));
+ checker.watch(value.get());
+ g_assert_true(jsc_value_is_object(value.get()));
+
+ value = adoptGRef(jsc_weak_value_get_value(weakStr.get()));
+ checker.watch(value.get());
+ g_assert_true(jsc_value_is_string(value.get()));
+
+ value = adoptGRef(jsc_weak_value_get_value(weakPrimitive.get()));
+ checker.watch(value.get());
+ g_assert_true(jsc_value_is_number(value.get()));
+ value = nullptr;
+
+ result = adoptGRef(jsc_context_evaluate(context.get(), "str = undefined"));
+ checker.watch(result.get());
+ jscContextGarbageCollect(context.get());
+
+ g_assert_true(weakStrValueCleared);
+ g_assert_false(weakObjValueCleared);
+ g_assert_false(weakPrimitiveValueCleared);
+ g_assert_null(jsc_weak_value_get_value(weakStr.get()));
+
+ result = adoptGRef(jsc_context_evaluate(context.get(), "f = undefined"));
+ checker.watch(result.get());
+ jscContextGarbageCollect(context.get());
+
+ // Non-string primitve values are not garbage collected, the weak value
+ // will be cleared when the global object is destroyed.
+ g_assert_false(weakPrimitiveValueCleared);
+ g_assert_false(weakObjValueCleared);
+ g_assert_true(weakStrValueCleared);
+
+ value = adoptGRef(jsc_weak_value_get_value(weakPrimitive.get()));
+ checker.watch(value.get());
+ g_assert_true(jsc_value_is_number(value.get()));
+ value = nullptr;
+
+ result = adoptGRef(jsc_context_evaluate(context.get(), "obj = undefined"));
+ checker.watch(result.get());
+ jscContextGarbageCollect(context.get());
+
+ g_assert_true(weakObjValueCleared);
+ g_assert_true(weakStrValueCleared);
+ g_assert_false(weakPrimitiveValueCleared);
+ g_assert_null(jsc_weak_value_get_value(weakObj.get()));
+ weakObjValueCleared = false;
+ weakStrValueCleared = false;
+ }
+
+ // Context is now destroyed, only the primitive value should be notified.
+ g_assert_true(weakPrimitiveValueCleared);
+ g_assert_false(weakObjValueCleared);
+ g_assert_false(weakStrValueCleared);
+ g_assert_null(jsc_weak_value_get_value(weakPrimitive.get()));
+ }
+}
+
static void testsJSCVirtualMachine()
{
{
@@ -1860,6 +2037,7 @@
g_test_add_func("/jsc/exceptions", testJSCExceptions);
g_test_add_func("/jsc/promises", testJSCPromises);
g_test_add_func("/jsc/garbage-collector", testJSCGarbageCollector);
+ g_test_add_func("/jsc/weak-value", testJSCWeakValue);
g_test_add_func("/jsc/vm", testsJSCVirtualMachine);
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
g_test_add_func("/jsc/autocleanups", testsJSCAutocleanups);