Skip to content

Commit

Permalink
[MERGE #3316 @kfarnung] Expose JsHasOwnProperty
Browse files Browse the repository at this point in the history
Merge pull request #3316 from kfarnung:hasownprop

Enable support for usage in node's n-api. Added a new unit test for the functionality.
  • Loading branch information
kfarnung committed Jul 11, 2017
2 parents 8f0631d + 4ba4c1a commit 6450f4f
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 3 deletions.
37 changes: 37 additions & 0 deletions bin/NativeTests/JsRTApiTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2061,4 +2061,41 @@ namespace JsRTApiTest
JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, ReentrantNoErrorParseModuleTest);
}

void ObjectHasOwnPropertyMethodTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
{
JsValueRef proto = JS_INVALID_REFERENCE;
JsValueRef object = JS_INVALID_REFERENCE;

REQUIRE(JsCreateObject(&proto) == JsNoError);
REQUIRE(JsCreateObject(&object) == JsNoError);
REQUIRE(JsSetPrototype(object, proto) == JsNoError);

JsPropertyIdRef propertyIdFoo = JS_INVALID_REFERENCE;
JsPropertyIdRef propertyIdBar = JS_INVALID_REFERENCE;
bool hasProperty = false;

REQUIRE(JsGetPropertyIdFromName(_u("foo"), &propertyIdFoo) == JsNoError);
REQUIRE(JsGetPropertyIdFromName(_u("bar"), &propertyIdBar) == JsNoError);

REQUIRE(JsSetProperty(object, propertyIdFoo, object, true) == JsNoError);
REQUIRE(JsSetProperty(proto, propertyIdBar, object, true) == JsNoError);

REQUIRE(JsHasProperty(object, propertyIdFoo, &hasProperty) == JsNoError);
CHECK(hasProperty);

REQUIRE(JsHasOwnProperty(object, propertyIdFoo, &hasProperty) == JsNoError);
CHECK(hasProperty);

REQUIRE(JsHasProperty(object, propertyIdBar, &hasProperty) == JsNoError);
CHECK(hasProperty);

REQUIRE(JsHasOwnProperty(object, propertyIdBar, &hasProperty) == JsNoError);
CHECK(!hasProperty);
}

TEST_CASE("ApiTest_ObjectHasOwnPropertyMethodTest", "[ApiTest]")
{
JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectHasOwnPropertyMethodTest);
}

}
18 changes: 18 additions & 0 deletions lib/Jsrt/ChakraCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -661,5 +661,23 @@ CHAKRA_API
JsReleaseSharedArrayBufferContentHandle(
_In_ JsSharedArrayBufferContentHandle sharedContents);

/// <summary>
/// Determines whether an object has a non-inherited property.
/// </summary>
/// <remarks>
/// Requires an active script context.
/// </remarks>
/// <param name="object">The object that may contain the property.</param>
/// <param name="propertyId">The ID of the property.</param>
/// <param name="hasOwnProperty">Whether the object has the non-inherited property.</param>
/// <returns>
/// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.
/// </returns>
CHAKRA_API
JsHasOwnProperty(
_In_ JsValueRef object,
_In_ JsPropertyIdRef propertyId,
_Out_ bool *hasOwnProperty);

#endif // CHAKRACOREBUILD_
#endif // _CHAKRACORE_H_
23 changes: 20 additions & 3 deletions lib/Jsrt/Jsrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1347,7 +1347,7 @@ CHAKRA_API JsGetExtensionAllowed(_In_ JsValueRef object, _Out_ bool *value)

VALIDATE_INCOMING_OBJECT(object, scriptContext);
PARAM_NOT_NULL(value);
*value = nullptr;
*value = false;

*value = Js::RecyclableObject::FromVar(object)->IsExtensible() != 0;

Expand Down Expand Up @@ -1473,7 +1473,7 @@ CHAKRA_API JsHasProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId
VALIDATE_INCOMING_OBJECT(object, scriptContext);
VALIDATE_INCOMING_PROPERTYID(propertyId);
PARAM_NOT_NULL(hasProperty);
*hasProperty = nullptr;
*hasProperty = false;

*hasProperty = Js::JavascriptOperators::OP_HasProperty(object, ((Js::PropertyRecord *)propertyId)->GetPropertyId(), scriptContext) != 0;

Expand Down Expand Up @@ -1510,7 +1510,7 @@ CHAKRA_API JsDefineProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propert
VALIDATE_INCOMING_PROPERTYID(propertyId);
VALIDATE_INCOMING_OBJECT(propertyDescriptor, scriptContext);
PARAM_NOT_NULL(result);
*result = nullptr;
*result = false;

