diff --git a/bin/ChakraCore/ChakraCore.def b/bin/ChakraCore/ChakraCore.def
index 1602aa1de4c..9d711da224e 100644
--- a/bin/ChakraCore/ChakraCore.def
+++ b/bin/ChakraCore/ChakraCore.def
@@ -55,3 +55,6 @@ JsInitializeJITServer
JsCreateSharedArrayBufferWithSharedContent
JsGetSharedArrayBufferContent
JsReleaseSharedArrayBufferContentHandle
+
+JsLessThan
+JsLessThanOrEqual
diff --git a/bin/NativeTests/JsRTApiTest.cpp b/bin/NativeTests/JsRTApiTest.cpp
index e022f7908c4..65ce8286610 100644
--- a/bin/NativeTests/JsRTApiTest.cpp
+++ b/bin/NativeTests/JsRTApiTest.cpp
@@ -2196,4 +2196,57 @@ namespace JsRTApiTest
JsRTApiTest::RunWithAttributes(JsRTApiTest::JsCopyStringOneByteMethodTest);
}
+ void JsLessThanTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
+ {
+ // Create some values
+ JsValueRef number1 = JS_INVALID_REFERENCE; // number1 = 1
+ REQUIRE(JsDoubleToNumber(1, &number1) == JsNoError);
+ JsValueRef number2 = JS_INVALID_REFERENCE; // number2 = 2
+ REQUIRE(JsDoubleToNumber(2, &number2) == JsNoError);
+ JsValueRef stringa = JS_INVALID_REFERENCE; // stringa = "1"
+ REQUIRE(JsPointerToString(_u("1"), wcslen(_u("1")), &stringa) == JsNoError);
+ JsValueRef undefined = GetUndefined();
+ JsValueRef nullValue = JS_INVALID_REFERENCE;
+ REQUIRE(JsGetNullValue(&nullValue) == JsNoError);
+ JsValueRef trueValue = JS_INVALID_REFERENCE;
+ REQUIRE(JsGetTrueValue(&trueValue) == JsNoError);
+ JsValueRef falseValue = JS_INVALID_REFERENCE;
+ REQUIRE(JsGetFalseValue(&falseValue) == JsNoError);
+
+ bool result;
+ REQUIRE(JsLessThan(number1, number2, &result) == JsNoError);
+ CHECK(result == true);
+ REQUIRE(JsLessThan(number1, stringa, &result) == JsNoError);
+ CHECK(result == false);
+ REQUIRE(JsLessThan(number1, undefined, &result) == JsNoError);
+ CHECK(result == false);
+ REQUIRE(JsLessThan(falseValue, trueValue, &result) == JsNoError);
+ CHECK(result == true);
+ REQUIRE(JsLessThan(undefined, undefined, &result) == JsNoError);
+ CHECK(result == false);
+ REQUIRE(JsLessThan(nullValue, undefined, &result) == JsNoError);
+ CHECK(result == false);
+
+ REQUIRE(JsLessThanOrEqual(number1, number2, &result) == JsNoError);
+ CHECK(result == true);
+ REQUIRE(JsLessThanOrEqual(number1, number1, &result) == JsNoError);
+ CHECK(result == true);
+ REQUIRE(JsLessThanOrEqual(number1, stringa, &result) == JsNoError);
+ CHECK(result == true);
+ REQUIRE(JsLessThanOrEqual(trueValue, trueValue, &result) == JsNoError);
+ CHECK(result == true);
+ REQUIRE(JsLessThanOrEqual(falseValue, nullValue, &result) == JsNoError);
+ CHECK(result == true);
+ REQUIRE(JsLessThanOrEqual(falseValue, undefined, &result) == JsNoError);
+ CHECK(result == false);
+ REQUIRE(JsLessThanOrEqual(undefined, undefined, &result) == JsNoError);
+ CHECK(result == false);
+ REQUIRE(JsLessThanOrEqual(nullValue, undefined, &result) == JsNoError);
+ CHECK(result == false);
+ }
+
+ TEST_CASE("ApiTest_JsLessThanTest", "[ApiTest]")
+ {
+ JsRTApiTest::RunWithAttributes(JsRTApiTest::JsLessThanTest);
+ }
}
diff --git a/lib/Jsrt/ChakraCore.h b/lib/Jsrt/ChakraCore.h
index f0680558a83..c685550496a 100644
--- a/lib/Jsrt/ChakraCore.h
+++ b/lib/Jsrt/ChakraCore.h
@@ -745,5 +745,51 @@ CHAKRA_API
_Out_opt_ unsigned int *byteOffset,
_Out_opt_ unsigned int *byteLength);
+///
+/// Determine if one JavaScript value is less than another JavaScript value.
+///
+///
+///
+/// This function is equivalent to the < operator in Javascript.
+///
+///
+/// Requires an active script context.
+///
+///
+/// The first object to compare.
+/// The second object to compare.
+/// Whether object1 is less than object2.
+///
+/// The code JsNoError if the operation succeeded, a failure code otherwise.
+///
+CHAKRA_API
+JsLessThan(
+ _In_ JsValueRef object1,
+ _In_ JsValueRef object2,
+ _Out_ bool *result);
+
+///
+/// Determine if one JavaScript value is less than or equal to another JavaScript value.
+///
+///
+///
+/// This function is equivalent to the <= operator in Javascript.
+///
+///
+/// Requires an active script context.
+///
+///
+/// The first object to compare.
+/// The second object to compare.
+/// Whether object1 is less than or equal to object2.
+///
+/// The code JsNoError if the operation succeeded, a failure code otherwise.
+///
+CHAKRA_API
+JsLessThanOrEqual(
+ _In_ JsValueRef object1,
+ _In_ JsValueRef object2,
+ _Out_ bool *result);
+
#endif // _CHAKRACOREBUILD
#endif // _CHAKRACORE_H_
diff --git a/lib/Jsrt/Jsrt.cpp b/lib/Jsrt/Jsrt.cpp
index 549d980ff63..392205a15ed 100644
--- a/lib/Jsrt/Jsrt.cpp
+++ b/lib/Jsrt/Jsrt.cpp
@@ -2221,6 +2221,36 @@ CHAKRA_API JsGetIndexedPropertiesExternalData(
END_JSRT_NO_EXCEPTION
}
+CHAKRA_API JsLessThan(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
+{
+ return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
+ PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTLessThan, object1, object2, false);
+
+ VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
+ VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
+ PARAM_NOT_NULL(result);
+
+ *result = Js::JavascriptOperators::Less((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
+
+ return JsNoError;
+ });
+}
+
+CHAKRA_API JsLessThanOrEqual(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
+{
+ return ContextAPIWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
+ PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTLessThan, object1, object2, true);
+
+ VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
+ VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
+ PARAM_NOT_NULL(result);
+
+ *result = Js::JavascriptOperators::LessEqual((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
+
+ return JsNoError;
+ });
+}
+
CHAKRA_API JsEquals(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
{
return ContextAPIWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
diff --git a/lib/Runtime/Debug/TTActionEvents.cpp b/lib/Runtime/Debug/TTActionEvents.cpp
index 060c2aadd7c..97089378c86 100644
--- a/lib/Runtime/Debug/TTActionEvents.cpp
+++ b/lib/Runtime/Debug/TTActionEvents.cpp
@@ -536,6 +536,26 @@ namespace TTD
}
}
+ void LessThanAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext)
+ {
+ TTD_REPLAY_ACTIVE_CONTEXT(executeContext);
+ const JsRTDoubleVarSingleScalarArgumentAction* action = GetInlineEventDataAs(evt);
+ Js::Var object1 = InflateVarInReplay(executeContext, GetVarItem_0(action));
+ TTD_REPLAY_VALIDATE_INCOMING_REFERENCE(object1, ctx);
+ Js::Var object2 = InflateVarInReplay(executeContext, GetVarItem_1(action));
+ TTD_REPLAY_VALIDATE_INCOMING_REFERENCE(object2, ctx);
+
+ //Result is not needed but trigger computation for any effects
+ if (GetScalarItem_0(action))
+ {
+ Js::JavascriptOperators::LessEqual(object1, object2, ctx);
+ }
+ else
+ {
+ Js::JavascriptOperators::Less(object1, object2, ctx);
+ }
+ }
+
void GetPropertyIdFromSymbolAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext)
{
TTD_REPLAY_ACTIVE_CONTEXT(executeContext);
diff --git a/lib/Runtime/Debug/TTActionEvents.h b/lib/Runtime/Debug/TTActionEvents.h
index 14b00f931a4..51113d6d88d 100644
--- a/lib/Runtime/Debug/TTActionEvents.h
+++ b/lib/Runtime/Debug/TTActionEvents.h
@@ -492,6 +492,7 @@ namespace TTD
void HasOwnPropertyAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);
void InstanceOfAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);
void EqualsAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);
+ void LessThanAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);
void GetPropertyIdFromSymbolAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);
diff --git a/lib/Runtime/Debug/TTEventLog.cpp b/lib/Runtime/Debug/TTEventLog.cpp
index 0fe5925d57e..6ec19116320 100644
--- a/lib/Runtime/Debug/TTEventLog.cpp
+++ b/lib/Runtime/Debug/TTEventLog.cpp
@@ -551,6 +551,7 @@ namespace TTD
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(HasOwnPropertyActionTag, ContextAPIWrapper, JsRTSingleVarScalarArgumentAction, HasOwnPropertyAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(InstanceOfActionTag, ContextAPIWrapper, JsRTDoubleVarArgumentAction, InstanceOfAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(EqualsActionTag, ContextAPIWrapper, JsRTDoubleVarSingleScalarArgumentAction, EqualsAction_Execute);
+ TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(LessThanActionTag, ContextAPIWrapper, JsRTDoubleVarSingleScalarArgumentAction, LessThanAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetPropertyIdFromSymbolTag, ContextAPINoScriptWrapper, JsRTSingleVarArgumentAction, GetPropertyIdFromSymbolAction_Execute);
@@ -2200,6 +2201,17 @@ namespace TTD
actionPopper.InitializeWithEventAndEnter(evt);
}
+ void EventLog::RecordJsRTLessThan(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var1, Js::Var var2, bool allowsEqual)
+ {
+ NSLogEvents::JsRTDoubleVarSingleScalarArgumentAction* gpAction = nullptr;
+ NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent(&gpAction);
+ NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var1));
+ NSLogEvents::SetVarItem_1(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var2));
+ NSLogEvents::SetScalarItem_0(gpAction, allowsEqual);
+
+ actionPopper.InitializeWithEventAndEnter(evt);
+ }
+
void EventLog::RecordJsRTGetPropertyIdFromSymbol(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var sym)
{
NSLogEvents::JsRTSingleVarArgumentAction* gpAction = nullptr;
diff --git a/lib/Runtime/Debug/TTEventLog.h b/lib/Runtime/Debug/TTEventLog.h
index eed4d5fa3c8..d3d7b06b66d 100644
--- a/lib/Runtime/Debug/TTEventLog.h
+++ b/lib/Runtime/Debug/TTEventLog.h
@@ -560,6 +560,7 @@ namespace TTD
void RecordJsRTHasOwnProperty(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var);
void RecordJsRTInstanceOf(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var object, Js::Var constructor);
void RecordJsRTEquals(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var1, Js::Var var2, bool doStrict);
+ void RecordJsRTLessThan(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var1, Js::Var var2, bool allowsEqual);
//Record getters with native results
void RecordJsRTGetPropertyIdFromSymbol(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var sym);
diff --git a/lib/Runtime/Debug/TTEvents.h b/lib/Runtime/Debug/TTEvents.h
index bfdd041b749..1b84c70f180 100644
--- a/lib/Runtime/Debug/TTEvents.h
+++ b/lib/Runtime/Debug/TTEvents.h
@@ -142,6 +142,7 @@ namespace TTD
HasPropertyActionTag,
InstanceOfActionTag,
EqualsActionTag,
+ LessThanActionTag,
GetPropertyIdFromSymbolTag,