diff --git a/bin/NativeTests/JsRTApiTest.cpp b/bin/NativeTests/JsRTApiTest.cpp
index 3a40a675b5a..c093f3afbdc 100644
--- a/bin/NativeTests/JsRTApiTest.cpp
+++ b/bin/NativeTests/JsRTApiTest.cpp
@@ -102,6 +102,37 @@ namespace JsRTApiTest
JsRTApiTest::RunWithAttributes(JsRTApiTest::ReferenceCountingTest);
}
+ void WeakReferenceTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
+ {
+ JsValueRef valueRef = JS_INVALID_REFERENCE;
+ REQUIRE(JsCreateString("test", strlen("test"), &valueRef) == JsNoError);
+
+ JsWeakRef weakRef = JS_INVALID_REFERENCE;
+ REQUIRE(JsCreateWeakReference(valueRef, &weakRef) == JsNoError);
+
+ // JsGetWeakReferenceValue should return the original value reference.
+ JsValueRef valueRefFromWeakRef = JS_INVALID_REFERENCE;
+ CHECK(JsGetWeakReferenceValue(weakRef, &valueRefFromWeakRef) == JsNoError);
+ CHECK(valueRefFromWeakRef != JS_INVALID_REFERENCE);
+ CHECK(valueRefFromWeakRef == valueRef);
+
+ // Clear the references on the stack, so that the value will be GC'd.
+ valueRef = JS_INVALID_REFERENCE;
+ valueRefFromWeakRef = JS_INVALID_REFERENCE;
+
+ CHECK(JsCollectGarbage(runtime) == JsNoError);
+
+ // JsGetWeakReferenceValue should return an invalid reference after the value was GC'd.
+ JsValueRef valueRefAfterGC = JS_INVALID_REFERENCE;
+ CHECK(JsGetWeakReferenceValue(weakRef, &valueRefAfterGC) == JsNoError);
+ CHECK(valueRefAfterGC == JS_INVALID_REFERENCE);
+ }
+
+ TEST_CASE("ApiTest_WeakReferenceTest", "[ApiTest]")
+ {
+ JsRTApiTest::RunWithAttributes(JsRTApiTest::WeakReferenceTest);
+ }
+
void ObjectsAndPropertiesTest1(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
{
JsValueRef object = JS_INVALID_REFERENCE;
diff --git a/lib/Jsrt/ChakraCore.h b/lib/Jsrt/ChakraCore.h
index d999f287ab3..695bff57e2d 100644
--- a/lib/Jsrt/ChakraCore.h
+++ b/lib/Jsrt/ChakraCore.h
@@ -508,9 +508,47 @@ CHAKRA_API
/// The code JsNoError if the operation succeeded, a failure code otherwise.
///
CHAKRA_API
-JsCreatePromise(
- _Out_ JsValueRef *promise,
- _Out_ JsValueRef *resolveFunction,
- _Out_ JsValueRef *rejectFunction);
+ JsCreatePromise(
+ _Out_ JsValueRef *promise,
+ _Out_ JsValueRef *resolveFunction,
+ _Out_ JsValueRef *rejectFunction);
+
+///
+/// A weak reference to a JavaScript value.
+///
+///
+/// A value with only weak references is available for garbage-collection. A strong reference
+/// to the value (JsValueRef) may be obtained from a weak reference if the value happens
+/// to still be available.
+///
+typedef JsRef JsWeakRef;
+
+///
+/// Creates a weak reference to a value.
+///
+/// The value to be referenced.
+/// Weak reference to the value.
+///
+/// The code JsNoError if the operation succeeded, a failure code otherwise.
+///
+CHAKRA_API
+ JsCreateWeakReference(
+ _In_ JsValueRef value,
+ _Out_ JsWeakRef* weakRef);
+
+///
+/// Gets a strong reference to the value referred to by a weak reference.
+///
+/// A weak reference.
+/// Reference to the value, or JS_INVALID_REFERENCE if the value is
+/// no longer available.
+///
+/// The code JsNoError if the operation succeeded, a failure code otherwise.
+///
+CHAKRA_API
+ JsGetWeakReferenceValue(
+ _In_ JsWeakRef weakRef,
+ _Out_ JsValueRef* value);
+
#endif // CHAKRACOREBUILD_
#endif // _CHAKRACORE_H_
diff --git a/lib/Jsrt/Jsrt.cpp b/lib/Jsrt/Jsrt.cpp
index 0e2a24da758..f9f202e637d 100644
--- a/lib/Jsrt/Jsrt.cpp
+++ b/lib/Jsrt/Jsrt.cpp
@@ -761,7 +761,7 @@ CHAKRA_API JsSetCurrentContext(_In_ JsContextRef newContext)
}
else
{
- if(oldScriptContext->IsTTDRecordModeEnabled())
+ if(oldScriptContext->IsTTDRecordModeEnabled())
{
//already know newScriptContext != oldScriptContext so don't check again
if(oldScriptContext->ShouldPerformRecordAction())
@@ -3904,7 +3904,7 @@ CHAKRA_API JsTTDPreExecuteSnapShotInterval(_In_ JsRuntimeHandle runtimeHandle, _
return inflateStatus;
}
- //If we are in the "active" segment set the continue breakpoint
+ //If we are in the "active" segment set the continue breakpoint
if((moveMode & JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment) == JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment)
{
GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
@@ -3944,7 +3944,7 @@ CHAKRA_API JsTTDPreExecuteSnapShotInterval(_In_ JsRuntimeHandle runtimeHandle, _
elog->PopMode(TTD::TTDMode::DebuggerLogBreakpoints);
elog->PopMode(TTD::TTDMode::DebuggerSuppressBreakpoints);
- //If we are in the "active" segment un-set the continue breakpoint
+ //If we are in the "active" segment un-set the continue breakpoint
if((moveMode & JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment) == JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment)
{
GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
@@ -4036,7 +4036,7 @@ CHAKRA_API JsTTDReplayExecution(_Inout_ JsTTDMoveMode* moveMode, _Out_ int64_t*
return JsNoError;
});
- if(bpstatus != JsNoError)
+ if(bpstatus != JsNoError)
{
return bpstatus;
}
@@ -4545,4 +4545,49 @@ CHAKRA_API JsCreatePromise(_Out_ JsValueRef *promise, _Out_ JsValueRef *resolve,
return JsNoError;
});
}
+
+CHAKRA_API JsCreateWeakReference(
+ _In_ JsValueRef value,
+ _Out_ JsWeakRef* weakRef)
+{
+ VALIDATE_JSREF(value);
+ PARAM_NOT_NULL(weakRef);
+ *weakRef = nullptr;
+
+ return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
+ ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
+ if (threadContext == nullptr)
+ {
+ return JsErrorNoCurrentContext;
+ }
+
+ Recycler* recycler = threadContext->GetRecycler();
+ if (recycler->IsInObjectBeforeCollectCallback())
+ {
+ return JsErrorInObjectBeforeCollectCallback;
+ }
+
+ recycler->FindOrCreateWeakReferenceHandle(
+ reinterpret_cast(value),
+ reinterpret_cast**>(weakRef));
+ return JsNoError;
+ });
+}
+
+CHAKRA_API JsGetWeakReferenceValue(
+ _In_ JsWeakRef weakRef,
+ _Out_ JsValueRef* value)
+{
+ VALIDATE_JSREF(weakRef);
+ PARAM_NOT_NULL(value);
+ *value = JS_INVALID_REFERENCE;
+
+ return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
+ Memory::RecyclerWeakReference* recyclerWeakReference =
+ reinterpret_cast*>(weakRef);
+ *value = reinterpret_cast(recyclerWeakReference->Get());
+ return JsNoError;
+ });
+}
+
#endif // CHAKRACOREBUILD_
diff --git a/lib/Jsrt/JsrtCommonExports.inc b/lib/Jsrt/JsrtCommonExports.inc
index a1828185c14..6de2f6c2747 100644
--- a/lib/Jsrt/JsrtCommonExports.inc
+++ b/lib/Jsrt/JsrtCommonExports.inc
@@ -116,4 +116,6 @@
JsCreatePropertyId
JsCopyPropertyId
JsCreatePromise
+ JsCreateWeakReference
+ JsGetWeakReferenceValue
#endif