Js::PropertyDescriptor propertyDescriptorValue;
if (!Js::JavascriptOperators::ToPropertyDescriptor(propertyDescriptor, &propertyDescriptorValue, scriptContext))
Expand Down Expand Up @@ -4731,4 +4731,21 @@ CHAKRA_API JsGetAndClearExceptionWithMetadata(_Out_ JsValueRef *metadata)
return JsNoError;
});
}

CHAKRA_API JsHasOwnProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ bool *hasOwnProperty)
{
return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHasOwnProperty, (Js::PropertyRecord *)propertyId, object);

VALIDATE_INCOMING_OBJECT(object, scriptContext);
VALIDATE_INCOMING_PROPERTYID(propertyId);
PARAM_NOT_NULL(hasOwnProperty);
*hasOwnProperty = false;

*hasOwnProperty = Js::JavascriptOperators::OP_HasOwnProperty(object, ((Js::PropertyRecord *)propertyId)->GetPropertyId(), scriptContext) != 0;

return JsNoError;
});
}

#endif // CHAKRACOREBUILD_
1 change: 1 addition & 0 deletions lib/Jsrt/JsrtCommonExports.inc
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,5 @@
JsCreateWeakReference
JsGetWeakReferenceValue
JsGetAndClearExceptionWithMetadata
JsHasOwnProperty
#endif
11 changes: 11 additions & 0 deletions lib/Runtime/Debug/TTActionEvents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,17 @@ namespace TTD
Js::JavascriptOperators::OP_HasProperty(var, GetPropertyIdItem(action), ctx);
}

void HasOwnPropertyAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext)
{
TTD_REPLAY_ACTIVE_CONTEXT(executeContext);
const JsRTSingleVarScalarArgumentAction* action = GetInlineEventDataAs<JsRTSingleVarScalarArgumentAction, EventKind::HasOwnPropertyActionTag>(evt);
Js::Var var = InflateVarInReplay(executeContext, GetVarItem_0(action));
TTD_REPLAY_VALIDATE_INCOMING_OBJECT(var, ctx);

//Result is not needed but trigger computation for any effects
Js::JavascriptOperators::OP_HasOwnProperty(var, GetPropertyIdItem(action), ctx);
}

void InstanceOfAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext)
{
TTD_REPLAY_ACTIVE_CONTEXT(executeContext);
Expand Down
1 change: 1 addition & 0 deletions lib/Runtime/Debug/TTActionEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ namespace TTD
void SetExceptionAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);

void HasPropertyAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);
void HasOwnPropertyAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);
void InstanceOfAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);
void EqualsAction_Execute(const EventLogEntry* evt, ThreadContextTTD* executeContext);

Expand Down
17 changes: 17 additions & 0 deletions lib/Runtime/Debug/TTEventLog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ namespace TTD
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(SetExceptionActionTag, ContextAPINoScriptWrapper, JsRTSingleVarScalarArgumentAction, SetExceptionAction_Execute);

TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(HasPropertyActionTag, ContextAPIWrapper, JsRTSingleVarScalarArgumentAction, HasPropertyAction_Execute);
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);

Expand Down Expand Up @@ -2145,6 +2146,22 @@ namespace TTD
actionPopper.InitializeWithEventAndEnter(evt);
}

void EventLog::RecordJsRTHasOwnProperty(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var)
{
//The host may not have validated this yet (and will exit early if the check fails) so we check it here as well before getting the property id below
if(pRecord == nullptr || Js::IsInternalPropertyId(pRecord->GetPropertyId()))
{
return;
}

NSLogEvents::JsRTSingleVarScalarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarScalarArgumentAction, NSLogEvents::EventKind::HasOwnPropertyActionTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetPropertyIdItem(gpAction, pRecord->GetPropertyId());

actionPopper.InitializeWithEventAndEnter(evt);
}

void EventLog::RecordJsRTInstanceOf(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var object, Js::Var constructor)
{
NSLogEvents::JsRTDoubleVarArgumentAction* gpAction = nullptr;
Expand Down
1 change: 1 addition & 0 deletions lib/Runtime/Debug/TTEventLog.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ namespace TTD

//Record query operations
void RecordJsRTHasProperty(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var);
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);

Expand Down
2 changes: 2 additions & 0 deletions lib/Runtime/Debug/TTEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ namespace TTD
ConstructCallActionTag,
CodeParseActionTag,
CallExistingFunctionActionTag,

HasOwnPropertyActionTag,

Count
};
Expand Down

0 comments on commit 6450f4f

Please sign in to comment.