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,