-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
jsrt: update context api wrapping #3207
Conversation
lib/Jsrt/Jsrt.cpp
Outdated
@@ -1244,7 +1244,7 @@ CHAKRA_API JsGetGlobalObject(_Out_ JsValueRef *globalObject) | |||
|
|||
CHAKRA_API JsCreateObject(_Out_ JsValueRef *object) | |||
{ | |||
return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { | |||
return ContextAPIWrapper<true>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do these calls need to change from ContextAPINoScriptWrapper
to ContextAPIWrapper
? Is this fixing a correctness bug? It looks to me like creating an object doesn't rely on executing any script.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thinking (explained a bit on PR comment) Don't we allocate memory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does allocate memory yes, but ContextAPINoScriptWrapper
sets up handlers for OOM exceptions (and I believe we also failfast on OOM as well) so I'm not sure why we specifically need the script-handling version here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MSLaguana is right. JsCreateObject()
won't execute the user script and hence we want to keep it under ContextAPINoScriptWrapper
. Additionally ContextAPINoScriptWrapper
is lighter version of ContextApiWrapper
as it doesn't have BEGIN_ENTER_SCRIPT(scriptContext, true, true, true)
and END_ENTER_SCRIPT
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, we do set up handler for OOM
in both cases.
lib/Jsrt/Jsrt.cpp
Outdated
@@ -1327,7 +1327,7 @@ CHAKRA_API JsSetPrototype(_In_ JsValueRef object, _In_ JsValueRef prototypeObjec | |||
} | |||
|
|||
CHAKRA_API JsInstanceOf(_In_ JsValueRef object, _In_ JsValueRef constructor, _Out_ bool *result) { | |||
return ContextAPIWrapper<true>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { | |||
return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure that this is correct? It is possible to provide a custom hasInstance
method which may have arbitrary side effects, so surely we need to allow for the possibility of script executing here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes right, I was 50/50 on this, will update
@@ -1467,7 +1467,7 @@ CHAKRA_API JsSetProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId | |||
|
|||
CHAKRA_API JsHasProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ bool *hasProperty) | |||
{ | |||
return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { | |||
return ContextAPINoScriptWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { | |||
PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHasProperty, (Js::PropertyRecord *)propertyId, object); | |||
|
|||
VALIDATE_INCOMING_OBJECT(object, scriptContext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you are modifying this area, I just noticed the line *hasProperty = nullptr
which seems strange since hasProperty
is a bool*
so if anything we should be doing *hasProperty = false
, or just removing that line completely and letting the following line set the value.
lib/Jsrt/Jsrt.cpp
Outdated
@@ -1934,7 +1934,7 @@ CHAKRA_API JsCreateSymbol(_In_ JsValueRef description, _Out_ JsValueRef *result) | |||
|
|||
CHAKRA_API JsHasIndexedProperty(_In_ JsValueRef object, _In_ JsValueRef index, _Out_ bool *result) | |||
{ | |||
return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { | |||
return ContextAPINoScriptWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced that this is safe, given the ability to write a proxy with a custom accessor.
lib/Jsrt/Jsrt.cpp
Outdated
@@ -2186,7 +2186,7 @@ CHAKRA_API JsGetIndexedPropertiesExternalData( | |||
|
|||
CHAKRA_API JsEquals(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result) | |||
{ | |||
return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { | |||
return ContextAPINoScriptWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { | |||
PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTEquals, object1, object2, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can also call script if one of the objects has a custom valueOf
provided.
@@ -2200,7 +2200,7 @@ CHAKRA_API JsEquals(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool | |||
|
|||
CHAKRA_API JsStrictEquals(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result) | |||
{ | |||
return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { | |||
return ContextAPINoScriptWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that this one is probably fine.
lib/Jsrt/Jsrt.cpp
Outdated
@@ -1291,7 +1291,7 @@ CHAKRA_API JsConvertValueToObject(_In_ JsValueRef value, _Out_ JsValueRef *resul | |||
|
|||
CHAKRA_API JsGetPrototype(_In_ JsValueRef object, _Out_ JsValueRef *prototypeObject) | |||
{ | |||
return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ContextAPIWrapper [](start = 11, length = 17)
can call user script code if have getter?
lib/Jsrt/Jsrt.cpp
Outdated
@@ -1342,7 +1342,7 @@ CHAKRA_API JsInstanceOf(_In_ JsValueRef object, _In_ JsValueRef constructor, _Ou | |||
|
|||
CHAKRA_API JsGetExtensionAllowed(_In_ JsValueRef object, _Out_ bool *value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsGetExtensionAllowed [](start = 11, length = 21)
For most of the APIs below can call into user code if the object is proxy and you have handler for respective methods. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
When JSRT call ends up creating an object etc. (recycler allocation) we better wrap using ContextAPIWrapper. Oppositely, we could use a lighter version of it (ContextAPINoScriptWrapper) for simpler tasks
PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHasProperty, (Js::PropertyRecord *)propertyId, object); | ||
|
||
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious now, how does OP_HasProperty
interact with proxies? It looks like it walks the prototype chain, but I'm not sure whether it can potentially trigger proxies (e.g. custom get functions on the proxy) or if it only checks for normal properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I will double check this because I see OP_HasProperty calls into HasPropertyQuery and Proxy has an implementation for it.
In reply to: 126565457 [](ancestors = 126565457)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, don't spend much time on this. I've been working on another approach that might cover the rest as well. I will close this PR for now.
@@ -1503,7 +1503,7 @@ CHAKRA_API JsDeleteProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propert | |||
|
|||
CHAKRA_API JsDefineProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _In_ JsValueRef propertyDescriptor, _Out_ bool *result) | |||
{ | |||
return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { | |||
return ContextAPINoScriptWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DefineOwnPropertyDescriptor
can also be proxied.
When JSRT call ends up creating an object etc. (recycler allocation) we better wrap using ContextAPIWrapper. Oppositely, we could use a lighter version of it (ContextAPINoScriptWrapper) for simpler tasks.
Especially JsHasProperty is a very hot call for node-chakracore.